1 Question 1 — Single-Factor (Market) Model

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
  • \(T = 96\) months, \(R^2 = 0.50\), \(E[R_m - R_f] = 0.70\%\), critical \(|t| \approx 1.98\).

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

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

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

# t-statistic
t_beta <- (beta_hat - 0) / se_beta
t_beta <- round(t_beta, 4)
cat("t-statistic for H0: beta = 0 :", t_beta, "\n")
t-statistic for H0: beta = 0 : 5.7647 
# Decision
if (abs(t_beta) > t_crit) {
  cat("Decision: |t| =", abs(t_beta), "> 1.98 => REJECT H0 at 5% level.\n")
} else {
  cat("Decision: |t| =", abs(t_beta), "<= 1.98 => FAIL TO REJECT H0.\n")
}
Decision: |t| = 5.7647 > 1.98 => REJECT H0 at 5% level.

Interpretation of \(\beta\): A \(\beta = 0.98\) implies that for every 1% increase in the market excess return, the fund’s excess return increases by approximately 0.98%.
Since \(\beta < 1\), the fund exhibits slightly less systematic (market) risk than the market portfolio.
Economically, this fund has near-market co-movement and is suitable for investors seeking broad market exposure with marginally lower volatility than a passive index.


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

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

t_beta1 <- (beta_hat - 1) / se_beta
t_beta1 <- round(t_beta1, 4)
cat("t-statistic for H0: beta = 1 :", t_beta1, "\n")
t-statistic for H0: beta = 1 : -0.1176 
if (abs(t_beta1) > t_crit) {
  cat("Decision: |t| =", abs(t_beta1), "> 1.98 => REJECT H0 at 5% level.\n")
} else {
  cat("Decision: |t| =", abs(t_beta1), "<= 1.98 => FAIL TO REJECT H0.\n")
}
Decision: |t| = 0.1176 <= 1.98 => FAIL TO REJECT H0.

Interpretation:
We fail to reject \(H_0: \beta = 1\).
This means there is insufficient statistical evidence to conclude that the fund’s systematic risk differs from the market’s.
While the point estimate of 0.98 is slightly below 1.00, the difference is well within sampling uncertainty.
The fund’s systematic risk is statistically indistinguishable from that of the market benchmark.


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

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

alpha_hat  <- 0.0017
se_alpha   <- 0.0020

t_alpha <- (alpha_hat - 0) / se_alpha
t_alpha <- round(t_alpha, 4)
cat("t-statistic for H0: alpha = 0 :", t_alpha, "\n")
t-statistic for H0: alpha = 0 : 0.85 
if (abs(t_alpha) > t_crit) {
  cat("Decision: REJECT H0 — alpha is statistically significant at 5%.\n")
} else {
  cat("Decision: FAIL TO REJECT H0 — alpha is NOT statistically significant at 5%.\n")
}
Decision: FAIL TO REJECT H0 — alpha is NOT statistically significant at 5%.

Marketing claim assessment:
The estimated Jensen’s alpha is positive (\(\hat\alpha = 0.0017\), i.e., +0.17% per month), which is encouraging on the surface.
However, \(|t_\alpha| = 0.85 < 1.98\), so we fail to reject \(H_0: \alpha = 0\).

The data do NOT statistically justify the claim of positive risk-adjusted performance.
The observed positive alpha is consistent with random sampling variation around zero.
Advertising “positive risk-adjusted performance” based on this estimate would be statistically misleading.


1.4 Part (d) — Interpret \(R^2\)

R2 <- 0.50
systematic_pct    <- round(R2 * 100, 4)
diversifiable_pct <- round((1 - R2) * 100, 4)

cat("Fraction explained by market (systematic) :", systematic_pct, "%\n")
Fraction explained by market (systematic) : 50 %
cat("Fraction unexplained (diversifiable/idiosyncratic):", diversifiable_pct, "%\n")
Fraction unexplained (diversifiable/idiosyncratic): 50 %

Interpretation:
\(R^2 = 0.50\) means that 50% of the monthly return variation in the fund is explained by the market factor (systematic risk).
The remaining 50% is idiosyncratic (diversifiable) risk — variation attributable to firm-specific or strategy-specific factors not correlated with the broad market.
A relatively low \(R^2\) of 0.50 in a single-factor model suggests either active stock selection, sector concentration, or exposure to non-market risk premia. This is consistent with a fund that is not a passive index tracker.


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

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

MRP     <- 0.0070   # E[Rm - Rf] = 0.70% expressed as decimal
E_excess <- beta_hat * MRP
E_excess_pct <- round(E_excess * 100, 4)

cat("CAPM-implied expected monthly excess return:\n")
CAPM-implied expected monthly excess return:
cat("  E[Ri - Rf] = beta * E[Rm - Rf]\n")
  E[Ri - Rf] = beta * E[Rm - Rf]
cat("             =", beta_hat, "*", MRP * 100, "%\n")
             = 0.98 * 0.7 %
cat("             =", E_excess_pct, "%\n")
             = 0.686 %

Conclusion — Question 1:
The fund’s market beta of 0.98 is statistically significant and economically near-market, but statistically indistinguishable from 1. Jensen’s alpha is positive yet insignificant, providing no credible evidence of skill. With only 50% of variation explained by the market, the fund carries substantial idiosyncratic risk. The CAPM-implied expected excess return of 0.686% per month reflects near-benchmark compensation for systematic risk.


2 Question 2 — Fama–French Three-Factor Model

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

Given information (\(T = 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 (for each coefficient \(\hat\theta\)): \[t_{\hat\theta} = \frac{\hat\theta}{SE(\hat\theta)}\]

coefs  <- c(alpha = 0.0029, b_MKT = 0.97, s_SMB = 0.75, h_HML = -0.13)
ses    <- c(alpha = 0.0018, b_MKT = 0.08, s_SMB = 0.11, h_HML =  0.13)
t_crit <- 1.98

t_stats    <- round(coefs / ses, 4)
significant <- ifelse(abs(t_stats) > t_crit, "Yes", "No")

results_q2f <- data.frame(
  Coefficient = names(coefs),
  Estimate    = coefs,
  Std_Error   = ses,
  t_statistic = t_stats,
  Significant_5pct = significant,
  row.names   = NULL
)

print(results_q2f)
  Coefficient Estimate Std_Error t_statistic Significant_5pct
1       alpha   0.0029    0.0018      1.6111               No
2       b_MKT   0.9700    0.0800     12.1250              Yes
3       s_SMB   0.7500    0.1100      6.8182              Yes
4       h_HML  -0.1300    0.1300     -1.0000               No

Summary: - MKT (\(t = 12.125\)): Highly significant — strong, positive market exposure. - SMB (\(t = 6.818\)): Highly significant — meaningful small-cap tilt. - HML (\(t = -1.000\)): Not significant at 5% — growth tilt is imprecise. - Alpha (\(t = 1.611\)): Not significant at 5% — borderline, discussed in (h).


2.2 Part (g) — Investment Style Classification

s_SMB_est <- 0.75
h_HML_est <- -0.13

cat("SMB loading:", s_SMB_est, "=> Positive and significant => SMALL-CAP tilt\n")
SMB loading: 0.75 => Positive and significant => SMALL-CAP tilt
cat("HML loading:", h_HML_est, "=> Negative (insignificant) => Growth (anti-value) tilt\n")
HML loading: -0.13 => Negative (insignificant) => Growth (anti-value) tilt

Style interpretation:

Factor Loading Sign Economic Meaning
SMB +0.75 Positive, large, significant Strong small-cap bias — fund overweights small companies relative to large-caps
HML −0.13 Negative, small, insignificant Mild growth orientation — slight underweighting of high book-to-market stocks

Classification: The fund is a small-cap growth fund.
- The large, significant SMB loading of +0.75 firmly anchors the fund in the small-capitalization segment of the equity universe.
- The negative HML loading suggests a preference for growth stocks (low book-to-market), though this tilt lacks statistical significance, so it should be treated with caution.


2.3 Part (h) — Intercept (Alpha) Interpretation

alpha_ff  <- 0.0029
se_alpha_ff <- 0.0018
t_alpha_ff  <- round(alpha_ff / se_alpha_ff, 4)

cat("Fama-French alpha  :", alpha_ff * 100, "% per month\n")
Fama-French alpha  : 0.29 % per month
cat("t-statistic        :", t_alpha_ff, "\n")
t-statistic        : 1.6111 
cat("Critical value     :", t_crit, "\n")
Critical value     : 1.98 
if (abs(t_alpha_ff) > t_crit) {
  cat("Decision: REJECT H0 — alpha is significant; manager ADDS VALUE.\n")
} else {
  cat("Decision: FAIL TO REJECT H0 — alpha is NOT significant at 5%.\n")
  cat("The fund does not add statistically significant value beyond factor exposures.\n")
}
Decision: FAIL TO REJECT H0 — alpha is NOT significant at 5%.
The fund does not add statistically significant value beyond factor exposures.

Interpretation:
After controlling for market, size, and value exposures, the fund generates \(\hat\alpha = +0.29\%\) per month.
However, with \(t = 1.611 < 1.98\), this alpha is not statistically significant at the 5% level.
This means we cannot conclude the manager adds value beyond systematic factor risk premia.
The result is consistent with the efficient markets hypothesis: apparent outperformance is better explained by the fund’s exposure to the well-documented SMB and MKT risk factors.


2.4 Part (i) — \(R^2\) rise from 0.75 to 0.92; role of Adjusted \(R^2\)

R2_CAPM  <- 0.75
R2_FF    <- 0.92
Adj_R2_FF <- 0.918

improvement <- round((R2_FF - R2_CAPM) * 100, 4)
cat("R2 improvement from adding SMB and HML :", improvement, "percentage points\n")
R2 improvement from adding SMB and HML : 17 percentage points
cat("Adjusted R2 (FF3):", Adj_R2_FF, "\n")
Adjusted R2 (FF3): 0.918 
cat("Unadjusted R2 (FF3):", R2_FF, "\n")
Unadjusted R2 (FF3): 0.92 
cat("Penalty for 2 extra parameters very small:", round(R2_FF - Adj_R2_FF, 4), "\n")
Penalty for 2 extra parameters very small: 0.002 

Explanation:

The jump in \(R^2\) from 0.75 (CAPM) to 0.92 (FF3) indicates that the SMB and HML factors collectively explain an additional 17 percentage points of monthly return variation.
This reveals that the single-factor CAPM systematically omits two important dimensions of equity risk: size and value. The fund’s small-cap growth tilt is a genuine source of return variation that the market factor alone cannot capture.

Why Adjusted \(R^2\) is appropriate for model comparison:
Raw \(R^2\) never decreases when adding predictors, even if they are noise.
Adjusted \(R^2\) penalizes for additional parameters:

\[\bar{R}^2 = 1 - \frac{(1-R^2)(T-1)}{T - k - 1}\]

where \(k\) is the number of predictors.
Here, Adjusted \(R^2 = 0.918\) vs \(R^2 = 0.920\), showing the two extra factors are genuinely informative (minimal shrinkage from 0.92 to 0.918). When comparing the 1-factor CAPM to the 3-factor FF model, adjusted \(R^2\) properly credits the FF model only for the real explanatory gain, not mechanical inflation from adding regressors.

Conclusion — Question 2:
The FF3 model dramatically improves fit (R² from 0.75 to 0.92), confirming that the fund’s returns are driven by exposure to small-cap and market factors. The manager’s alpha is positive but statistically insignificant — the performance is better attributed to systematic risk-factor harvesting than to genuine stock-selection skill.


3 Question 3 — Logistic Regression for Market Direction

Model: \[\text{logit}\,P(\text{Up}) = \beta_0 + \beta_1\,r_{t-1} + \beta_2\,\Delta\text{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\text{VIX} = 1.5\).


3.1 Part (j) — Predicted Probability and Class

Formula: \[\text{logit} = \beta_0 + \beta_1 r_{t-1} + \beta_2 \Delta\text{VIX}\] \[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
delta_vix <- 1.5

# Log-odds
logit_val <- beta0 + beta1 * r_lag + beta2 * delta_vix
logit_val <- round(logit_val, 4)
cat("Log-odds (logit):", logit_val, "\n")
Log-odds (logit): -0.536 
# Probability
prob_up <- 1 / (1 + exp(-logit_val))
prob_up <- round(prob_up, 4)
cat("P(Up) =", prob_up, "\n")
P(Up) = 0.3691 
# Predicted class at 0.5 threshold
pred_class <- ifelse(prob_up >= 0.5, "Up", "Down")
cat("Predicted class (threshold = 0.5):", pred_class, "\n")
Predicted class (threshold = 0.5): Down 

Step-by-step: \[\text{logit} = -0.02 + 5.4 \times 0.010 + (-0.38) \times 1.5 = -0.02 + 0.054 - 0.57 = -0.536\] \[P(\text{Up}) = \frac{1}{1 + e^{0.536}} = \frac{1}{1 + 1.7093} \approx 0.3693\]

Predicted class: Down (probability 0.3693 < 0.50 threshold).


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

cat("beta1 =", beta1, ": Lagged return\n")
beta1 = 5.4 : Lagged return
cat("beta2 =", beta2, ": Delta VIX\n")
beta2 = -0.38 : Delta VIX

\(\beta_1 = +5.4\) (positive — lagged return):
A positive \(\beta_1\) captures return momentum: when yesterday’s market return was positive, the model assigns a higher probability to today also being “Up.”
Economically, this reflects short-term price momentum, one of the most documented anomalies in equity markets (Jegadeesh & Titman, 1993). Positive serial correlation in short-horizon returns suggests that buying pressure persists intra-week.

\(\beta_2 = -0.38\) (negative — \(\Delta\)VIX):
A negative \(\beta_2\) captures the fear gauge relationship: when the VIX rises (increasing implied volatility / investor anxiety), the probability of an “Up” day falls.
Economically, rising VIX signals elevated uncertainty, risk aversion, and potential selling pressure, all of which reduce the probability of a positive market return. This is consistent with the well-established leverage effect and volatility feedback mechanisms in financial markets.


3.3 Part (l) — Confusion Matrix Metrics

Confusion matrix:

Actual Up Actual Down Total
Predicted Up 67 (TP) 44 (FP) 111
Predicted Down 33 (FN) 56 (TN) 89
Total 100 100 200

Formulas: \[\text{Accuracy} = \frac{TP + TN}{N}, \quad \text{Sensitivity} = \frac{TP}{TP + FN}\] \[\text{Specificity} = \frac{TN}{TN + FP}, \quad \text{Precision} = \frac{TP}{TP + FP}\]

TP <- 67; FP <- 44; FN <- 33; TN <- 56; N <- 200

accuracy    <- round((TP + TN) / N, 4)
sensitivity <- round(TP / (TP + FN), 4)   # True-positive rate for "Up"
specificity <- round(TN / (TN + FP), 4)
precision   <- round(TP / (TP + FP), 4)

metrics <- data.frame(
  Metric     = c("Accuracy", "Sensitivity (TPR for Up)", "Specificity", "Precision (for Up)"),
  Formula    = c("(TP+TN)/N", "TP/(TP+FN)", "TN/(TN+FP)", "TP/(TP+FP)"),
  Calculation = c(
    paste0("(", TP, "+", TN, ")/", N),
    paste0(TP, "/(", TP, "+", FN, ")"),
    paste0(TN, "/(", TN, "+", FP, ")"),
    paste0(TP, "/(", TP, "+", FP, ")")
  ),
  Value = c(accuracy, sensitivity, specificity, precision)
)
print(metrics)
                    Metric    Formula Calculation  Value
1                 Accuracy  (TP+TN)/N (67+56)/200 0.6150
2 Sensitivity (TPR for Up) TP/(TP+FN)  67/(67+33) 0.6700
3              Specificity TN/(TN+FP)  56/(56+44) 0.5600
4       Precision (for Up) TP/(TP+FP)  67/(67+44) 0.6036

Interpretation: - Accuracy (61.5%): The model correctly classifies 123 out of 200 days. - Sensitivity (67%): Of all actual “Up” days, the model correctly identifies 67%. Reasonable directional signal. - Specificity (56%): Of all actual “Down” days, the model correctly identifies 56%. Weaker at detecting downturns. - Precision (60.36%): Of days the model predicts “Up,” 60.36% are genuinely “Up.” Only marginally better than a coin flip.


3.4 Part (m) — Naive Classifier; Accuracy Critique

# Naive rule: always predict majority class
# Classes are balanced (100 Up, 100 Down) — majority = either, accuracy = 50%
total_up   <- 100
total_down <- 100
N_total    <- 200

naive_accuracy <- round(max(total_up, total_down) / N_total, 4)
cat("Naive classifier accuracy (always predict majority class):", naive_accuracy * 100, "%\n")
Naive classifier accuracy (always predict majority class): 50 %
cat("Model accuracy                                           :", accuracy * 100, "%\n")
Model accuracy                                           : 61.5 %
cat("Model beats naive classifier                            :", accuracy > naive_accuracy, "\n")
Model beats naive classifier                            : TRUE 

Does the model beat the naive rule?
Yes: 61.5% model accuracy vs. 50% naive accuracy. The model provides a +11.5 percentage point improvement.

Why accuracy alone is inadequate for a trading system:

In practice, the costs of prediction errors are asymmetric: - A false positive (“predict Up, market goes Down”) may cause a long position to lose money. - A false negative (“predict Down, market goes Up”) causes an opportunity cost.

These are not equal under realistic transaction costs, leverage, or volatility regimes.

A more economically relevant criterion:
Profit & Loss (P&L)–weighted accuracy or the Sharpe ratio of the resulting trading strategy is far more meaningful.
For example, a strategy that correctly predicts large moves (even at lower hit-rate) may generate superior risk-adjusted returns compared to one with high accuracy on noise-level fluctuations.
Alternatively, the F1 score (harmonic mean of precision and recall) is a better single metric when class costs differ, and the AUC-ROC measures discrimination across all thresholds.

Conclusion — Question 3:
The logistic model delivers directional accuracy of 61.5%, beating the naive benchmark by 11.5pp. It correctly captures momentum (\(\beta_1 > 0\)) and the fear-uncertainty effect (\(\beta_2 < 0\)). However, the model’s precision for “Up” predictions is only 60.4%, and accuracy as a sole metric ignores the asymmetric economic costs of different error types in a real trading system.


4 Question 4 — Resampling and Regularization in a Backtest

Given: Sample mean monthly return \(\bar\mu = 0.70\%\), sample standard deviation \(\hat\sigma = 5.50\%\), \(T = 48\) months.


4.1 Part (n) — Monthly and Annualised Sharpe Ratio

Formulas: \[SR_{\text{monthly}} = \frac{\bar\mu}{\hat\sigma}\] \[SR_{\text{annual}} = SR_{\text{monthly}} \times \sqrt{12}\]

The scaling factor \(\sqrt{12}\) follows from the variance-additivity of i.i.d. returns over 12 monthly periods: \(\sigma_{\text{annual}} = \sigma_{\text{monthly}} \times \sqrt{12}\), and \(\mu_{\text{annual}} = \mu_{\text{monthly}} \times 12\), so the ratio scales by \(\sqrt{12}\).

mu_monthly    <- 0.0070   # 0.70% as decimal
sigma_monthly <- 0.0550   # 5.50% as decimal
T_months      <- 48
scaling       <- sqrt(12)

SR_monthly <- round(mu_monthly / sigma_monthly, 4)
SR_annual  <- round(SR_monthly * scaling, 4)

cat("Monthly Sharpe Ratio   :", SR_monthly, "\n")
Monthly Sharpe Ratio   : 0.1273 
cat("Scaling factor         : sqrt(12) =", round(scaling, 4), "\n")
Scaling factor         : sqrt(12) = 3.4641 
cat("Annualised Sharpe Ratio:", SR_annual, "\n")
Annualised Sharpe Ratio: 0.441 

Step-by-step: \[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\]

The annualised Sharpe ratio of 0.4409 is modest — below the conventional threshold of 1.0 often required for institutional acceptance.


4.2 Part (o) — Bootstrap Standard Error for the Sharpe Ratio

Step-by-step Bootstrap Procedure:

set.seed(42)
T_obs <- 48
B     <- 10000  # Number of bootstrap replications

# Simulate a return series consistent with the given moments
set.seed(42)
r_sim <- rnorm(T_obs, mean = 0.0070, sd = 0.0550)

# Bootstrap function
boot_sharpe <- function(returns, B = 10000) {
  n   <- length(returns)
  srs <- numeric(B)
  for (i in seq_len(B)) {
    idx       <- sample(seq_len(n), n, replace = TRUE)
    r_boot    <- returns[idx]
    srs[i]    <- mean(r_boot) / sd(r_boot)
  }
  srs
}

boot_srs   <- boot_sharpe(r_sim, B = 10000)
boot_se    <- round(sd(boot_srs), 4)
boot_sr_mean <- round(mean(boot_srs), 4)

cat("Bootstrap SE of monthly Sharpe Ratio:", boot_se, "\n")
Bootstrap SE of monthly Sharpe Ratio: 0.149 
cat("Bootstrap mean Sharpe (should ≈ sample SR):", boot_sr_mean, "\n")
Bootstrap mean Sharpe (should ≈ sample SR): 0.0783 
cat("95% Bootstrap CI: [",
    round(quantile(boot_srs, 0.025), 4), ",",
    round(quantile(boot_srs, 0.975), 4), "]\n")
95% Bootstrap CI: [ -0.2097 , 0.3765 ]

Detailed procedure description:

  1. Collect the observed return series \(\{r_1, r_2, \ldots, r_{48}\}\).
  2. Draw \(B = 10{,}000\) bootstrap samples of size \(n = 48\), sampling with replacement from the original 48 observations.
  3. For each bootstrap sample \(b\), compute the sample Sharpe ratio: \(\widehat{SR}^{(b)} = \bar r^{(b)} / s^{(b)}\).
  4. Estimate the standard error as the standard deviation of the \(B\) bootstrap Sharpe ratios: \(\widehat{SE}_{boot} = \text{sd}(\widehat{SR}^{(1)}, \ldots, \widehat{SR}^{(B)})\).
  5. Construct confidence intervals using the percentile method or BCa-adjusted method.

Why the ordinary i.i.d. bootstrap is inappropriate:
Monthly financial returns exhibit time-series dependence — autocorrelation (especially in squared returns / volatility clustering) and possible heteroskedasticity violate the i.i.d. assumption. The i.i.d. bootstrap destroys the temporal ordering of observations, thereby breaking any serial correlation structure (e.g., volatility clustering from GARCH-type dynamics, momentum effects).

Appropriate variant — Block Bootstrap:
The stationary block bootstrap (Politis & Romano, 1994) or the moving block bootstrap resamples contiguous blocks of consecutive returns rather than individual observations. By preserving the within-block temporal structure, it respects serial dependence while still providing asymptotically valid inference.
The block length \(l\) is typically chosen as \(l \approx T^{1/3} \approx 48^{1/3} \approx 3.6\), i.e., \(l = 3\) or \(4\) months.


4.3 Part (p) — LASSO Model Selection: \(\lambda^*\) vs. One-Standard-Error Rule

lambda_min  <- 0.030
factors_min <- 14
lambda_1se  <- 0.065
factors_1se <- 7

cat("lambda_min  :", lambda_min, " => Retains", factors_min, "factors (minimum CV error)\n")
lambda_min  : 0.03  => Retains 14 factors (minimum CV error)
cat("lambda_1se  :", lambda_1se, " => Retains",  factors_1se, "factors (1-SE rule)\n")
lambda_1se  : 0.065  => Retains 7 factors (1-SE rule)

Recommended choice: \(\lambda = 0.065\) (one-standard-error rule)

Rationale:

  1. Bias–variance tradeoff in deployment: The minimum-CV-error \(\lambda\) selects the model that minimises average CV loss, but this estimate has its own sampling uncertainty. The 1-SE rule selects the simplest model (most regularized, fewest factors) whose CV error is within one standard error of the minimum. This guards against overfitting the cross-validation procedure itself.

  2. Parsimony and interpretability: A 7-factor model is substantially easier to implement, monitor, and explain to stakeholders than a 14-factor model. Fewer factors also reduce transaction costs, data requirements, and the risk of data-snooping bias.

  3. Out-of-sample generalisation: In financial applications with limited data, simpler models typically generalise better. With 60 candidate factors, the 14-factor solution is susceptible to in-sample overfitting, whereas the 7-factor solution imposes a stronger prior of sparsity, which is economically sensible (most factors are likely spurious).

  4. Ockham’s Razor in finance: Unless the additional 7 factors deliver a statistically significant improvement in out-of-sample performance, the 1-SE model is preferred as the deployable solution.


4.4 Part (q) — Walk-Forward (Time-Respecting) Cross-Validation

# Illustrative walk-forward scheme diagram
cat("Walk-Forward Evaluation Scheme\n")
Walk-Forward Evaluation Scheme
cat("================================\n")
================================
cat("Period 1: Train [1,36]      | Test [37,48]\n")
Period 1: Train [1,36]      | Test [37,48]
cat("Period 2: Train [1,48]      | Test [49,60]\n")
Period 2: Train [1,48]      | Test [49,60]
cat("Period 3: Train [1,60]      | Test [61,72]\n")
Period 3: Train [1,60]      | Test [61,72]
cat("         ...expanding window...\n")
         ...expanding window...
cat("Each test window immediately follows its training window.\n")
Each test window immediately follows its training window.
cat("No future data ever enters the training set.\n")
No future data ever enters the training set.

Walk-Forward (Expanding-Window) Scheme:

  1. Initial training window: Use the first \(W_0\) months (e.g., 36 months) to estimate the LASSO model (tune \(\lambda\), select factors, fit coefficients).
  2. Out-of-sample test: Apply the fitted model to predict/trade the next \(h\) months (e.g., 12 months), recording returns.
  3. Expand the window: Add the test period data to the training set, refit the model from scratch (including re-tuning \(\lambda\)), and predict the subsequent \(h\) months.
  4. Repeat until the end of the data. Aggregate out-of-sample returns across all test windows to compute the strategy’s true OOS Sharpe ratio and other performance metrics.

Why standard random \(k\)-fold cross-validation is unsafe for financial time series:

Problem Explanation
Look-ahead bias Random shuffling mixes future observations into training folds, causing the model to “see” information not available at the time of trade. This inflates apparent performance.
Temporal leakage Autocorrelated features (momentum, VIX, macro variables) mean a test fold adjacent in time to its training fold will share information even after shuffling.
Artificial IID assumption \(k\)-fold CV assumes exchangeable observations. Financial returns are serially dependent (volatility clustering, regime changes), so random fold assignment produces biased error estimates.
Non-stationarity Markets evolve; a model trained on 2010–2015 data and tested on 2012 data (random fold) will show spuriously good performance because the regimes overlap. Walk-forward forces the model to predict future states, not interpolate within a known period.

Conclusion — Question 4:
The annualised Sharpe ratio of 0.44 is modest. Bootstrap SE is the appropriate uncertainty measure, but requires a block bootstrap to respect return autocorrelation. For LASSO model selection, the 1-SE rule’s 7-factor model is preferred for its superior parsimony and expected OOS robustness. Walk-forward evaluation is the only statistically valid backtesting approach for financial strategies, eliminating the look-ahead contamination that corrupts standard \(k\)-fold results.


5 Summary of Key Results

summary_df <- data.frame(
  Question = c(
    "Q1(a)", "Q1(b)", "Q1(c)", "Q1(d)", "Q1(e)",
    "Q2(f)", "Q2(g)", "Q2(h)",
    "Q3(j)", "Q3(l) Accuracy", "Q3(l) Sensitivity", "Q3(l) Specificity", "Q3(l) Precision",
    "Q4(n) SR monthly", "Q4(n) SR annual"
  ),
  Result = c(
    "t(β=0) = 5.7647, REJECT H0",
    "t(β=1) = -0.1176, FAIL TO REJECT H0",
    "t(α=0) = 0.85, NOT significant",
    "50% systematic, 50% idiosyncratic",
    "CAPM E[excess return] = 0.686% / month",
    "MKT, SMB significant; HML, α not significant",
    "Small-cap Growth fund",
    "α = +0.29%/mo, t = 1.611, NOT significant",
    "P(Up) = 0.3693, Predicted class = Down",
    "61.5%",
    "67.0%",
    "56.0%",
    "60.36%",
    "0.1273",
    "0.4409"
  ),
  stringsAsFactors = FALSE
)
knitr::kable(summary_df, caption = "Summary of Key Results Across All Questions")
Summary of Key Results Across All Questions
Question Result
Q1(a) t(β=0) = 5.7647, REJECT H0
Q1(b) t(β=1) = -0.1176, FAIL TO REJECT H0
Q1(c) t(α=0) = 0.85, NOT significant
Q1(d) 50% systematic, 50% idiosyncratic
Q1(e) CAPM E[excess return] = 0.686% / month
Q2(f) MKT, SMB significant; HML, α not significant
Q2(g) Small-cap Growth fund
Q2(h) α = +0.29%/mo, t = 1.611, NOT significant
Q3(j) P(Up) = 0.3693, Predicted class = Down
Q3(l) Accuracy 61.5%
Q3(l) Sensitivity 67.0%
Q3(l) Specificity 56.0%
Q3(l) Precision 60.36%
Q4(n) SR monthly 0.1273
Q4(n) SR annual 0.4409

End of examination solutions.
All calculations verified with R. Rounded to 4 decimal places throughout.