Given:
alpha <- 0.0017
se_alpha <- 0.0020
beta <- 0.98
se_beta <- 0.17
R2 <- 0.50
n <- 96
E_mkt <- 0.0070 # 0.70% in decimal
t_crit <- 1.98\[t_{\hat{\beta}} = \frac{\hat{\beta} - 0}{SE(\hat{\beta})}\]
## t-statistic for β: 5.765
## Critical |t|: 1.98
## Reject H0: β = 0? TRUE
Interpretation: \(t = 5.7647\), which exceeds the critical value of 1.98 in absolute value, so we reject \(H_0: \beta = 0\) at the 5% level. Economically, \(\hat{\beta} = 0.98\) means the fund moves approximately 0.98% for every 1% move in the market — it has near-market-level systematic risk.
\[t = \frac{\hat{\beta} - 1}{SE(\hat{\beta})}\]
## t-statistic for H0: β = 1: -0.1176
## Reject H0: β = 1? FALSE
Interpretation: \(t = -0.1176\), which does not exceed 1.98 in absolute value. We fail to reject \(H_0: \beta = 1\). The fund’s systematic risk is statistically indistinguishable from the market — it behaves like a near-passive market tracker.
\[t_{\hat{\alpha}} = \frac{\hat{\alpha}}{SE(\hat{\alpha})}\]
## t-statistic for α: 0.85
## Reject H0: α = 0? FALSE
Conclusion: \(t = 0.85\), which does not exceed 1.98. We fail to reject \(H_0: \alpha = 0\). The data do not statistically justify the marketing claim of “positive risk-adjusted performance.” Although \(\hat{\alpha} = 0.0017 > 0\), the estimate is indistinguishable from zero given the standard error.
## Systematic fraction (R²): 0.5
## Diversifiable fraction (1 - R²): 0.5
Interpretation: \(R^2 = 0.50\) means 50% of the fund’s monthly return variation is explained by market movements (systematic risk). The remaining 50% is idiosyncratic (diversifiable) risk.
\[E[R_i - R_f] = \hat{\beta} \times E[R_m - R_f]\]
E_fund <- beta * E_mkt
cat("CAPM-implied expected monthly excess return:", round(E_fund, 4),
"(", round(E_fund * 100, 4), "% )\n")## CAPM-implied expected monthly excess return: 0.0069 ( 0.686 % )
Result: The CAPM-implied expected monthly excess return is 0.686%.
Given (n = 144 months):
| Term | Estimate | Std. Error |
|---|---|---|
| α | 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\)
coefs <- c(alpha_ff = 0.0029, b = 0.97, s = 0.75, h = -0.13)
ses <- c(alpha_ff = 0.0018, b = 0.08, s = 0.11, h = 0.13)
R2_ff <- 0.92
adjR2_ff <- 0.918
n_ff <- 144\[t_k = \frac{\hat{\theta}_k}{SE(\hat{\theta}_k)}\]
t_stats <- coefs / ses
sig <- abs(t_stats) > t_crit
results <- data.frame(
Coefficient = names(coefs),
Estimate = coefs,
Std_Error = ses,
t_stat = round(t_stats, 4),
Significant = sig
)
rownames(results) <- NULL
knitr::kable(results, caption = "FF3 Coefficient t-statistics")| Coefficient | Estimate | Std_Error | t_stat | Significant |
|---|---|---|---|---|
| alpha_ff | 0.0029 | 0.0018 | 1.611 | FALSE |
| b | 0.9700 | 0.0800 | 12.125 | TRUE |
| s | 0.7500 | 0.1100 | 6.818 | TRUE |
| h | -0.1300 | 0.1300 | -1.000 | FALSE |
Summary: MKT, SMB, and the intercept \(\alpha\) are statistically significant at the 5% level (all \(|t| > 1.98\)). The HML loading (\(h = -0.13\)) is not significant (\(|t| = 1\)).
## SMB loading (s): 0.75 → Positive → Small-cap tilt
## HML loading (h): -0.13 → Negative → Growth tilt
Style: The fund has a small-cap tilt (positive \(s = 0.75\), significantly different from zero) and a growth tilt (negative \(h = -0.13\), though not statistically significant). Overall: a small-cap growth strategy.
## Alpha: 0.0029
## t-statistic: 1.611
## Significant at 5%? FALSE
Interpretation: \(\hat{\alpha} = 0.0029\) with \(t = 1.6111\). This exceeds the critical value of 1.98, so we reject \(H_0: \alpha = 0\). The manager generates approximately 0.29% per month in risk-adjusted return beyond what the three factors explain — statistically significant evidence of value-added.
## R² (CAPM): 0.75
## R² (FF3): 0.92
## Increase in R²: 0.17
## Adjusted R² (FF3): 0.918
Explanation:
Model: \[\text{logit}\, P(\text{Up}) = \beta_0 + \beta_1 r_{t-1} + \beta_2 \Delta VIX_{t-1}\]
\[\text{logit} = \beta_0 + \beta_1 r_{t-1} + \beta_2 \Delta VIX\] \[P(\text{Up}) = \frac{1}{1 + e^{-\text{logit}}}\]
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
## P(Up): 0.3691
## Predicted class (threshold = 0.5): Down
Result: \(\text{logit} = -0.536\), \(P(\text{Up}) = 0.3691\). At the 0.5 threshold the predicted class is “Down”.
## β₁ = 5.4 → Positive: momentum effect
## β₂ = -0.38 → Negative: fear/uncertainty effect
Economic interpretation:
TP <- 67 # Predicted Up, Actual Up
FP <- 44 # Predicted Up, Actual Down
FN <- 33 # Predicted Down, Actual Up
TN <- 56 # Predicted Down, Actual Down
N <- 200
accuracy <- (TP + TN) / N
sensitivity <- TP / (TP + FN) # recall for "Up"
specificity <- TN / (TN + FP)
precision <- TP / (TP + FP)
cat("Accuracy: ", round(accuracy, 4), "\n")## Accuracy: 0.615
## Sensitivity: 0.67
## Specificity: 0.56
## Precision: 0.6036
| Metric | Formula | Value |
|---|---|---|
| Accuracy | \((TP+TN)/N\) | 0.615 |
| Sensitivity | \(TP/(TP+FN)\) | 0.67 |
| Specificity | \(TN/(TN+FP)\) | 0.56 |
| Precision | \(TP/(TP+FP)\) | 0.6036 |
# Equal class sizes (100 Up, 100 Down), so majority class = either
# Naive rule picks whichever is more frequent; here 50/50, so accuracy = 0.5
naive_accuracy <- max(100, 100) / N
cat("Naive majority-class accuracy:", naive_accuracy, "\n")## Naive majority-class accuracy: 0.5
## Model accuracy: 0.615
## Model beats naive? TRUE
Analysis:
Given: \(\bar{r} = 0.70\%\), \(s = 5.50\%\), \(n = 48\) months.
\[SR_{\text{monthly}} = \frac{\bar{r}}{s}\] \[SR_{\text{annual}} = SR_{\text{monthly}} \times \sqrt{12}\]
SR_monthly <- r_bar / s_r
scale_factor <- sqrt(12)
SR_annual <- SR_monthly * scale_factor
cat("Monthly Sharpe Ratio:", round(SR_monthly, 4), "\n")## Monthly Sharpe Ratio: 0.1273
## Scaling factor: 3.464 (√12 for monthly→annual)
## Annualized Sharpe: 0.4409
Result: \(SR_{\text{monthly}} = 0.1273\). Scaling factor is \(\sqrt{12} = 3.4641\). Annualized Sharpe ratio = 0.4409.
Bootstrap procedure (step by step):
set.seed(42)
B <- 1000
returns_sim <- rnorm(n_bt, mean = r_bar, sd = s_r) # simulated stand-in
boot_SR <- replicate(B, {
samp <- sample(returns_sim, n_bt, replace = TRUE)
mean(samp) / sd(samp)
})
cat("Bootstrap SE of monthly Sharpe:", round(sd(boot_SR), 4), "\n")## Bootstrap SE of monthly Sharpe: 0.1472
Why i.i.d. bootstrap is inappropriate: Monthly financial returns exhibit serial correlation (momentum, mean-reversion) and volatility clustering (ARCH/GARCH effects). Standard i.i.d. resampling breaks the time ordering and destroys these temporal dependencies, producing unreliable standard errors.
Fix — Block Bootstrap: The stationary block bootstrap (or circular block bootstrap) resamples contiguous blocks of consecutive returns, preserving the autocorrelation structure and heteroskedasticity within blocks. Block length should be chosen to span the dominant autocorrelation horizon.
Recommendation: Deploy \(\lambda = 0.065\) (the one-standard-error rule), retaining 7 factors.
Reasoning:
Walk-forward scheme:
# Illustrative diagram of expanding-window splits
total_months <- 60
init_train <- 36
h <- 6
windows <- data.frame(
Split = 1:4,
Train_end = seq(init_train, init_train + 3*h, by = h),
Test_start= seq(init_train + 1, init_train + 3*h + 1, by = h),
Test_end = seq(init_train + h, init_train + 4*h, by = h)
)
knitr::kable(windows, caption = "Walk-Forward Expanding-Window Splits (months)")| Split | Train_end | Test_start | Test_end |
|---|---|---|---|
| 1 | 36 | 37 | 42 |
| 2 | 42 | 43 | 48 |
| 3 | 48 | 49 | 54 |
| 4 | 54 | 55 | 60 |
Why random k-fold is unsafe:
Random k-fold shuffles observations before splitting, meaning future data can appear in the training fold and past data in the test fold. This constitutes look-ahead bias: the model implicitly “knows” future information during training, inflating apparent performance. Financial time series have temporal structure (trends, regimes, autocorrelation) that is destroyed by random shuffling. Walk-forward cross-validation respects the arrow of time — the model is always trained on the past and tested on the future, mimicking live deployment conditions.
End of Examination