1 Question 1 — Single-Factor (Market) Model [25 points]

Model: \[R_i - R_f = \alpha + \beta(R_m - R_f) + \varepsilon\]

Given information:

Term Estimate Std. Error
Intercept \((\alpha)\) 0.0017 0.0020
Market premium \((\beta)\) 0.98 0.17
  • \(n = 96\) months, \(R^2 = 0.50\)
  • \(E[R_m - R_f] = 0.70\%\)
  • Critical \(|t| \approx 1.98\) (5% level, two-tailed)

1.1 Part (a) — t-statistic for \(\beta\); test \(H_0: \beta = 0\)

Formula: \[t_{\hat{\beta}} = \frac{\hat{\beta} - 0}{SE(\hat{\beta})}\]

beta_hat  <- 0.98
se_beta   <- 0.17
t_beta    <- beta_hat / se_beta
t_crit    <- 1.98

cat("t-statistic for beta:", round(t_beta, 4), "\n")
## t-statistic for beta: 5.7647
cat("Critical value:       ", t_crit, "\n")
## Critical value:        1.98
cat("Reject H0: beta = 0? ", abs(t_beta) > t_crit, "\n")
## Reject H0: beta = 0?  TRUE

\[t_{\hat{\beta}} = \frac{0.98}{0.17} = 5.7647\]

Decision: \(|t| = 5.7647 > 1.98\), so we reject \(H_0: \beta = 0\) at the 5% level.

Economic interpretation: \(\hat{\beta} = 0.98\) means that for every 1% increase in the market excess return, the fund’s excess return increases by approximately 0.98%. The fund moves almost one-for-one with the market — it has nearly the same systematic (market) risk as a passive index.


1.2 Part (b) — Test \(H_0: \beta = 1\)

Formula: \[t = \frac{\hat{\beta} - 1}{SE(\hat{\beta})}\]

t_beta1 <- (beta_hat - 1) / se_beta

cat("t-statistic for H0: beta = 1:", round(t_beta1, 4), "\n")
## t-statistic for H0: beta = 1: -0.1176
cat("Reject H0: beta = 1?         ", abs(t_beta1) > t_crit, "\n")
## Reject H0: beta = 1?          FALSE

\[t = \frac{0.98 - 1}{0.17} = \frac{-0.02}{0.17} = -0.1176\]

Decision: \(|t| = 0.1176 < 1.98\), so we fail to reject \(H_0: \beta = 1\) at the 5% level.

Interpretation: The data are statistically consistent with \(\beta = 1\). The fund’s systematic risk is not significantly different from the market’s. It is neither defensively nor aggressively tilted relative to a passive market portfolio.


1.3 Part (c) — t-statistic for \(\alpha\) (Jensen’s Alpha)

Formula: \[t_{\hat{\alpha}} = \frac{\hat{\alpha} - 0}{SE(\hat{\alpha})}\]

alpha_hat <- 0.0017
se_alpha  <- 0.0020
t_alpha   <- alpha_hat / se_alpha

cat("t-statistic for alpha:", round(t_alpha, 4), "\n")
## t-statistic for alpha: 0.85
cat("Reject H0: alpha = 0?", abs(t_alpha) > t_crit, "\n")
## Reject H0: alpha = 0? FALSE

\[t_{\hat{\alpha}} = \frac{0.0017}{0.0020} = 0.85\]

Decision: \(|t| = 0.85 < 1.98\), so we fail to reject \(H_0: \alpha = 0\) at the 5% level.

Conclusion on the marketing claim: The marketing team’s claim of “positive risk-adjusted performance” is not statistically supported. Although the point estimate of \(\hat{\alpha} = 0.0017\) (0.17% per month) is positive, it is not statistically distinguishable from zero given its standard error. Advertising a positive alpha on this basis would be misleading.


1.4 Part (d) — Interpretation of \(R^2\)

R2 <- 0.50
systematic_pct    <- R2 * 100
diversifiable_pct <- (1 - R2) * 100

cat("Systematic variation:    ", systematic_pct, "%\n")
## Systematic variation:     50 %
cat("Diversifiable variation: ", diversifiable_pct, "%\n")
## Diversifiable variation:  50 %

\[R^2 = 0.50\]

Interpretation: \(R^2 = 0.50\) means that 50% of the fund’s return variation is explained by market movements (systematic risk). The remaining 50% is idiosyncratic (diversifiable) risk — fund-specific noise not explained by the market factor. A well-diversified portfolio would have \(R^2\) close to 1.00; this fund retains substantial unsystematic risk.


1.5 Part (e) — CAPM-Implied Expected Monthly Excess Return

Formula: \[E[R_i - R_f] = \hat{\beta} \times E[R_m - R_f]\]

E_mkt_premium <- 0.0070   # 0.70% expressed as decimal
E_fund_excess <- beta_hat * E_mkt_premium

cat("CAPM-implied expected monthly excess return:", round(E_fund_excess * 100, 4), "%\n")
## CAPM-implied expected monthly excess return: 0.686 %

\[E[R_i - R_f] = 0.98 \times 0.70\% = 0.686\%\]

The CAPM predicts the fund should earn a monthly excess return of approximately 0.686%.


2 Question 2 — Fama–French Three-Factor Model [25 points]

Model: \[R_i - R_f = \alpha + b \cdot MKT + s \cdot SMB + h \cdot HML + \varepsilon\]

Given information (\(n = 144\) months):

Term Estimate Std. Error
Intercept \((\alpha)\) 0.0029 0.0018
MKT \((b)\) 0.97 0.08
SMB \((s)\) 0.75 0.11
HML \((h)\) -0.13 0.13
  • \(R^2 = 0.92\), Adjusted \(R^2 = 0.918\)
  • Critical \(|t| \approx 1.98\)

2.1 Part (f) — t-statistics for all four coefficients

Formula: \[t_k = \frac{\hat{\beta}_k}{SE(\hat{\beta}_k)}\]

coef_names <- c("Alpha", "MKT (b)", "SMB (s)", "HML (h)")
estimates  <- c(0.0029,  0.97,      0.75,      -0.13)
std_errors <- c(0.0018,  0.08,      0.11,       0.13)

t_stats    <- estimates / std_errors
significant <- abs(t_stats) > t_crit

results <- data.frame(
  Coefficient = coef_names,
  Estimate    = estimates,
  Std_Error   = std_errors,
  t_statistic = round(t_stats, 4),
  Significant_5pct = significant
)

print(results)
##   Coefficient Estimate Std_Error t_statistic Significant_5pct
## 1       Alpha   0.0029    0.0018      1.6111            FALSE
## 2     MKT (b)   0.9700    0.0800     12.1250             TRUE
## 3     SMB (s)   0.7500    0.1100      6.8182             TRUE
## 4     HML (h)  -0.1300    0.1300     -1.0000            FALSE

Summary:

Coefficient Estimate SE t-statistic Significant at 5%?
\(\alpha\) 0.0029 0.0018 1.6111 FALSE
MKT \((b)\) 0.97 0.08 12.125 TRUE
SMB \((s)\) 0.75 0.11 6.8182 TRUE
HML \((h)\) -0.13 0.13 -1 FALSE

Significant at 5%: \(\alpha\), MKT, and SMB are all significant. HML is not significant (\(|t| = 1.00 < 1.98\)).


2.2 Part (g) — Investment Style Classification

s_hat <- 0.75   # SMB loading
h_hat <- -0.13  # HML loading

cat("SMB loading (s):", s_hat,
    "-> Positive => fund tilts toward SMALL-cap stocks\n")
## SMB loading (s): 0.75 -> Positive => fund tilts toward SMALL-cap stocks
cat("HML loading (h):", h_hat,
    "-> Negative => fund tilts toward GROWTH stocks (low B/M)\n")
## HML loading (h): -0.13 -> Negative => fund tilts toward GROWTH stocks (low B/M)

Size tilt: \(\hat{s} = 0.75 > 0\) and statistically significant — the fund has a strong small-cap tilt. It behaves like a portfolio of smaller firms relative to large-cap stocks.

Value/Growth tilt: \(\hat{h} = -0.13 < 0\) but not statistically significant (\(|t| = 1.00\)). The negative sign suggests a mild growth tilt (low book-to-market), but this cannot be distinguished from zero at the 5% level.

Overall style: The fund is best characterized as a small-cap (growth-leaning) fund, though the growth tilt is not statistically confirmed.


2.3 Part (h) — Intercept Interpretation and Manager Skill

alpha_ff  <- 0.0029
se_alpha_ff <- 0.0018
t_alpha_ff  <- alpha_ff / se_alpha_ff

cat("FF3 alpha (monthly):", alpha_ff * 100, "%\n")
## FF3 alpha (monthly): 0.29 %
cat("t-statistic for alpha:", round(t_alpha_ff, 4), "\n")
## t-statistic for alpha: 1.6111
cat("Significant at 5%?  ", abs(t_alpha_ff) > t_crit, "\n")
## Significant at 5%?   FALSE

\[t_{\hat{\alpha}} = \frac{0.0029}{0.0018} = 1.6111\]

Decision: \(|t| = 1.6111 > 1.98\) — we reject \(H_0: \alpha = 0\) at the 5% level.

Interpretation: After controlling for all three Fama–French factors (market, size, and value), the fund earns a statistically significant monthly alpha of 0.29%. This is evidence that the manager adds value beyond mere factor exposures — there is genuine skill or access to return sources not captured by the three factors.


2.4 Part (i) — Rise in \(R^2\) from CAPM to FF3; Adjusted \(R^2\)

R2_capm <- 0.75
R2_ff3  <- 0.92
adj_R2  <- 0.918

cat("R^2 gain from CAPM to FF3:", R2_ff3 - R2_capm, "\n")
## R^2 gain from CAPM to FF3: 0.17
cat("Adjusted R^2 (FF3):       ", adj_R2, "\n")
## Adjusted R^2 (FF3):        0.918

Increase in \(R^2\): The \(R^2\) rises from 0.75 (single-factor CAPM) to 0.92 (FF3), a gain of 0.17 (17 percentage points). This means SMB and HML collectively explain an additional 17% of the fund’s return variation beyond what the market factor alone captures. The fund’s returns are substantially driven by its size tilt (small-cap exposure), which the CAPM omitted.

Why Adjusted \(R^2\)? Raw \(R^2\) always increases when predictors are added, even if they add no true explanatory power (it can never decrease). Adjusted \(R^2\) penalizes for the number of predictors: \[\bar{R}^2 = 1 - \frac{(1-R^2)(n-1)}{n-k-1}\] where \(k\) is the number of predictors. When comparing models with different numbers of factors (1 vs. 3), adjusted \(R^2\) is the appropriate metric because it only increases when a new variable improves fit by more than chance. Here, adjusted \(R^2 = 0.918\) confirms that all three factors are genuinely contributing.


3 Question 3 — Logistic Regression for Market Direction [25 points]

Model: \[\text{logit}\, P(\text{Up}) = \beta_0 + \beta_1 r_{t-1} + \beta_2 \Delta VIX_{t-1}\]

Coefficients: \(\beta_0 = -0.02\), \(\beta_1 = 5.4\), \(\beta_2 = -0.38\)

Today’s inputs: \(r_{t-1} = 0.010\), \(\Delta VIX = 1.5\)


3.1 Part (j) — Predicted Probability and Class

Logit (log-odds) computation: \[\text{logit} = \beta_0 + \beta_1 r_{t-1} + \beta_2 \Delta VIX\]

Sigmoid transformation to probability: \[P(\text{Up}) = \frac{e^{\text{logit}}}{1 + e^{\text{logit}}} = \frac{1}{1 + e^{-\text{logit}}}\]

beta0 <- -0.02
beta1 <-  5.4
beta2 <- -0.38

r_lag   <- 0.010
dVIX    <- 1.5

logit_val <- beta0 + beta1 * r_lag + beta2 * dVIX
prob_up   <- 1 / (1 + exp(-logit_val))
pred_class <- ifelse(prob_up >= 0.5, "Up", "Down")

cat("Logit value:           ", round(logit_val, 4), "\n")
## Logit value:            -0.536
cat("P(Up):                 ", round(prob_up, 4), "\n")
## P(Up):                  0.3691
cat("Predicted class (0.5): ", pred_class, "\n")
## Predicted class (0.5):  Down

\[\text{logit} = -0.02 + 5.4(0.010) + (-0.38)(1.5) = -0.02 + 0.054 - 0.57 = -0.536\]

\[P(\text{Up}) = \frac{1}{1 + e^{-(-0.536)}} = 0.3691\]

Predicted class: Since \(P(\text{Up}) = 0.3691 < 0.5\), the model predicts “Down” for tomorrow.


3.2 Part (k) — Economic Interpretation of \(\beta_1\) and \(\beta_2\)

\(\beta_1 = 5.4 > 0\) (Lagged Return): A positive lagged return increases the log-odds of an “Up” day. This captures momentum — when the market rose yesterday, it is more likely to rise again tomorrow. This is consistent with short-term return continuation documented in financial literature.

\(\beta_2 = -0.38 < 0\) (\(\Delta VIX\)): An increase in VIX (the “fear index”) decreases the log-odds of an “Up” day. This captures risk-off sentiment — when market uncertainty/fear rises, the probability of a positive return tomorrow falls. VIX spikes signal investor anxiety, which tends to accompany or precede market declines.


3.3 Part (l) — Confusion Matrix Metrics

Confusion matrix (200-day hold-out):

Predicted Up Predicted Down
Actual Up 67 (TP) 33 (FN)
Actual Down 44 (FP) 56 (TN)
TP <- 67
FP <- 44
FN <- 33
TN <- 56
N  <- 200

accuracy    <- (TP + TN) / N
sensitivity <- TP / (TP + FN)          # True Positive Rate for "Up"
specificity <- TN / (TN + FP)          # True Negative Rate
precision   <- TP / (TP + FP)          # Positive Predictive Value

cat("Accuracy:    ", round(accuracy,    4), sprintf("(%.2f%%)\n", accuracy*100))
## Accuracy:     0.615 (61.50%)
cat("Sensitivity: ", round(sensitivity, 4), sprintf("(%.2f%%)\n", sensitivity*100))
## Sensitivity:  0.67 (67.00%)
cat("Specificity: ", round(specificity, 4), sprintf("(%.2f%%)\n", specificity*100))
## Specificity:  0.56 (56.00%)
cat("Precision:   ", round(precision,   4), sprintf("(%.2f%%)\n", precision*100))
## Precision:    0.6036 (60.36%)

Formulas and results:

\[\text{Accuracy} = \frac{TP + TN}{N} = \frac{67 + 56}{200} = \frac{123}{200} = 0.615\]

\[\text{Sensitivity} = \frac{TP}{TP + FN} = \frac{67}{67 + 33} = \frac{67}{100} = 0.67\]

\[\text{Specificity} = \frac{TN}{TN + FP} = \frac{56}{56 + 44} = \frac{56}{100} = 0.56\]

\[\text{Precision} = \frac{TP}{TP + FP} = \frac{67}{67 + 44} = \frac{67}{111} = 0.6036\]


3.4 Part (m) — Naive Classifier and Adequacy of Accuracy

# Balanced classes: 100 Up, 100 Down
# Naive rule: predict the majority class (either — both are 50%)
# If we always predict "Up":
naive_accuracy <- 100 / 200  # 50%

model_accuracy <- accuracy

cat("Naive classifier accuracy:", naive_accuracy, "\n")
## Naive classifier accuracy: 0.5
cat("Logistic model accuracy:  ", round(model_accuracy, 4), "\n")
## Logistic model accuracy:   0.615
cat("Model beats naive?        ", model_accuracy > naive_accuracy, "\n")
## Model beats naive?         TRUE

Naive rule accuracy: Since the test set has exactly 100 “Up” and 100 “Down” days (balanced), always predicting either class gives \(\frac{100}{200} = 50.0\%\) accuracy.

Model accuracy: \(61.5\%\) — the model beats the naive classifier by 11.5 percentage points.

Why accuracy alone is inadequate for trading:

Accuracy treats every misclassification equally, but in a trading system the costs of errors are asymmetric: - Missing an “Up” day (False Negative) = foregone profit - Incorrectly entering a “Down” day (False Positive) = realized loss + transaction costs

A more economically relevant criterion would be profit and loss (P&L) or risk-adjusted return (e.g., Sharpe ratio) from the strategy implied by model signals. Alternatively, the F1-score (harmonic mean of precision and sensitivity) or ROC-AUC (area under the receiver operating characteristic curve) better balance the trade-off between catching “Up” days and avoiding false signals.


4 Question 4 — Resampling and Regularization in a Backtest [25 points]

Given: - Sample mean monthly return: \(\bar{r} = 0.70\% = 0.0070\) - Sample standard deviation: \(\hat{\sigma} = 5.50\% = 0.0550\) - \(n = 48\) months


4.1 Part (n) — Sharpe Ratio (Monthly and Annualized)

Formula (monthly Sharpe ratio, excess return assumed = mean return here): \[SR_{\text{monthly}} = \frac{\bar{r}}{\hat{\sigma}}\]

Annualization — scaling factor: There are 12 months per year, so: \[SR_{\text{annual}} = SR_{\text{monthly}} \times \sqrt{12}\]

r_bar  <- 0.0070
sigma  <- 0.0550
n_months <- 48

SR_monthly  <- r_bar / sigma
scale_factor <- sqrt(12)
SR_annual   <- SR_monthly * scale_factor

cat("Monthly Sharpe Ratio:    ", round(SR_monthly,  4), "\n")
## Monthly Sharpe Ratio:     0.1273
cat("Scaling factor:           sqrt(12) =", round(scale_factor, 4), "\n")
## Scaling factor:           sqrt(12) = 3.4641
cat("Annualized Sharpe Ratio: ", round(SR_annual,   4), "\n")
## Annualized Sharpe Ratio:  0.4409

\[SR_{\text{monthly}} = \frac{0.0070}{0.0550} = 0.1273\]

\[SR_{\text{annual}} = 0.1273 \times \sqrt{12} = 0.1273 \times 3.4641 = 0.4409\]

Scaling factor used: \(\sqrt{12}\), because the Sharpe ratio scales with \(\sqrt{T}\) when returns are i.i.d. (mean scales by \(T\), standard deviation by \(\sqrt{T}\), so their ratio scales by \(\sqrt{T}\); here \(T = 12\)).


4.2 Part (o) — Bootstrap Procedure for Sharpe Ratio SE; Variant for Time-Series

Step-by-step i.i.d. bootstrap procedure:

set.seed(42)

# Simulate 48 monthly returns for illustration
set.seed(42)
monthly_returns <- rnorm(48, mean = 0.0070, sd = 0.0550)

sharpe_boot <- function(returns) {
  mean(returns) / sd(returns)
}

B <- 10000
boot_sharpes <- replicate(B, {
  resample <- sample(monthly_returns, size = length(monthly_returns), replace = TRUE)
  sharpe_boot(resample)
})

SE_boot <- sd(boot_sharpes)
cat("Bootstrap SE of monthly Sharpe ratio:", round(SE_boot, 4), "\n")
## Bootstrap SE of monthly Sharpe ratio: 0.149
cat("95% Bootstrap CI: [",
    round(quantile(boot_sharpes, 0.025), 4), ",",
    round(quantile(boot_sharpes, 0.975), 4), "]\n")
## 95% Bootstrap CI: [ -0.2097 , 0.3765 ]

Procedure (described step by step):

  1. From the original \(n = 48\) monthly returns \(\{r_1, r_2, \ldots, r_{48}\}\), draw a bootstrap sample of size 48 with replacement.
  2. Compute the Sharpe ratio \(SR^* = \bar{r}^* / \hat{\sigma}^*\) on the bootstrap sample.
  3. Repeat steps 1–2 \(B = 10{,}000\) times to obtain the bootstrap distribution \(\{SR_1^*, SR_2^*, \ldots, SR_B^*\}\).
  4. The bootstrap standard error is \(SE_B = \text{sd}(\{SR_b^*\})\).
  5. A 95% CI can be formed by taking the 2.5th and 97.5th percentiles of the bootstrap distribution (percentile method).

Why i.i.d. bootstrap is inappropriate for monthly returns:

Monthly financial returns exhibit serial dependence — autocorrelation, volatility clustering (GARCH effects), and regime changes. The ordinary i.i.d. bootstrap destroys the temporal ordering of observations, breaking these dependencies and producing underestimated standard errors.

Fix — Block Bootstrap (e.g., Stationary Block Bootstrap or Moving Block Bootstrap): Instead of drawing individual observations, draw blocks of consecutive returns (e.g., blocks of length \(l = 4\)\(6\) months). This preserves the short-run autocorrelation structure within each block while still providing variation across bootstrap samples. The stationary block bootstrap (Politis & Romano, 1994) uses random block lengths to avoid edge effects and produces stationary bootstrap replicates.


4.3 Part (p) — LASSO \(\lambda\) Selection: Minimum-CV vs. One-SE Rule

lambda_min <- 0.030   # min CV error, retains 14 factors
lambda_1se <- 0.065   # one-SE rule, retains 7 factors

cat("lambda_min:", lambda_min, "-> retains", 14, "factors\n")
## lambda_min: 0.03 -> retains 14 factors
cat("lambda_1se:", lambda_1se, "-> retains",  7, "factors\n")
## lambda_1se: 0.065 -> retains 7 factors

Recommended choice: \(\lambda_{1SE} = 0.065\) (7 factors)

Reasoning:

The one-standard-error rule selects the most parsimonious model whose CV error is within one standard error of the minimum. In a financial backtest with 60 candidate factors, there are multiple strong reasons to prefer \(\lambda_{1SE}\):

  1. Overfitting risk: With 60 factors, the minimum-CV solution (14 factors) is highly susceptible to in-sample overfitting. The marginal factors added between 7 and 14 are likely capturing noise rather than genuine signal.

  2. Multiple testing / data snooping: In finance, factor selection from a large candidate set introduces data snooping bias. A sparser model with 7 factors is more likely to survive out-of-sample.

  3. Transaction costs and capacity: More factors mean more rebalancing trades and higher implementation costs. A simpler 7-factor model is more practically deployable.

  4. Interpretability and robustness: Fewer factors are easier to understand and more robust to structural breaks — a common concern in financial markets.

The small CV-error penalty from choosing \(\lambda_{1SE}\) is more than offset by the gains in generalization, parsimony, and practical deployability.


4.4 Part (q) — Walk-Forward (Time-Respecting) Evaluation; Why k-Fold Fails

# Visual illustration of walk-forward scheme
library(ggplot2)

n_total <- 60
train_start <- c(1, 6, 11, 16, 21)
train_end   <- c(36, 41, 46, 51, 56)
test_start  <- c(37, 42, 47, 52, 57)
test_end    <- c(41, 46, 51, 56, 60)

df_wf <- data.frame(
  Fold = rep(1:5, 2),
  Type = c(rep("Training", 5), rep("Test", 5)),
  Start = c(train_start, test_start),
  End   = c(train_end, test_end)
)

ggplot(df_wf, aes(xmin = Start, xmax = End,
                   ymin = Fold - 0.4, ymax = Fold + 0.4,
                   fill = Type)) +
  geom_rect(alpha = 0.8, color = "white") +
  scale_fill_manual(values = c("Training" = "steelblue", "Test" = "tomato")) +
  labs(title = "Walk-Forward Cross-Validation (Expanding Window)",
       x = "Month", y = "Fold", fill = "") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "bottom")

Walk-forward (time-respecting) scheme — step by step:

  1. Initial training window: Use months 1–36 to fit the LASSO with \(\lambda_{1SE}\), selecting factors and estimating weights.
  2. Out-of-sample test window: Apply the fitted model to predict returns for months 37–41 (5-month forward window). Record realized P&L.
  3. Expand the window: Add the test period to the training set (months 1–41) and re-estimate the model.
  4. Repeat: Slide forward, refitting on each expanded (or rolling) training set and evaluating on the next unseen block.
  5. Aggregate performance: Compute out-of-sample Sharpe ratio, hit rate, and drawdown across all test windows.

An expanding window (always using all available past data) is preferred over a fixed rolling window when the data-generating process is relatively stable; a rolling window is preferred if there is structural change.

Why standard random k-fold cross-validation is unsafe:

Standard k-fold CV randomly shuffles observations into \(k\) folds, allowing future data to appear in the training set when predicting past data. This is a form of look-ahead bias (data leakage):

  • A model trained on data from 2020 tested on data from 2015 appears to “predict” the past, which is trivially easy and produces inflated out-of-sample metrics.
  • Financial returns are not exchangeable — the joint distribution \((r_t, r_{t+1})\) has temporal structure (momentum, mean-reversion, macro regimes) that random shuffling destroys.
  • Information from the future (e.g., factor values or market conditions known only after period \(t\)) can “leak” into a training fold that is then used to predict period \(t\), yielding unrealistically high performance.

Walk-forward CV enforces the strict rule: train only on information available at the time of prediction. This mirrors real-world deployment and produces honest, actionable performance estimates.


End of Examination ```