Level 5 — MasteryPortfolio Theory

Portfolio Theory

90 minutes60 marksprintable — key stays hidden on paper

Chapter: 5.5 Portfolio Theory Level: 5 — Mastery (cross-domain: math + statistics + coding, build/prove) Time limit: 90 minutes Total marks: 60

Instructions: Answer all three questions. Show all derivations. Where code is requested, write clean, runnable Python (NumPy) and state assumptions. Use ...... notation for mathematics.


Question 1 — Two-Asset Optimization, Diversification & the Efficient Frontier (20 marks)

Two risky assets have the following annualised statistics:

  • Asset A: expected return μA=0.10\mu_A = 0.10, volatility σA=0.20\sigma_A = 0.20
  • Asset B: expected return μB=0.16\mu_B = 0.16, volatility σB=0.30\sigma_B = 0.30
  • Correlation ρAB=0.20\rho_{AB} = 0.20

(a) Derive from first principles the weight wAw_A (with wB=1wAw_B = 1-w_A) that produces the global minimum-variance portfolio (GMVP) for two assets. State the general formula, then compute wA,wBw_A, w_B numerically. (6)

(b) Compute the expected return and volatility of the GMVP. Verify that its volatility is strictly lower than min(σA,σB)\min(\sigma_A,\sigma_B) and explain why this diversification benefit exists in terms of covariance. (5)

(c) Prove that as ρAB1\rho_{AB} \to -1, a risk-free combination of the two assets exists, and derive the weight wAw_A that achieves σp=0\sigma_p = 0. (4)

(d) Write a NumPy function frontier(mu, cov, n) that returns n points (σp,μp)(\sigma_p, \mu_p) on the two-asset frontier by sweeping wA[0,1]w_A \in [0,1]. Explain how you would identify the efficient portion of the frontier from the output. (5)


Question 2 — CAPM, the Security Market Line & Alpha (22 marks)

The risk-free rate is rf=0.04r_f = 0.04 and the market portfolio has μM=0.11\mu_M = 0.11, σM=0.18\sigma_M = 0.18.

A fund manager reports the following realised annual data for portfolio PP: μP=0.14\mu_P = 0.14, σP=0.25\sigma_P = 0.25, Cov(P,M)=0.0243\text{Cov}(P,M) = 0.0243.

(a) Derive βP\beta_P from the covariance definition, then use the Security Market Line (SML) to compute the CAPM-required return of PP. (5)

(b) Compute Jensen's alpha of the portfolio. Interpret the sign: is the manager adding value on a systematic-risk-adjusted basis? (4)

(c) Decompose σP2\sigma_P^2 into systematic and unsystematic components. State each as a variance and as a fraction of total variance. (5)

(d) Compute and compare the Sharpe ratio and Treynor ratio of PP versus the market. Explain why a portfolio can beat the market on Treynor but lose on Sharpe, and what that reveals about its unsystematic risk. (5)

(e) Prove algebraically that for a fully diversified portfolio (zero unsystematic risk) lying on the SML, the Sharpe ratio and Treynor ratio give consistent rankings relative to the market. (3)


Question 3 — Sortino Ratio: Build & Prove (18 marks)

A strategy produces the following 8 monthly excess returns (over target τ=0\tau = 0), in decimal: [0.05, 0.02, 0.03, 0.06, 0.04, 0.01, 0.03, 0.02][\,0.05,\ -0.02,\ 0.03,\ -0.06,\ 0.04,\ 0.01,\ -0.03,\ 0.02\,]

(a) Define the downside deviation σd\sigma_d relative to target τ\tau and the Sortino ratio. Explain why Sortino differs from Sharpe in its treatment of upside volatility. (4)

(b) Compute σd\sigma_d and the Sortino ratio for the data above (use τ=0\tau=0; mean of the raw returns as the numerator; divide sum of squared shortfalls by N=8N=8). (6)

(c) Write a NumPy function sortino(returns, target, periods_per_year) that returns the annualised Sortino ratio (annualise mean by ×\timesperiods, downside deviation by ×periods\times\sqrt{\text{periods}}). (4)

(d) Prove that for a return series with no observations below the target, the Sortino ratio is undefined (or ++\infty), and explain what this implies about ranking such a strategy against peers. (4)

Answer keyMark scheme & solutions

Question 1

(a) For two assets, portfolio variance is σp2=wA2σA2+(1wA)2σB2+2wA(1wA)σAB,\sigma_p^2 = w_A^2\sigma_A^2 + (1-w_A)^2\sigma_B^2 + 2w_A(1-w_A)\sigma_{AB}, where σAB=ρABσAσB\sigma_{AB} = \rho_{AB}\sigma_A\sigma_B. Setting dσp2dwA=0\frac{d\sigma_p^2}{dw_A}=0: wAGMVP=σB2σABσA2+σB22σAB.(2 marks for derivation)w_A^{GMVP} = \frac{\sigma_B^2 - \sigma_{AB}}{\sigma_A^2 + \sigma_B^2 - 2\sigma_{AB}}. \quad (2\text{ marks for derivation})

Compute σAB=0.200.200.30=0.012\sigma_{AB} = 0.20\cdot0.20\cdot0.30 = 0.012. wA=0.090.0120.04+0.092(0.012)=0.0780.106=0.7358.w_A = \frac{0.09 - 0.012}{0.04 + 0.09 - 2(0.012)} = \frac{0.078}{0.106} = 0.7358. wB=0.2642w_B = 0.2642. (2 formula + 2 correct numbers = 6)

(b) μp=0.7358(0.10)+0.2642(0.16)=0.115850.1159\mu_p = 0.7358(0.10) + 0.2642(0.16) = 0.11585 \approx 0.1159. (1) σp2=0.73582(0.04)+0.26422(0.09)+2(0.7358)(0.2642)(0.012)\sigma_p^2 = 0.7358^2(0.04) + 0.2642^2(0.09) + 2(0.7358)(0.2642)(0.012) =0.021658+0.006283+0.004666=0.032607σp=0.1806.= 0.021658 + 0.006283 + 0.004666 = 0.032607 \Rightarrow \sigma_p = 0.1806. (2) Since 0.1806<0.20=min(σA,σB)0.1806 < 0.20 = \min(\sigma_A,\sigma_B), diversification lowers risk. (1) Why: because ρAB=0.2<1\rho_{AB}=0.2 < 1, the covariance term is smaller than it would be under perfect correlation; imperfectly correlated assets partially offset each other's fluctuations, so combined variance falls below the individual variances. (1)

(c) With ρ=1\rho=-1, σAB=σAσB\sigma_{AB} = -\sigma_A\sigma_B and σp2=(wAσA(1wA)σB)2.\sigma_p^2 = (w_A\sigma_A - (1-w_A)\sigma_B)^2. This is a perfect square, so σp=0\sigma_p=0 when wAσA=(1wA)σBw_A\sigma_A = (1-w_A)\sigma_B, giving wA=σBσA+σB=0.300.50=0.60.w_A = \frac{\sigma_B}{\sigma_A+\sigma_B} = \frac{0.30}{0.50} = 0.60. (2 for perfect-square form + 2 for weight = 4)

(d)

import numpy as np
def frontier(mu, cov, n):
    ws = np.linspace(0, 1, n)
    pts = []
    for wA in ws:
        w = np.array([wA, 1-wA])
        mp = w @ mu
        vp = w @ cov @ w
        pts.append((np.sqrt(vp), mp))
    return np.array(pts)

Efficient portion: find the GMVP (minimum σp\sigma_p); all points with μpμGMVP\mu_p \ge \mu_{GMVP} form the efficient frontier — for any given risk level an investor prefers the higher return, so the lower branch (below GMVP return) is dominated. (3 code + 2 explanation = 5)


Question 2

(a) βP=Cov(P,M)σM2=0.02430.182=0.02430.0324=0.75\beta_P = \dfrac{\text{Cov}(P,M)}{\sigma_M^2} = \dfrac{0.0243}{0.18^2} = \dfrac{0.0243}{0.0324} = 0.75. (2) SML: rPCAPM=rf+βP(μMrf)=0.04+0.75(0.110.04)=0.04+0.0525=0.0925r_P^{CAPM} = r_f + \beta_P(\mu_M - r_f) = 0.04 + 0.75(0.11-0.04) = 0.04 + 0.0525 = 0.0925. (3)

(b) Jensen's alpha =μPrPCAPM=0.140.0925=0.0475= \mu_P - r_P^{CAPM} = 0.14 - 0.0925 = 0.0475 (4.75%). (3) Positive alpha ⇒ the manager earned 4.75% above the systematic-risk-adjusted required return ⇒ adding value. (1)

(c) Systematic variance =βP2σM2=0.752(0.0324)=0.018225= \beta_P^2\sigma_M^2 = 0.75^2(0.0324) = 0.018225. (2) Total variance =σP2=0.252=0.0625= \sigma_P^2 = 0.25^2 = 0.0625. (1) Unsystematic variance =0.06250.018225=0.044275= 0.0625 - 0.018225 = 0.044275. (1) Fractions: systematic =0.018225/0.0625=0.2916= 0.018225/0.0625 = 0.2916 (29.16%); unsystematic =70.84%= 70.84\%. (1)

(d) SharpeP=μPrfσP=0.100.25=0.40_P = \dfrac{\mu_P - r_f}{\sigma_P} = \dfrac{0.10}{0.25} = 0.40. SharpeM=0.110.040.18=0.070.18=0.3889_M = \dfrac{0.11-0.04}{0.18} = \dfrac{0.07}{0.18} = 0.3889. (2) TreynorP=μPrfβP=0.100.75=0.1333_P = \dfrac{\mu_P - r_f}{\beta_P} = \dfrac{0.10}{0.75} = 0.1333. TreynorM=0.071=0.07_M = \dfrac{0.07}{1} = 0.07. (1) So PP beats market on both here; but in general why divergence occurs: Treynor divides only by systematic risk (β\beta), Sharpe by total risk (σ\sigma). A portfolio with large unsystematic risk has high σ\sigma relative to β\beta, so it can look strong on Treynor (which ignores diversifiable risk) yet weak on Sharpe. Divergence therefore flags poor diversification / high idiosyncratic risk. (2)

(e) For a fully diversified portfolio, σP=βPσM\sigma_P = \beta_P\sigma_M (zero residual). Then SharpeP=μPrfβPσM=1σMμPrfβP=TreynorPσM.\text{Sharpe}_P = \frac{\mu_P-r_f}{\beta_P\sigma_M} = \frac{1}{\sigma_M}\cdot\frac{\mu_P-r_f}{\beta_P} = \frac{\text{Treynor}_P}{\sigma_M}. Since σM>0\sigma_M>0 is a common positive constant, Sharpe and Treynor are proportional across all such portfolios, giving identical rankings. (3)


Question 3

(a) Downside deviation relative to τ\tau: σd=1Ni=1N(min(riτ,0))2.\sigma_d = \sqrt{\frac{1}{N}\sum_{i=1}^N \big(\min(r_i-\tau,\,0)\big)^2}. Sortino =rˉτσd= \dfrac{\bar r - \tau}{\sigma_d}. It differs from Sharpe because Sharpe penalises all volatility (upside and downside) via σ\sigma, whereas Sortino only penalises returns below the target — investors dislike downside, not upside dispersion. (2 def + 2 why = 4)

(b) Mean rˉ=(0.050.02+0.030.06+0.04+0.010.03+0.02)/8=0.04/8=0.005\bar r = (0.05-0.02+0.03-0.06+0.04+0.01-0.03+0.02)/8 = 0.04/8 = 0.005. (1) Shortfalls (negatives only): 0.02,0.06,0.03-0.02, -0.06, -0.03. Squares: 0.0004,0.0036,0.00090.0004, 0.0036, 0.0009; sum =0.0049=0.0049. (2) σd=0.0049/8=0.0006125=0.024749\sigma_d = \sqrt{0.0049/8} = \sqrt{0.0006125} = 0.024749. (2) Sortino =0.005/0.024749=0.2020= 0.005/0.024749 = 0.2020. (1)

(c)

import numpy as np
def sortino(returns, target, periods_per_year):
    r = np.asarray(returns, dtype=float)
    excess_mean = r.mean() - target
    downside = np.minimum(r - target, 0.0)
    dd = np.sqrt(np.mean(downside**2))
    if dd == 0:
        return np.inf
    ann_mean = excess_mean * periods_per_year
    ann_dd = dd * np.sqrt(periods_per_year)
    return ann_mean / ann_dd

(4 — must annualise mean by periods and dd by √periods, and guard dd=0)

(d) If no observation is below target, every min(riτ,0)=0\min(r_i-\tau,0)=0, so ()2=0σd=0\sum(\cdot)^2 = 0 \Rightarrow \sigma_d = 0. The Sortino ratio rˉτ0\frac{\bar r-\tau}{0} is undefined; with positive excess mean it tends to ++\infty. (2) Implication: the metric cannot rank such a strategy against peers with finite downside risk — the ratio saturates at infinity for any strategy that never breaches the target, erasing differences among them. In practice one must either use a longer/finer sample, raise the target, or fall back to Sharpe for comparison. (2)

[
  {"claim":"GMVP weight wA = 0.7358","code":"sA,sB,rho=0.20,0.30,0.20; sAB=rho*sA*sB; wA=(sB**2-sAB)/(sA**2+sB**2-2*sAB); result=abs(float(wA)-0.7358)<0.001"},
  {"claim":"GMVP volatility 0.1806","code":"sA,sB,rho=0.20,0.30,0.20; sAB=rho*sA*sB; wA=(sB**2-sAB)/(sA**2+sB**2-2*sAB); wB=1-wA; var=wA**2*sA**2+wB**2*sB**2+2*wA*wB*sAB; result=abs(float(var**0.5)-0.1806)<0.001"},
  {"claim":"rho=-1 risk-free weight wA=0.60","code":"sA,sB=0.20,0.30; wA=sB/(sA+sB); result=abs(float(wA)-0.60)<1e-9"},
  {"claim":"beta=0.75 and Jensen alpha=0.0475","code":"cov,sM=0.0243,0.18; beta=cov/sM**2; rf,muM,muP=0.04,0.11,0.14; req=rf+beta*(muM-rf); alpha=muP-req; result=abs(float(beta)-0.75)<1e-9 and abs(float(alpha)-0.0475)<1e-9"},
  {"claim":"systematic variance fraction 0.2916","code":"beta,sM,sP=0.75,0.18,0.25; frac=(beta**2*sM**2)/sP**2; result=abs(float(frac)-0.2916)<0.001"},
  {"claim":"downside deviation 0.024749 and Sortino 0.2020","code":"import numpy as np; r=np.array([0.05,-0.02,0.03,-0.06,0.04,0.01,-0.03,0.02]); dd=float(np.sqrt(np.mean(np.minimum(r,0)**2))); s=float(r.mean()/dd); result=abs(dd-0.024749)<1e-4 and abs(s-0.2020)<1e-3"}
]