26 — Covariance Shrinkage and Black-Litterman¶
Free learning pack¶
- MIT OCW Portfolio Theory I–III
reference/concepts/covariance_shrinkage.md,black_litterman.md
Do not search for more material until these are insufficient.
PREDICT¶
Full shrinkage (shrinkage=1.0) toward a diagonal target removes all
off-diagonal covariance. Would that make minimum_variance treat all
assets as if uncorrelated? Is that obviously good or obviously bad?
Formula¶
Sigma_shrunk = shrinkage * Target + (1 - shrinkage) * Sigma_sample
Target = diag(diag(Sigma_sample))
import numpy as np
sample_cov = np.array([
[0.040, 0.018, 0.006],
[0.018, 0.030, 0.010],
[0.006, 0.010, 0.020],
])
# MANUAL FIRST:
# shrink sample_cov toward its diagonal at shrinkage=0.3 and shrinkage=1.0.
# Confirm variances (the diagonal) never change, only off-diagonals shrink.
shrunk_30pct = None
shrunk_full = None
print(shrunk_30pct)
print(shrunk_full)
PREDICT (Black-Litterman)¶
The market-implied prior return for Asset A is 5%. You have a highly confident view that Asset A will return 10%. Should the Black-Litterman posterior for Asset A land exactly at 10%, or somewhere between 5% and 10%? What would make it land closer to one end?
Formula¶
pi = risk_aversion * Sigma @ w_market (the prior)
posterior_cov = [(tau*Sigma)^-1 + P'*Omega^-1*P]^-1
posterior_mean = posterior_cov @ [(tau*Sigma)^-1 @ pi + P'*Omega^-1*Q]
Sigma = np.array([[0.04, 0.01], [0.01, 0.09]])
w_market = np.array([0.6, 0.4])
risk_aversion = 3.0
# MANUAL FIRST (step 1):
# compute the market-implied prior pi = risk_aversion * Sigma @ w_market.
pi = None
print(pi)
P = np.array([[1.0, 0.0]]) # a view purely on asset 1
Q = np.array([0.10]) # asset 1 will return 10%
Omega = np.array([[0.0001]]) # small = high confidence
tau = 0.05
# MANUAL FIRST (step 2):
# using `pi` from above, compute posterior_cov and posterior_mean per the
# formula. Confirm posterior_mean[0] moved toward 0.10 from pi[0], and
# notice whether asset 2's posterior moved at all despite having no
# direct view - and why.
posterior_mean = None
print(posterior_mean)
Experiment¶
Rerun the Black-Litterman step with Omega = [[10.0]] (very low
confidence) instead. Confirm the posterior stays close to pi, not Q.
Reference¶
reference/concepts/covariance_shrinkage.md
reference/concepts/black_litterman.md
Promote¶
Use src/pm/robust.py (shrink_covariance, market_implied_returns,
black_litterman_posterior) only after your own implementation.
Test¶
pytest tests/test_robust.py
ORAL CHECK¶
Explain to a PM why Black-Litterman is generally preferred over feeding
raw historical average returns straight into mean_variance.
Try /tutor portfolio-construction black litterman for an adaptive walkthrough.