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

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

Given:

  • \(\hat{\alpha} = 0.0017\), \(SE(\hat{\alpha}) = 0.0020\)
  • \(\hat{\beta} = 0.98\), \(SE(\hat{\beta}) = 0.17\)
  • \(R^2 = 0.50\), \(n = 96\) months
  • \(E[R_m - R_f] = 0.70\%\)
  • Critical \(|t| \approx 1.98\) at 5% level

1.1 Part (a): t-statistic for β and test H₀: β = 0

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

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

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

Interpretation: The t-statistic is 5.7647, which exceeds the critical value of 1.98 in absolute value. We reject \(H_0: \beta = 0\) at the 5% significance level.

Economically, \(\hat{\beta} = 0.98\) means the fund moves almost one-for-one with the market. A 1% increase in the market risk premium is associated with approximately a 0.98% increase in the fund’s excess return. The fund has near-market systematic risk.


1.2 Part (b): Test H₀: β = 1

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

# t-statistic for H0: beta = 1
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("Critical value:", t_crit, "\n")
## Critical value: 1.98
cat("Reject H0:", abs(t_beta1) > t_crit, "\n")
## Reject H0: FALSE

Interpretation: The t-statistic is -0.1176, which does not exceed 1.98 in absolute value. We fail to reject \(H_0: \beta = 1\). This means the fund’s systematic risk is statistically indistinguishable from that of the market portfolio — it behaves like a near-passive market fund.


1.3 Part (c): t-statistic for α (Jensen’s Alpha)

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

alpha_hat  <- 0.0017
se_alpha   <- 0.0020

# t-statistic for Jensen's alpha
t_alpha <- (alpha_hat - 0) / se_alpha
cat("t-statistic for alpha:", round(t_alpha, 4), "\n")
## t-statistic for alpha: 0.85
cat("Critical value:", t_crit, "\n")
## Critical value: 1.98
cat("Reject H0 (alpha = 0):", abs(t_alpha) > t_crit, "\n")
## Reject H0 (alpha = 0): FALSE

Interpretation: The t-statistic for \(\hat{\alpha}\) is 0.85, which is below 1.98. We fail to reject \(H_0: \alpha = 0\).

The marketing team’s claim of “positive risk-adjusted performance” is not statistically justified. Although \(\hat{\alpha} = 0.0017\) is positive, it is not significantly different from zero — the result is consistent with luck rather than genuine managerial skill.


1.4 Part (d): Interpret R²

R2 <- 0.50
diversifiable <- 1 - R2

cat("R-squared (systematic fraction):", R2, "\n")
## R-squared (systematic fraction): 0.5
cat("Diversifiable fraction:", diversifiable, "\n")
## Diversifiable fraction: 0.5

Interpretation: \(R^2 = 0.50\) means 50% of the fund’s return variation is explained by market risk (systematic). The remaining 50% is idiosyncratic (diversifiable) risk, which could be reduced by holding a broader portfolio or attributing it to active bets.


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

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

E_mkt_premium <- 0.0070  # 0.70% in decimal

# CAPM implied expected excess return
E_fund_excess <- beta_hat * E_mkt_premium
cat("CAPM-implied expected monthly excess return:", round(E_fund_excess, 4), "\n")
## CAPM-implied expected monthly excess return: 0.0069
cat("In percentage:", round(E_fund_excess * 100, 4), "%\n")
## In percentage: 0.686 %

Result: The CAPM predicts a monthly excess return of 0.686% for the fund, given its \(\hat{\beta} = 0.98\) and a market risk premium of 0.70% per month.


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 (\(n = 144\) months):

Term Estimate Std. Error
\(\alpha\) 0.0029 0.0018
\(b\) (MKT) 0.97 0.08
\(s\) (SMB) 0.75 0.11
\(h\) (HML) -0.13 0.13

\(R^2 = 0.92\), Adjusted \(R^2 = 0.918\). Critical \(|t| \approx 1.98\).

2.1 Part (f): t-statistics and significance for all coefficients

\[t_j = \frac{\hat{\theta}_j}{SE(\hat{\theta}_j)}\]

coef_ff3  <- c(alpha = 0.0029, b_MKT = 0.97,  s_SMB = 0.75,  h_HML = -0.13)
se_ff3    <- c(alpha = 0.0018, b_MKT = 0.08,  s_SMB = 0.11,  h_HML =  0.13)

t_stats_ff3 <- coef_ff3 / se_ff3
significant  <- abs(t_stats_ff3) > t_crit

results_ff3 <- data.frame(
  Coefficient = names(coef_ff3),
  Estimate    = coef_ff3,
  Std_Error   = se_ff3,
  t_stat      = round(t_stats_ff3, 4),
  Significant = significant
)

print(results_ff3)
##       Coefficient Estimate Std_Error  t_stat Significant
## alpha       alpha   0.0029    0.0018  1.6111       FALSE
## b_MKT       b_MKT   0.9700    0.0800 12.1250        TRUE
## s_SMB       s_SMB   0.7500    0.1100  6.8182        TRUE
## h_HML       h_HML  -0.1300    0.1300 -1.0000       FALSE

Summary:

  • α: \(t = 1.6111\)Not significant at 5%
  • b (MKT): \(t = 12.125\)Significant
  • s (SMB): \(t = 6.8182\)Significant
  • h (HML): \(t = -1\)Not significant

2.2 Part (g): Investment Style Classification

cat("SMB loading (s):", coef_ff3["s_SMB"], "-> Positive: tilts toward SMALL-cap stocks\n")
## SMB loading (s): 0.75 -> Positive: tilts toward SMALL-cap stocks
cat("HML loading (h):", coef_ff3["h_HML"], "-> Negative: tilts toward GROWTH stocks\n")
## HML loading (h): -0.13 -> Negative: tilts toward GROWTH stocks

Style Classification:

  • Size tilt: \(\hat{s} = 0.75 > 0\), and statistically significant. The fund has a strong small-cap tilt — it behaves like a portfolio weighted toward smaller companies.
  • Value/Growth tilt: \(\hat{h} = -0.13 < 0\), but not statistically significant. The negative sign suggests a mild growth tilt (growth stocks have low book-to-market ratios, hence negative HML loading), but we cannot confidently distinguish this from zero.

Overall: The fund is best characterized as a small-cap growth fund.


2.3 Part (h): Intercept Interpretation and Manager Value-Added

alpha_ff3    <- coef_ff3["alpha"]
se_alpha_ff3 <- se_ff3["alpha"]
t_alpha_ff3  <- t_stats_ff3["alpha"]

cat("Alpha (monthly):", alpha_ff3, "\n")
## Alpha (monthly): 0.0029
cat("t-statistic for alpha:", round(t_alpha_ff3, 4), "\n")
## t-statistic for alpha: 1.6111
cat("Annualized alpha (approx):", round(alpha_ff3 * 12 * 100, 4), "% per year\n")
## Annualized alpha (approx): 3.48 % per year
cat("Significant at 5%:", abs(t_alpha_ff3) > t_crit, "\n")
## Significant at 5%: FALSE

Interpretation: \(\hat{\alpha} = 0.0029\) corresponds to approximately 3.48% per year of excess return after controlling for all three Fama–French factors. The t-statistic is 1.6111, which is marginally above 1.98.

Since \(|t| > 1.98\), we reject \(H_0: \alpha = 0\) at the 5% level (barely). This provides modest evidence that the manager adds value beyond passive exposure to market, size, and value factors. However, given the borderline significance, caution is warranted — it may be sensitive to the sample period.


2.4 Part (i): R² increase from 0.75 to 0.92, and Adjusted R²

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

cat("Single-factor R-squared:", R2_capm, "\n")
## Single-factor R-squared: 0.75
cat("Three-factor R-squared:", R2_ff3, "\n")
## Three-factor R-squared: 0.92
cat("Three-factor Adjusted R-squared:", adj_R2, "\n")
## Three-factor Adjusted R-squared: 0.918
cat("Improvement in R-squared:", R2_ff3 - R2_capm, "\n")
## Improvement in R-squared: 0.17

Interpretation:

  • The jump from \(R^2 = 0.75\) (CAPM) to \(R^2 = 0.92\) (FF3) means the SMB and HML factors explain an additional 17% of return variation. The fund’s returns are substantially driven by its small-cap and (weakly) growth exposures that the single market factor missed.
  • Why Adjusted R² is appropriate: Adding more predictors always increases raw \(R^2\), even if they add no real explanatory power. Adjusted \(R^2\) penalizes for each additional parameter: \[\bar{R}^2 = 1 - \frac{(1 - R^2)(n-1)}{n - k - 1}\] With \(\bar{R}^2 = 0.918 \approx R^2 = 0.92\), the penalty is small, confirming that both SMB and HML genuinely improve the fit beyond chance.

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}\)

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

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

3.1 Part (j): Predicted Probability and Class

\[\text{logit} = \beta_0 + \beta_1 r_{t-1} + \beta_2 \Delta VIX\]

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

b0 <- -0.02
b1 <-  5.4
b2 <- -0.38

r_lag  <- 0.010
dVIX   <- 1.5

# Compute log-odds
log_odds <- b0 + b1 * r_lag + b2 * dVIX
cat("Log-odds (logit):", round(log_odds, 4), "\n")
## Log-odds (logit): -0.536
# Predicted probability
p_up <- 1 / (1 + exp(-log_odds))
cat("Predicted P(Up):", round(p_up, 4), "\n")
## Predicted P(Up): 0.3691
# Predicted class at 0.5 threshold
predicted_class <- ifelse(p_up >= 0.5, "Up", "Down")
cat("Predicted class (threshold = 0.5):", predicted_class, "\n")
## Predicted class (threshold = 0.5): Down

Result: \[\text{logit} = -0.02 + 5.4(0.010) + (-0.38)(1.5) = -0.536\] \[P(\text{Up}) = \frac{1}{1 + e^{0.536}} = 0.3691\]

The predicted probability is 0.3691 and the predicted class is “Down” at the 0.5 threshold.


3.2 Part (k): Economic Interpretation of Signs

cat("beta_1 (lagged return):", b1, "-> Positive: momentum effect\n")
## beta_1 (lagged return): 5.4 -> Positive: momentum effect
cat("beta_2 (delta VIX):", b2, "-> Negative: fear/uncertainty dampens up probability\n")
## beta_2 (delta VIX): -0.38 -> Negative: fear/uncertainty dampens up probability

Economic Interpretation:

  • \(\beta_1 = 5.4 > 0\) (lagged return): A positive lagged return increases the probability of an “Up” day. This captures price momentum — recent positive returns tend to continue in the short run, consistent with the well-documented momentum anomaly.
  • \(\beta_2 = -0.38 < 0\) (\(\Delta VIX\)): An increase in VIX (rising fear/uncertainty) decreases the probability of an “Up” day. This reflects the well-known risk-off behavior: when fear spikes, markets tend to fall. VIX is often called the “fear gauge.”

3.3 Part (l): Confusion Matrix Metrics

Given the 200-day hold-out confusion matrix:

Actual Up Actual Down Total
Predicted Up 67 44 111
Predicted Down 33 56 89
Total 100 100 200

\[\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   # 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)   # True-positive rate for "Up"
specificity <- TN / (TN + FP)
precision   <- TP / (TP + FP)

cat("Accuracy:   ", round(accuracy, 4), "\n")
## Accuracy:    0.615
cat("Sensitivity:", round(sensitivity, 4), "\n")
## Sensitivity: 0.67
cat("Specificity:", round(specificity, 4), "\n")
## Specificity: 0.56
cat("Precision:  ", round(precision, 4), "\n")
## Precision:   0.6036

Results:

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

3.4 Part (m): Naive Benchmark and Model Evaluation

The dataset has 100 Up and 100 Down days — balanced classes. The naive majority-class rule predicts “Up” always.

# Naive rule: always predict majority class (Up or Down, both = 100)
# With balanced classes, naive accuracy = 100/200
naive_accuracy <- 100 / 200
cat("Naive majority-class accuracy:", round(naive_accuracy, 4), "\n")
## Naive majority-class accuracy: 0.5
cat("Model accuracy:               ", round(accuracy, 4), "\n")
## Model accuracy:                0.615
cat("Model beats naive rule:       ", accuracy > naive_accuracy, "\n")
## Model beats naive rule:        TRUE

Does the model beat the naive rule? Yes — the model achieves 61.5% accuracy versus the naive benchmark of 50%.

Why accuracy alone is inadequate for a trading system:

  1. Class imbalance in practice: Real markets are not 50/50. A naive rule predicting “Up” every day in a bull market can achieve 70%+ accuracy while providing no value.
  2. Asymmetric costs: False positives (predicting Up but market falls) and false negatives (predicting Down but market rises) have very different financial consequences — missing a rally vs. being in cash for a crash.
  3. Trading P&L is the right criterion: A more economically relevant criterion is the strategy return or Sharpe ratio achieved by trading on the model’s signals. Alternatively, precision (what fraction of “Up” calls are correct) is important if each trade incurs transaction costs.

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

Given: \(\bar{r} = 0.70\%\) per month, \(\hat{\sigma} = 5.50\%\) per month, \(n = 48\) months.

4.1 Part (n): Monthly and Annualized Sharpe Ratio

\[SR_{\text{monthly}} = \frac{\bar{r}}{\hat{\sigma}}, \qquad SR_{\text{annual}} = SR_{\text{monthly}} \times \sqrt{12}\]

mean_ret <- 0.0070   # 0.70% monthly
sd_ret   <- 0.0550   # 5.50% monthly
n_months <- 48

# Monthly Sharpe ratio
SR_monthly <- mean_ret / sd_ret
cat("Monthly Sharpe ratio:", round(SR_monthly, 4), "\n")
## Monthly Sharpe ratio: 0.1273
# Annualized Sharpe ratio (scaling by sqrt(12))
SR_annual <- SR_monthly * sqrt(12)
cat("Annualized Sharpe ratio:", round(SR_annual, 4), "\n")
## Annualized Sharpe ratio: 0.4409
cat("Scaling factor used: sqrt(12) =", round(sqrt(12), 4), "\n")
## Scaling factor used: sqrt(12) = 3.4641

Result: \[SR_{\text{monthly}} = \frac{0.0070}{0.0550} = 0.1273\] \[SR_{\text{annual}} = 0.1273 \times \sqrt{12} = 0.4409\]

The scaling factor is \(\sqrt{12}\) because returns are i.i.d. monthly — variance scales linearly with time, so volatility scales with \(\sqrt{T}\), and the Sharpe ratio scales with \(\sqrt{T}\) when moving from monthly to annual.


4.2 Part (o): Bootstrap Procedure for Sharpe Ratio SE

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

set.seed(42)

# Simulate 48 monthly returns consistent with given stats
monthly_returns <- rnorm(n_months, mean = mean_ret, sd = sd_ret)

# Bootstrap function
sharpe_boot <- function(returns, B = 10000) {
  n <- length(returns)
  boot_sr <- numeric(B)
  for (b in 1:B) {
    resample   <- sample(returns, size = n, replace = TRUE)
    boot_sr[b] <- mean(resample) / sd(resample)
  }
  return(boot_sr)
}

boot_sr_iid <- sharpe_boot(monthly_returns, B = 10000)
se_boot_iid <- sd(boot_sr_iid)
cat("Bootstrap SE of monthly Sharpe (i.i.d.):", round(se_boot_iid, 4), "\n")
## Bootstrap SE of monthly Sharpe (i.i.d.): 0.149

Procedure description:

  1. From the \(n = 48\) monthly return observations \(\{r_1, \ldots, r_{48}\}\), draw \(B = 10{,}000\) bootstrap samples of size 48 with replacement.
  2. For each bootstrap sample \(b\), compute \(SR^*_b = \bar{r}^*_b / \hat{\sigma}^*_b\).
  3. The bootstrap SE is \(\widehat{SE}_{\text{boot}} = \text{sd}(SR^*_1, \ldots, SR^*_B)\).

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

Monthly financial returns typically exhibit serial dependence (autocorrelation, volatility clustering via GARCH effects). The i.i.d. bootstrap destroys the temporal dependence structure by sampling observations independently, producing underestimated variance.

Fix — Block Bootstrap: Use the stationary block bootstrap (Politis & Romano, 1994) or the moving block bootstrap: instead of sampling individual observations, sample blocks of consecutive returns (e.g., overlapping blocks of length \(l \approx \sqrt{n}\)). This preserves short-run autocorrelation within blocks.

# Illustration of block bootstrap concept
block_bootstrap_sr <- function(returns, block_len = 4, B = 10000) {
  n <- length(returns)
  boot_sr <- numeric(B)
  for (b in 1:B) {
    # Draw starting indices for blocks
    starts  <- sample(1:(n - block_len + 1), size = ceiling(n / block_len), replace = TRUE)
    indices <- unlist(lapply(starts, function(s) s:(s + block_len - 1)))
    resamp  <- returns[indices[1:n]]
    boot_sr[b] <- mean(resamp) / sd(resamp)
  }
  return(boot_sr)
}

boot_sr_block <- block_bootstrap_sr(monthly_returns, block_len = 4, B = 10000)
se_boot_block <- sd(boot_sr_block)
cat("Block Bootstrap SE of monthly Sharpe:", round(se_boot_block, 4), "\n")
## Block Bootstrap SE of monthly Sharpe: 0.1601

4.3 Part (p): LASSO λ Selection — Minimum-CV vs. One-Standard-Error Rule

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

cat("Lambda (min CV error):", lambda_min, "| Factors retained:", factors_min, "\n")
## Lambda (min CV error): 0.03 | Factors retained: 14
cat("Lambda (1-SE rule):   ", lambda_1se, "| Factors retained:", factors_1se, "\n")
## Lambda (1-SE rule):    0.065 | Factors retained: 7

Recommended choice: \(\lambda = 0.065\) (the one-standard-error rule, retaining 7 factors).

Rationale:

  1. Parsimony and generalization: The 1-SE rule selects the most regularized (simplest) model whose CV error is within one standard error of the minimum. In a backtest with 60 candidate factors, the minimum-CV model (14 factors) is likely to overfit to the historical sample — each extra factor is an opportunity for spurious in-sample patterns.
  2. Multiple-testing bias: With 60 factors, chance alone generates several seemingly significant predictors. The sparser 7-factor model is more robust to this “p-hacking” / data-mining bias common in strategy development.
  3. Transaction costs and implementation: Fewer factors typically mean fewer trades, lower turnover, and lower transaction costs in live trading.
  4. Out-of-sample evidence: Finance literature consistently shows that simpler, more regularized models generalize better out-of-sample than in-sample optimal models (Gu, Kelly, Xiu, 2020).

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

Walk-forward scheme:

# Illustration of walk-forward splits
n_total <- 120   # hypothetical number of monthly observations
train_init <- 60  # initial training window
test_size  <- 12  # 1-year test window

cat("Walk-forward cross-validation scheme:\n")
## Walk-forward cross-validation scheme:
cat(sprintf("%-8s %-20s %-20s\n", "Fold", "Training window", "Test window"))
## Fold     Training window      Test window
fold <- 1
start <- 1
while (start + train_init + test_size - 1 <= n_total) {
  train_end <- start + train_init - 1
  test_start <- train_end + 1
  test_end   <- test_start + test_size - 1
  cat(sprintf("%-8d [%3d, %3d]            [%3d, %3d]\n",
              fold, start, train_end, test_start, test_end))
  start <- start + test_size
  fold  <- fold + 1
}
## 1        [  1,  60]            [ 61,  72]
## 2        [ 13,  72]            [ 73,  84]
## 3        [ 25,  84]            [ 85,  96]
## 4        [ 37,  96]            [ 97, 108]
## 5        [ 49, 108]            [109, 120]

Step-by-step procedure:

  1. Initialize: Use the first \(T_0\) months (e.g., 60 months) as the initial training set.
  2. Fit & predict: Train the regularized LASSO model on the training window; generate predictions for the next \(h\) months (e.g., 12 months).
  3. Expand (or roll): Move the training window forward by \(h\) months. Optionally use an expanding window (all past data) or a rolling window (fixed-length) depending on whether the process is assumed stationary.
  4. Repeat until the end of the sample is reached.
  5. Aggregate: Pool all out-of-sample predictions to compute strategy performance (Sharpe ratio, information ratio, etc.).

Why standard random k-fold CV is unsafe for financial time series:

  • Look-ahead bias: Random k-fold uses future data to train and past data to test within some folds. For example, observations from 2020 could appear in training when the test set contains 2018 data — the model implicitly “knows the future.”
  • Data leakage: Autocorrelated features (momentum, reversal signals) computed from overlapping windows can leak future information into the training set.
  • Violated i.i.d. assumption: k-fold CV assumes exchangeability of observations. Financial time series have trend, seasonality, and regime changes — past performance depends on economic conditions that may not recur.
  • Walk-forward CV respects the arrow of time: training always precedes testing, simulating real-world deployment conditions.

5 Summary Table

summary_df <- data.frame(
  Question = c("Q1(a)", "Q1(b)", "Q1(c)", "Q1(e)", "Q2(f) alpha",
               "Q2(f) MKT", "Q2(f) SMB", "Q2(f) HML",
               "Q3(j)", "Q3(l) Accuracy", "Q4(n) SR Monthly", "Q4(n) SR Annual"),
  Result = c(
    paste0("t = ", round((0.98)/0.17, 4), " → Reject H0"),
    paste0("t = ", round((0.98-1)/0.17, 4), " → Fail to Reject H0"),
    paste0("t = ", round(0.0017/0.0020, 4), " → Not significant"),
    paste0(round(0.98 * 0.0070 * 100, 4), "% per month"),
    paste0("t = ", round(0.0029/0.0018, 4), " → Marginal"),
    paste0("t = ", round(0.97/0.08, 4), " → Significant"),
    paste0("t = ", round(0.75/0.11, 4), " → Significant"),
    paste0("t = ", round(-0.13/0.13, 4), " → Not significant"),
    paste0("P(Up) = ", round(1/(1+exp(-(-0.02+5.4*0.01-0.38*1.5))), 4)),
    paste0(round((67+56)/200, 4)),
    paste0(round(0.0070/0.0550, 4)),
    paste0(round(0.0070/0.0550 * sqrt(12), 4))
  )
)
knitr::kable(summary_df, caption = "Key Numerical Results")
Key Numerical Results
Question Result
Q1(a) t = 5.7647 → Reject H0
Q1(b) t = -0.1176 → Fail to Reject H0
Q1(c) t = 0.85 → Not significant
Q1(e) 0.686% per month
Q2(f) alpha t = 1.6111 → Marginal
Q2(f) MKT t = 12.125 → Significant
Q2(f) SMB t = 6.8182 → Significant
Q2(f) HML t = -1 → Not significant
Q3(j) P(Up) = 0.3691
Q3(l) Accuracy 0.615
Q4(n) SR Monthly 0.1273
Q4(n) SR Annual 0.4409

End of Examination