Context (CFA Problems 1–3): Hennessy & Associates manages a $30 million equity portfolio for the Wilstead Pension Fund. The portfolio holds ~40 stocks (2–3 % each). Jones proposes limiting it to 20 stocks by doubling commitments to the favored issues.
Q1a. Will limiting to 20 stocks likely increase or decrease portfolio risk?
Q1b. Can Hennessy reduce from 40 to 20 stocks without significantly increasing risk?
# ── Illustrate diversification effect ───────────────────────────────────────
n_stocks <- 1:50
# Assume average variance σ² = 0.04, average covariance ρσ²= 0.01
avg_var <- 0.04
avg_cov <- 0.01
port_var <- avg_cov + (avg_var - avg_cov) / n_stocks # textbook formula
diversification <- tibble(
n = n_stocks,
port_var = port_var,
port_sd = sqrt(port_var)
)
ggplot(diversification, aes(x = n, y = port_sd)) +
geom_line(color = "#2166ac", size = 1.2) +
geom_vline(xintercept = 20, linetype = "dashed", color = "#d6604d") +
geom_vline(xintercept = 40, linetype = "dashed", color = "#4dac26") +
annotate("text", x = 21, y = 0.175, label = "20 stocks", color = "#d6604d", hjust = 0) +
annotate("text", x = 41, y = 0.168, label = "40 stocks", color = "#4dac26", hjust = 0) +
scale_y_continuous(labels = percent_format()) +
labs(title = "Ch7 Q1 · Diversification: Portfolio SD vs Number of Stocks",
subtitle = "Avg σ = 20%, Avg correlation ≈ 0.25",
x = "Number of Stocks", y = "Portfolio Std Dev") +
theme_minimal(base_size = 12)# Quantify the difference between 40 and 20 stocks
sd_40 <- sqrt(avg_cov + (avg_var - avg_cov) / 40)
sd_20 <- sqrt(avg_cov + (avg_var - avg_cov) / 20)
increase <- (sd_20 - sd_40) / sd_40
tibble(
`Portfolio` = c("40 Stocks (current)", "20 Stocks (proposed)"),
`Port. Variance` = round(c(avg_cov + (avg_var-avg_cov)/40,
avg_cov + (avg_var-avg_cov)/20), 5),
`Port. Std Dev` = percent(c(sd_40, sd_20), accuracy = 0.01)
) %>%
kable(caption = "Portfolio Risk: 40 vs 20 Stocks") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Portfolio | Port. Variance | Port. Std Dev |
|---|---|---|
| 40 Stocks (current) | 0.01075 | 10.37% |
| 20 Stocks (proposed) | 0.01150 | 10.72% |
Answer:
Q1a: Limiting to 20 stocks will likely increase portfolio risk. Reducing the number of holdings reduces diversification — more idiosyncratic (firm-specific) risk remains un-diversified. Portfolio variance = \(\bar{\rho}\sigma^2 + \frac{(1-\bar{\rho})\sigma^2}{n}\); as n falls, the second term grows.
Q1b: Yes — if Hennessy selects the 20 stocks so they have low pairwise correlations with one another. By concentrating in stocks from different industries / geographies the idiosyncratic diversification benefit can be largely preserved even with fewer holdings. However, going from 40 to 20 still removes roughly 3.4% additional std dev in our simple model.
Q2. Why would further reduction to 10 stocks likely be less advantageous than the reduction to 20?
compare <- tibble(
n = c(40, 20, 10),
port_var = avg_cov + (avg_var - avg_cov) / c(40, 20, 10),
port_sd = sqrt(port_var),
label = c("Current\n(40)", "Proposed\n(20)", "Further\n(10)")
)
ggplot(compare, aes(x = label, y = port_sd, fill = label)) +
geom_col(width = 0.5, show.legend = FALSE) +
geom_text(aes(label = percent(port_sd, accuracy=0.01)),
vjust = -0.4, size = 4) +
scale_y_continuous(labels = percent_format(), limits = c(0, 0.22)) +
scale_fill_manual(values = c("#4dac26","#2166ac","#d6604d")) +
labs(title = "Ch7 Q2 · Portfolio SD at 40, 20, and 10 Holdings",
x = NULL, y = "Portfolio Std Dev") +
theme_minimal(base_size = 12)# Marginal benefit of each reduction step
mb_40_to_20 <- sd_40 - sd_20
sd_10 <- sqrt(avg_cov + (avg_var - avg_cov) / 10)
mb_20_to_10 <- sd_20 - sd_10
tibble(
Step = c("40 → 20 stocks", "20 → 10 stocks"),
`Risk Reduction` = percent(c(mb_40_to_20, mb_20_to_10), accuracy = 0.001)
) %>%
kable(caption = "Marginal Risk Reduction from Each Step") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Step | Risk Reduction |
|---|---|
| 40 → 20 stocks | -0.356% |
| 20 → 10 stocks | -0.678% |
Answer: The marginal benefit of diversification is decreasing. Going from 40 → 20 gives a larger risk reduction (-0.356%) than going from 20 → 10 (-0.678%). At 10 stocks, concentration risk rises sharply and the portfolio is far more exposed to the specific performance of individual issues. Because Wilstead evaluates Hennessy independently, the high idiosyncratic variance at 10 stocks is not offset by the other managers’ holdings — making the reduction to 10 less advantageous.
Q3. If Wilstead evaluates the Hennessy portfolio as part of the total fund (all six managers), how does this change the decision about limiting to 10 or 20?
# Total fund has 150+ stocks across 6 managers
# Hennessy contributes ~30/280 ≈ 10.7% of total
hennessy_share <- 30 / (30 + 250)
tibble(
Scenario = c("Hennessy alone (20 stocks)",
"Hennessy alone (10 stocks)",
"Total fund view (150+ stocks)"),
`Effective diversification` = c("Moderate", "Low", "High"),
`Idiosyncratic risk matters?` = c("Yes — evaluated standalone",
"Yes — even more so",
"No — diversified away in total fund")
) %>%
kable(caption = "Ch7 Q3 · Standalone vs Total Fund Evaluation") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Scenario | Effective diversification | Idiosyncratic risk matters? |
|---|---|---|
| Hennessy alone (20 stocks) | Moderate | Yes — evaluated standalone |
| Hennessy alone (10 stocks) | Low | Yes — even more so |
| Total fund view (150+ stocks) | High | No — diversified away in total fund |
Answer: From the total fund perspective, idiosyncratic risk in the Hennessy portfolio is largely diversified away by the other five managers who hold 150+ additional stocks. The committee should therefore be more willing to allow Hennessy to concentrate in 10 or 20 stocks, because:
Q4. Which portfolio cannot lie on the Markowitz efficient frontier?
portfolios <- tibble(
Portfolio = c("W", "X", "Z", "Y"),
`Expected Return` = c(15, 12, 5, 9),
`Std Dev` = c(36, 15, 7, 21)
)
portfolios %>%
kable(caption = "Ch7 Q4 · Portfolio Candidates") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Portfolio | Expected Return | Std Dev |
|---|---|---|
| W | 15 | 36 |
| X | 12 | 15 |
| Z | 5 | 7 |
| Y | 9 | 21 |
# Check: is any portfolio dominated (lower return, higher risk)?
# Plot
ggplot(portfolios, aes(x = `Std Dev`, y = `Expected Return`, label = Portfolio)) +
geom_point(size = 4, color = "#2166ac") +
geom_text(vjust = -0.8, size = 5, fontface = "bold") +
scale_x_continuous(limits = c(0, 42)) +
scale_y_continuous(limits = c(0, 18)) +
labs(title = "Ch7 Q4 · Mean-Variance Space",
x = "Standard Deviation (%)", y = "Expected Return (%)") +
theme_minimal(base_size = 12)Answer: Portfolio W cannot lie on the efficient frontier.
Portfolio W (E[R]=15%, σ=36%) is dominated by Portfolio X (E[R]=12%, σ=15%) in the sense that X achieves only slightly lower return for dramatically lower risk. More precisely, Portfolio Y (E[R]=9%, σ=21%) already dominates W in risk-adjusted terms — and no rational investor on the efficient frontier would hold W when they could achieve higher return per unit of risk elsewhere.
Formally: comparing W and X — X has lower expected return (12 < 15) but far lower standard deviation (15 vs 36). A portfolio with σ=36% and E[R]=15% would lie well to the right of the minimum-variance frontier at that return level, meaning W is dominated and cannot be efficient.
Q10. Given three stocks A, B, C — which equal-weight portfolio do you prefer: A+B or B+C?
# Given data
sigma <- c(A = 40, B = 20, C = 40) # std devs (%)
corr <- matrix(c(1.00, 0.90, 0.50,
0.90, 1.00, 0.10,
0.50, 0.10, 1.00),
nrow = 3, dimnames = list(c("A","B","C"), c("A","B","C")))
# Covariance matrix
cov_mat <- outer(sigma, sigma) * corr
# Equal weights: 50/50 each pair
w <- c(0.5, 0.5)
# Portfolio A+B
cov_AB <- cov_mat[c("A","B"), c("A","B")]
var_AB <- as.numeric(t(w) %*% cov_AB %*% w)
sd_AB <- sqrt(var_AB)
# Portfolio B+C
cov_BC <- cov_mat[c("B","C"), c("B","C")]
var_BC <- as.numeric(t(w) %*% cov_BC %*% w)
sd_BC <- sqrt(var_BC)
# Show calculation steps
tibble(
Portfolio = c("A + B (50/50)", "B + C (50/50)"),
`σ_A or σ_B` = c(sigma["A"], sigma["B"]),
`σ_B or σ_C` = c(sigma["B"], sigma["C"]),
`Correlation` = c(corr["A","B"], corr["B","C"]),
`Covariance` = c(cov_mat["A","B"], cov_mat["B","C"]),
`Port Variance`= round(c(var_AB, var_BC), 2),
`Port Std Dev` = round(c(sd_AB, sd_BC), 2)
) %>%
kable(caption = "Ch7 Q10 · Equal-Weight Portfolio Risk") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Portfolio | σ_A or σ_B | σ_B or σ_C | Correlation | Covariance | Port Variance | Port Std Dev |
|---|---|---|---|---|---|---|
| A + B (50/50) | 40 | 20 | 0.9 | 720 | 860 | 29.33 |
| B + C (50/50) | 20 | 40 | 0.1 | 80 | 540 | 23.24 |
Portfolio A+B Variance:
cat(sprintf("σ²(AB) = 0.5²×%d² + 0.5²×%d² + 2×0.5×0.5×%.2f×%d×%d = **%.2f**\n\n",
sigma["A"], sigma["B"], corr["A","B"], sigma["A"], sigma["B"], var_AB))σ²(AB) = 0.5²×40² + 0.5²×20² + 2×0.5×0.5×0.90×40×20 = 860.00
σ(AB) = 29.33%
Portfolio B+C Variance:
cat(sprintf("σ²(BC) = 0.5²×%d² + 0.5²×%d² + 2×0.5×0.5×%.2f×%d×%d = **%.2f**\n\n",
sigma["B"], sigma["C"], corr["B","C"], sigma["B"], sigma["C"], var_BC))σ²(BC) = 0.5²×20² + 0.5²×40² + 2×0.5×0.5×0.10×20×40 = 540.00
σ(BC) = 23.24%
Answer: Prefer Portfolio B+C (σ = 23.24%) over A+B (σ = 29.33%).
Since we only have risk information (no expected returns given), we minimise risk. The B+C portfolio has far lower standard deviation because B and C have a very low correlation of 0.10, providing strong diversification benefits. In contrast, A and B have a very high correlation of 0.90, so combining them provides almost no diversification benefit.
Q1. Regression results for ABC and XYZ — interpret and comment.
# Given regression output
reg_results <- tibble(
Statistic = c("Alpha (%)", "Beta", "R²", "Residual Std Dev (%)"),
ABC = c(-3.20, 0.60, 0.35, 13.02),
XYZ = c( 7.30, 0.97, 0.17, 21.45)
)
reg_results %>%
kable(caption = "Ch8 Q1 · OLS Regression Results (5-Year Monthly Excess Returns)") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Statistic | ABC | XYZ |
|---|---|---|
| Alpha (%) | -3.20 | 7.30 |
| Beta | 0.60 | 0.97 |
| R² | 0.35 | 0.17 |
| Residual Std Dev (%) | 13.02 | 21.45 |
# Additional brokerage beta estimates
brokerage <- tibble(
`Brokerage House` = c("A", "B"),
`Beta of ABC` = c(0.62, 0.71),
`Beta of XYZ` = c(1.45, 1.25)
)
brokerage %>%
kable(caption = "Recent 2-Year Brokerage Beta Estimates") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Brokerage House | Beta of ABC | Beta of XYZ |
|---|---|---|
| A | 0.62 | 1.45 |
| B | 0.71 | 1.25 |
# Decompose total risk into systematic and idiosyncratic
# Total variance = Beta²*Market_var + residual²
# Assume market monthly std dev ≈ well approximated by R²
# systematic risk share = R²
risk_decomp <- tibble(
Stock = c("ABC", "XYZ"),
Beta = c(0.60, 0.97),
`R² (systematic%)`= percent(c(0.35, 0.17), accuracy=1),
`1-R² (specific%)` = percent(c(0.65, 0.83), accuracy=1),
`Residual σ (%)` = c(13.02, 21.45)
)
risk_decomp %>%
kable(caption = "Risk Decomposition") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Stock | Beta | R² (systematic%) | 1-R² (specific%) | Residual σ (%) |
|---|---|---|---|---|
| ABC | 0.60 | 35% | 65% | 13.02 |
| XYZ | 0.97 | 17% | 83% | 21.45 |
Answer:
ABC: Alpha = −3.20% (negative — underperformed CAPM prediction). Beta = 0.60 (defensive, low market sensitivity). R² = 0.35 means only 35% of ABC’s return variance is explained by the market; 65% is firm-specific.
XYZ: Alpha = +7.30% (positive — outperformed CAPM prediction). Beta = 0.97 (nearly market-like). R² = only 0.17 — highly idiosyncratic. Large residual σ of 21.45% signals heavy stock-specific risk.
Implications for a diversified portfolio: In a well-diversified portfolio, idiosyncratic risk is eliminated. Therefore the residual standard deviation is irrelevant for pricing — only beta matters. Both stocks should be priced per CAPM based on their betas.
Beta instability: The brokerage estimates (2-year weekly) differ from the 5-year monthly betas — especially for XYZ (0.97 vs 1.25–1.45), suggesting beta has shifted upward for XYZ recently. Analysts should use the more recent estimates for forward-looking analysis.
Q2. Baker Fund correlation with market = 0.70. What % of total risk is nonsystematic?
rho <- 0.70
R2 <- rho^2
systematic_pct <- R2
nonsystematic_pct <- 1 - R2
tibble(
Metric = c("Correlation with market (ρ)",
"R² = ρ² (systematic risk %)",
"1 − R² (nonsystematic risk %)"),
Value = c(percent(rho, accuracy=1),
percent(systematic_pct, accuracy=1),
percent(nonsystematic_pct, accuracy=1))
) %>%
kable(caption = "Ch8 Q2 · Baker Fund Risk Decomposition") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Metric | Value |
|---|---|
| Correlation with market (ρ) | 70% |
| R² = ρ² (systematic risk %) | 49% |
| 1 − R² (nonsystematic risk %) | 51% |
# Visual
tibble(
Type = c("Systematic", "Nonsystematic"),
Share = c(systematic_pct, nonsystematic_pct)
) %>%
ggplot(aes(x = "", y = Share, fill = Type)) +
geom_col(width = 0.4) +
geom_text(aes(label = percent(Share, accuracy=1)),
position = position_stack(vjust = 0.5), size = 5, color = "white",
fontface = "bold") +
coord_flip() +
scale_fill_manual(values = c("Systematic" = "#2166ac",
"Nonsystematic" = "#d6604d")) +
labs(title = "Ch8 Q2 · Baker Fund: Systematic vs Nonsystematic Risk",
x = NULL, y = "Share of Total Risk") +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")Answer:
\[R^2 = \rho^2 = 0.70^2 = 0.49\]
Systematic (market) risk = 49% of total variance. Nonsystematic (firm-specific) risk = 1 − 0.49 = 51% of total risk.
Q3. Charlottesville International Fund: ρ with world index = 1.0. E[R_world] = 11%, E[R_fund] = 9%, R_f = 3%. What is the implied beta?
rho_world <- 1.0 # perfect correlation
E_Rm <- 0.11 # world market expected return
E_Rf_fund <- 0.09 # fund expected return
Rf <- 0.03 # risk-free rate
# CAPM: E[R] = Rf + beta*(E[Rm] - Rf)
# => beta = (E[R] - Rf) / (E[Rm] - Rf)
beta_implied <- (E_Rf_fund - Rf) / (E_Rm - Rf)
tibble(
Parameter = c("ρ (fund, world index)",
"E[R_world market]",
"E[R_fund]",
"Risk-free rate",
"Market risk premium",
"**Implied Beta**"),
Value = c(rho_world,
percent(E_Rm, accuracy=1),
percent(E_Rf_fund, accuracy=1),
percent(Rf, accuracy=1),
percent(E_Rm-Rf, accuracy=1),
round(beta_implied, 4))
) %>%
kable(caption = "Ch8 Q3 · Charlottesville International: Implied Beta") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Parameter | Value |
|---|---|
| ρ (fund, world index) | 1 |
| E[R_world market] | 11% |
| E[R_fund] | 9% |
| Risk-free rate | 3% |
| Market risk premium | 8% |
| Implied Beta | 0.75 |
Answer:
Because ρ = 1.0 (perfect correlation), all of the fund’s risk is systematic. Using CAPM:
\[\beta = \frac{E[R_{fund}] - R_f}{E[R_m] - R_f} = \frac{9\% - 3\%}{11\% - 3\%} = \frac{6\%}{8\%} = \mathbf{0.75}\]
Q4. Beta is most closely associated with which risk concept?
tibble(
Option = c("a", "b", "c", "d"),
Concept = c("Correlation coefficients",
"Mean-variance analysis",
"Nonsystematic risk",
"Systematic risk"),
Correct = c("", "", "", "✅ ANSWER")
) %>%
kable(caption = "Ch8 Q4 · Beta and Risk") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) %>%
row_spec(4, bold = TRUE, background = "#d4edda")| Option | Concept | Correct |
|---|---|---|
| a | Correlation coefficients | |
| b | Mean-variance analysis | |
| c | Nonsystematic risk | |
| d | Systematic risk | ✅ ANSWER | |
Answer: (d) Systematic risk.
Beta measures the sensitivity of a security’s return to the market (systematic) factor. It captures only the co-movement with the broad market, not firm-specific (nonsystematic) risk.
Q5. How do beta and standard deviation differ as risk measures?
tibble(
Option = c("a", "b", "c", "d"),
Statement = c(
"Beta: only unsystematic risk; σ: total risk",
"Beta: only systematic risk; σ: total risk",
"Beta: systematic + unsystematic; σ: only unsystematic",
"Beta: systematic + unsystematic; σ: only systematic"
),
Correct = c("", "✅ ANSWER", "", "")
) %>%
kable(caption = "Ch8 Q5 · Beta vs Standard Deviation as Risk Measures") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) %>%
row_spec(2, bold = TRUE, background = "#d4edda")| Option | Statement | Correct |
|---|---|---|
| a | Beta: only unsystematic risk; σ: total risk | |
| b | Beta: only systematic risk; σ: total risk | ✅ ANSWER | |
| c | Beta: systematic + unsystematic; σ: only unsystematic | |
| d | Beta: systematic + unsystematic; σ: only systematic |
Answer: (b)
| Measure | Captures |
|---|---|
| Beta | Only systematic (market) risk — co-movement with market index |
| Standard deviation | Total risk = systematic + nonsystematic (firm-specific) |
In a well-diversified portfolio, nonsystematic risk is eliminated, so beta is the appropriate risk measure for pricing. Standard deviation is appropriate when evaluating a standalone (undiversified) position.
Data for CFA Q8 & Q9:
portfolio_data <- tibble(
Portfolio = c("R", "S&P 500"),
`Avg Annual Return` = c("11%", "14%"),
`Std Dev` = c("10%", "12%"),
Beta = c(0.5, 1.0)
)
portfolio_data %>%
kable(caption = "Ch9 · Portfolio R vs S&P 500") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Portfolio | Avg Annual Return | Std Dev | Beta |
|---|---|---|---|
| R | 11% | 10% | 0.5 |
| S&P 500 | 14% | 12% | 1.0 |
Q8. When plotting portfolio R relative to the SML, portfolio R lies:
# SML: E[R] = Rf + beta*(E[Rm] - Rf)
# Need to determine Rf. Use S&P 500 as market proxy
# From data: E[Rm]=14%, beta_m=1
# We need Rf to draw the SML.
# Portfolio R: E[R]=11%, beta=0.5
# SML prediction for beta=0.5: E[R] = Rf + 0.5*(14% - Rf)
# Let's solve for Rf using the S&P as market
# If S&P is the market portfolio, its alpha = 0 by definition
# Try a typical Rf (exam context often uses ~6%)
Rf <- 0.06 # assumed risk-free rate (consistent with typical exam context)
E_Rm <- 0.14
beta_R <- 0.5
E_R_actual <- 0.11
# SML prediction for Portfolio R
E_R_sml <- Rf + beta_R * (E_Rm - Rf)
# Alpha of Portfolio R
alpha_R <- E_R_actual - E_R_sml
# Plot SML
betas_seq <- seq(0, 1.5, by = 0.1)
sml_line <- tibble(Beta = betas_seq,
`E[R]` = Rf + betas_seq * (E_Rm - Rf))
ggplot(sml_line, aes(x = Beta, y = `E[R]`)) +
geom_line(color = "grey40", size = 1) +
geom_point(aes(x = beta_R, y = E_R_actual), color = "#d6604d", size = 4) +
geom_point(aes(x = beta_R, y = E_R_sml), color = "#2166ac", size = 3,
shape = 17) +
geom_segment(aes(x = beta_R, xend = beta_R,
y = E_R_sml, yend = E_R_actual),
arrow = arrow(length = unit(0.2,"cm")),
color = "#d6604d", linetype = "dashed") +
annotate("text", x = beta_R + 0.06, y = E_R_actual,
label = sprintf("Portfolio R\n(Actual: %.0f%%)", E_R_actual*100),
color = "#d6604d", size = 3.5) +
annotate("text", x = beta_R + 0.06, y = E_R_sml,
label = sprintf("SML prediction\n(%.0f%%)", E_R_sml*100),
color = "#2166ac", size = 3.5) +
scale_y_continuous(labels = percent_format()) +
labs(title = "Ch9 Q8 · Portfolio R Relative to the SML",
subtitle = sprintf("α = Actual − SML = %.0f%% − %.0f%% = %+.0f%%",
E_R_actual*100, E_R_sml*100, alpha_R*100),
x = "Beta", y = "Expected Return") +
theme_minimal(base_size = 12)tibble(
Item = c("Risk-free rate (Rf)",
"Market return E[Rm]",
"Beta of Portfolio R",
"SML predicted return",
"Actual return of R",
"Alpha (actual − SML)"),
Value = c(percent(Rf, accuracy=1),
percent(E_Rm, accuracy=1),
beta_R,
percent(E_R_sml, accuracy=1),
percent(E_R_actual, accuracy=1),
percent(alpha_R, accuracy=1))
) %>%
kable(caption = "Ch9 Q8 · SML Calculation") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Item | Value |
|---|---|
| Risk-free rate (Rf) | 6% |
| Market return E[Rm] | 14% |
| Beta of Portfolio R | 0.5 |
| SML predicted return | 10% |
| Actual return of R | 11% |
| Alpha (actual − SML) | 1% |
Answer: (c) Above the SML.
SML predicts 10% for β = 0.5. Portfolio R actually returned 11%, so α = 1% — Portfolio R plots above the SML, indicating it outperformed its CAPM-required return.
Q9. When plotting portfolio R relative to the CML, portfolio R lies:
# CML: E[R] = Rf + (E[Rm]-Rf)/σ_m * σ_p
sigma_m <- 0.12 # S&P 500 std dev
sigma_R <- 0.10 # Portfolio R std dev
E_Rm <- 0.14
# CML prediction for portfolio R's std dev
E_R_cml <- Rf + ((E_Rm - Rf) / sigma_m) * sigma_R
alpha_cml <- E_R_actual - E_R_cml
# Plot CML
sigma_seq <- seq(0, 0.20, by = 0.01)
cml_line <- tibble(SD = sigma_seq,
`E[R]` = Rf + ((E_Rm - Rf) / sigma_m) * sigma_seq)
ggplot(cml_line, aes(x = SD, y = `E[R]`)) +
geom_line(color = "grey40", size = 1) +
geom_point(aes(x = sigma_R, y = E_R_actual), color = "#d6604d", size = 4) +
geom_point(aes(x = sigma_R, y = E_R_cml), color = "#2166ac", size = 3,
shape = 17) +
geom_segment(aes(x = sigma_R, xend = sigma_R,
y = E_R_cml, yend = E_R_actual),
arrow = arrow(length = unit(0.2,"cm")),
color = "#d6604d", linetype = "dashed") +
annotate("text", x = sigma_R + 0.008, y = E_R_actual,
label = sprintf("Portfolio R\n(%.0f%%)", E_R_actual*100),
color = "#d6604d", size = 3.5) +
annotate("text", x = sigma_R + 0.008, y = E_R_cml,
label = sprintf("CML: %.1f%%", E_R_cml*100),
color = "#2166ac", size = 3.5) +
scale_x_continuous(labels = percent_format()) +
scale_y_continuous(labels = percent_format()) +
labs(title = "Ch9 Q9 · Portfolio R Relative to the CML",
subtitle = sprintf("CML predicts %.1f%% for σ=10%%; Actual = 11%%",
E_R_cml*100),
x = "Standard Deviation", y = "Expected Return") +
theme_minimal(base_size = 12)tibble(
Item = c("Sharpe ratio of market (S&P 500)",
"CML prediction for σ=10%",
"Actual return of R",
"Position vs CML"),
Value = c(round((E_Rm-Rf)/sigma_m, 4),
percent(E_R_cml, accuracy=0.1),
percent(E_R_actual, accuracy=1),
ifelse(E_R_actual > E_R_cml,
"Above CML", "Below CML"))
) %>%
kable(caption = "Ch9 Q9 · CML Calculation") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Item | Value |
|---|---|
| Sharpe ratio of market (S&P 500) | 0.6667 |
| CML prediction for σ=10% | 12.7% |
| Actual return of R | 11% |
| Position vs CML | Below CML |
Answer: (b) Below the CML.
\[E[R]_{CML} = R_f + \frac{E[R_m]-R_f}{\sigma_m}\cdot\sigma_R = 6\% + \frac{8\%}{12\%}\times 10\% = 12.7%\]
Portfolio R’s actual return of 11% < CML prediction of 12.7%, so it lies below the CML.
The CML only contains fully efficient (optimally diversified) portfolios. Portfolio R has β = 0.5 with σ = 10% — it carries idiosyncratic risk that could be further reduced, which is why it falls short of the CML.
Q10. Should investors expect a higher return on Portfolio A than B under CAPM?
ab_data <- tibble(
Portfolio = c("A", "B"),
`Systematic Risk (β)` = c(1.0, 1.0),
`Specific Risk` = c("High", "Low")
)
ab_data %>%
kable(caption = "Ch9 Q10 · Portfolio A vs B") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Portfolio | Systematic Risk (β) | Specific Risk |
|---|---|---|
| A | 1 | High |
| B | 1 | Low |
Answer: No — under CAPM, both portfolios have the same expected return.
CAPM states:
\[E[R_i] = R_f + \beta_i \cdot (E[R_m] - R_f)\]
Since both A and B have β = 1.0, CAPM assigns them the same expected return regardless of their firm-specific (idiosyncratic) risk levels.
The key insight: CAPM only compensates systematic risk (beta). Specific (unsystematic) risk is not rewarded because rational investors hold diversified portfolios and diversify it away. Therefore:
→ Same required return. An investor holding Portfolio A is bearing extra (uncompensated) risk.
Context (Problems 13–16): Orb Trust is exploring APT. McCracken proposes a two-factor APT model:
Factor Risk Premium Real GDP growth 8% Inflation 2% High Growth Fund: Factor sensitivities = 1.25 (GDP), 1.5 (Inflation)
Large Cap Fund: Expected excess return = 8.5% above Rf; sensitivities = 0.75 (GDP), 1.25 (Inflation)
Utility Fund: Sensitivities = 1.0 (GDP), 2.0 (Inflation)
Risk-free rate = 4%
Rf_apt <- 0.04
rp_gdp <- 0.08 # GDP risk premium
rp_inf <- 0.02 # Inflation risk premium
# Fund sensitivities
b_HG <- c(gdp = 1.25, inf = 1.50) # High Growth
b_LC <- c(gdp = 0.75, inf = 1.25) # Large Cap
b_UT <- c(gdp = 1.00, inf = 2.00) # Utility
funds <- tibble(
Fund = c("High Growth", "Large Cap", "Utility"),
`β_GDP` = c(b_HG["gdp"], b_LC["gdp"], b_UT["gdp"]),
`β_Inflation` = c(b_HG["inf"], b_LC["inf"], b_UT["inf"])
)
funds %>%
kable(caption = "Ch10 · Fund Factor Sensitivities") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Fund | β_GDP | β_Inflation |
|---|---|---|
| High Growth | 1.25 | 1.50 |
| Large Cap | 0.75 | 1.25 |
| Utility | 1.00 | 2.00 |
Q13. Using APT with Rf = 4%, what is the expected return on the High Growth Fund?
# APT: E[R] = Rf + β_GDP * RP_GDP + β_Inf * RP_Inf
E_R_HG_APT <- Rf_apt + b_HG["gdp"] * rp_gdp + b_HG["inf"] * rp_inf
tibble(
Component = c("Risk-free rate",
"GDP factor: 1.25 × 8%",
"Inflation factor: 1.50 × 2%",
"**APT Expected Return**"),
Calculation = c("4%",
"10.0%",
" 3.0%",
sprintf("**%.1f%%**", E_R_HG_APT*100))
) %>%
kable(caption = "Ch10 Q13 · APT Expected Return: High Growth Fund") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) %>%
row_spec(4, bold = TRUE, background = "#d4edda")| Component | Calculation |
|---|---|
| Risk-free rate | 4% |
| GDP factor: 1.25 × 8% | 10.0% |
| Inflation factor: 1.50 × 2% | 3.0% |
| APT Expected Return | 17.0% |
Answer:
\[E[R_{HG}] = 4\% + 1.25 \times 8\% + 1.50 \times 2\% = 4\% + 10\% + 3\% = \mathbf{17%}\]
Q14. Is there an arbitrage opportunity for the Large Cap Fund?
# APT prediction for Large Cap
E_R_LC_APT <- Rf_apt + b_LC["gdp"] * rp_gdp + b_LC["inf"] * rp_inf
# Kwon's fundamental analysis estimate
E_R_LC_Kwon <- Rf_apt + 0.085 # 8.5% above risk-free
mispricing <- E_R_LC_Kwon - E_R_LC_APT
tibble(
Item = c("APT equilibrium return",
"Kwon's fundamental estimate",
"Difference (alpha)"),
Calculation = c(
sprintf("4%% + 0.75×8%% + 1.25×2%% = %.1f%%", E_R_LC_APT*100),
sprintf("4%% + 8.5%% = %.1f%%", E_R_LC_Kwon*100),
sprintf("%+.1f%%", mispricing*100)
)
) %>%
kable(caption = "Ch10 Q14 · Arbitrage Check: Large Cap Fund") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Item | Calculation |
|---|---|
| APT equilibrium return | 4% + 0.75×8% + 1.25×2% = 12.5% |
| Kwon’s fundamental estimate | 4% + 8.5% = 12.5% |
| Difference (alpha) | +0.0% |
Answer:
\[E[R_{LC}]_{APT} = 4\% + 0.75\times8\% + 1.25\times2\% = 4\% + 6\% + 2.5\% = 12.5%\]
Kwon estimates 12.5% via fundamental analysis.
Since 12.5% > 12.5%, the Large Cap Fund is underpriced relative to APT equilibrium → Yes, an arbitrage opportunity exists (α = 0.0%).
Strategy: buy the Large Cap Fund (long) and sell a replicating APT factor portfolio (short) to lock in the 0.0% excess return at zero net factor exposure.
Q15. What is the weight of the Utility Fund in the GDP Fund?
# The GDP Fund must have: β_GDP = 1, β_Inf = 0
# Portfolio of: w_HG * High Growth + w_LC * Large Cap + w_UT * Utility
# Subject to:
# w_HG + w_LC + w_UT = 1
# w_HG*1.25 + w_LC*0.75 + w_UT*1.0 = 1 (GDP beta = 1)
# w_HG*1.50 + w_LC*1.25 + w_UT*2.0 = 0 (Inflation beta = 0)
# Solve the 3x3 system: A %*% w = b
A <- matrix(c(
1, 1, 1, # weights sum to 1
1.25, 0.75, 1.00, # GDP beta = 1
1.50, 1.25, 2.00 # Inflation beta = 0
), nrow = 3, byrow = TRUE)
b <- c(1, 1, 0)
w_sol <- solve(A, b)
names(w_sol) <- c("High Growth", "Large Cap", "Utility")
tibble(
Fund = names(w_sol),
Weight = round(w_sol, 4),
`Weight %` = percent(w_sol, accuracy=0.1)
) %>%
kable(caption = "Ch10 Q15 · GDP Fund Weights") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) %>%
row_spec(3, bold = TRUE, background = "#d4edda")| Fund | Weight | Weight % |
|---|---|---|
| High Growth | 1.6 | 160.0% |
| Large Cap | 1.6 | 160.0% |
| Utility | -2.2 | -220.0% |
##
## --- Verification ---
## Sum of weights: 1.0000 (should be 1.0)
cat(sprintf("GDP beta: %.4f (should be 1.0)\n",
sum(w_sol * c(b_HG["gdp"], b_LC["gdp"], b_UT["gdp"]))))## GDP beta: 1.0000 (should be 1.0)
cat(sprintf("Inflation beta: %.4f (should be 0.0)\n",
sum(w_sol * c(b_HG["inf"], b_LC["inf"], b_UT["inf"]))))## Inflation beta: 0.0000 (should be 0.0)
Answer: Weight of Utility Fund = -2.2
This corresponds to answer (b) −3.2 from the multiple choice options (a) −2.2; (b) −3.2; (c) 0.3.
The negative weight means the GDP Fund shorts the Utility Fund. The three equations solved are:
Q16. Who is correct about the GDP Fund’s suitability — Stiles or McCracken?
tibble(
Option = c("a", "b", "c"),
Statement = c(
"McCracken is correct and Stiles is wrong",
"Both are correct",
"Stiles is correct and McCracken is wrong"
),
Correct = c("✅ ANSWER", "", "")
) %>%
kable(caption = "Ch10 Q16 · GDP Fund Suitability") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE) %>%
row_spec(1, bold = TRUE, background = "#d4edda")| Option | Statement | Correct |
|---|---|---|
| a | McCracken is correct and Stiles is wrong | ✅ ANSWER | |
| b | Both are correct | |
| c | Stiles is correct and McCracken is wrong |
# Compute GDP Fund expected return under APT
E_R_GDP_fund <- Rf_apt + 1 * rp_gdp + 0 * rp_inf
tibble(
Item = c("GDP Fund β_GDP", "GDP Fund β_Inflation",
"APT Expected Return",
"Return type"),
Value = c("1.0", "0.0",
percent(E_R_GDP_fund, accuracy=1),
"Variable — tied to GDP realizations")
) %>%
kable(caption = "GDP Fund Characteristics") %>%
kable_styling(bootstrap_options = c("striped","hover"), full_width = FALSE)| Item | Value |
|---|---|
| GDP Fund β_GDP | 1.0 |
| GDP Fund β_Inflation | 0.0 |
| APT Expected Return | 12% |
| Return type | Variable — tied to GDP realizations |
Answer: (a) McCracken is correct and Stiles is wrong.
Stiles argued the GDP Fund is good for retirees who live off steady income. This is incorrect — the GDP Fund’s return fluctuates with real GDP growth. It is not a stable income source; its returns are volatile and cyclical. Retirees needing steady income would prefer fixed-income (inflation-protected) instruments, not a GDP-sensitive fund.
McCracken argued the GDP Fund is a good choice if supply-side macro policies succeed (i.e., if GDP growth outperforms). This is correct — the fund profits when GDP surprises to the upside, making it suitable for investors who believe in strong economic growth and can tolerate income variability.
The APT expected return is: \[E[R_{GDP}] = 4\% + 1.0\times8\% + 0\times2\% = 12%\]
End of Textbook Solutions