7.4 — Covariance Shrinkage and Cluster-Based Allocation (Hierarchical Risk Parity)

Chapter 7 · Modern Statistical Learning in Practice

Prof. Xuhu Wan

Section 7.4 · Chapter 7 · Learning Statistics with Python

Covariance Shrinkage and Cluster-Based Allocation (Hierarchical Risk Parity)

Modern Statistical Learning in Practice

Prof. Xuhu Wan

ISOM, HKUST Business School · 2026 Edition

Covariance Shrinkage and Cluster-Based Allocation (Hierarchical Risk Parity)

The minimum-variance portfolio has a closed form, \(w \propto \Sigma^{-1}\mathbf 1\), and everything fragile about it lives in the inverse. You will measure how ill-conditioned a 21-asset sample covariance is, watch its optimal weights swing from one year to the next, shrink the matrix with Ledoit–Wolf, and then build a portfolio that never inverts anything — hierarchical risk parity — before putting all four rules through a nine-year walk-forward.

Twenty-one ETFs, one cash proxy removed

2 515 days, 21 assets from 6.7 % (IEF, 7–10-year Treasuries) to 40 % (USO, oil). SHY is excluded on purpose: a minimum-variance optimiser offered a 1.5 %-vol asset will buy 120 % of it and short everything else — a correct answer to an uninteresting question. The 21 that remain are the risky universe.

How ill-conditioned is one year of daily data?

For 21 correlated ETFs on 251 daily returns, the condition number \(\lambda_{\max}/\lambda_{\min}\) of the sample covariance will be of the order of…

  • 1–10: daily returns are nearly uncorrelated
  • 50–100
  • Thousands — the smallest eigenvalues are almost pure noise
  • Infinite — 21 assets need more than 251 days to invert

Sample: 6 373 in 2018, 5 010 in 2019. Ledoit–Wolf: 415 and 299 — fifteen times better-conditioned — from a shrinkage intensity \(\delta\) of only 0.03. The next slide shows what that does to the weights.

The weights that the inverse produces

Sample min-variance in 2018: 75 % IEF, −29 % TLT, +10 % SPY; a year later −27 % TLT and −22 % SPY — SPY flipped from long to short on nothing but a new year of data. Total weight change 0.99 for the sample, 0.52 for Ledoit–Wolf, whose SPY weight stays near zero. Both under-predict next year’s volatility (1.5 % promised, 2.0 % delivered): the optimiser has found the noise in \(\Sigma\) and bet on it.

Ledoit–Wolf: pull the matrix toward a target

\[\hat\Sigma_{LW} = (1 - \delta)\, S + \delta\, \mu I, \qquad \mu = \frac{\operatorname{tr}(S)}{N}, \quad \delta^\ast = \arg\min_\delta \mathbb E\lVert \hat\Sigma_{LW} - \Sigma \rVert^2.\]

  • \(S\) is unbiased but noisy; \(\mu I\) (every asset at the average variance, zero correlation) is biased but has no estimation error. The optimal \(\delta^\ast\) trades the two — the bias–variance trade-off of §4.3, applied to a matrix.
  • Shrinking toward \(\mu I\) raises the small eigenvalues and lowers the large ones: the condition number falls from thousands to hundreds while the average variance is untouched.
  • sklearn.covariance.LedoitWolf computes \(\delta^\ast\) from the data (Ledoit & Wolf, 2004); \(\delta\) = 0.03 sounds tiny, but it is applied where the matrix is weakest.

Note

Alternatives in the same family: shrinkage toward a constant-correlation target, toward a one-factor (CAPM) covariance, and non-linear shrinkage that adjusts each eigenvalue separately. All exist because \(S^{-1}\) is the problem, not \(S\).

HRP: replace the inverse with a tree

López de Prado (2016): the instability lives in \(\Sigma^{-1}\), so never compute it. Cluster the assets, order them so that neighbours are alike, and split capital down the tree two clusters at a time — estimation error stays local.

Correlation becomes distance, distance becomes a tree

The recipe: never invert \(\Sigma\). Cluster the assets on the correlation distance \(d_{ij} = \sqrt{\tfrac12(1 - \rho_{ij})}\), reorder them so that similar assets sit together, then split the capital top-down, two clusters at a time.

Two assets with \(\rho = 0.5\) — what is their distance \(d\), to 2 dp? And for \(\rho = -1\)?

print(round(np.sqrt(0.5 * (1 - 0.5)), 2), round(np.sqrt(0.5 * (1 + 1)), 2))

0.5 1.0

The tree puts the dollar and the metals first, then the three bond funds, then the defensive sectors, energy, credit and financials, and finally the equity indices with their sector funds. Adjacent assets correlate 0.63 on average against 0.22 in alphabetical order: the correlation matrix is now nearly block-diagonal.

See the blocks

Right-hand panel: a red equity block in the bottom-right, a small bond block, and the blue stripe where bonds meet equities. Recursive bisection will walk down this order and, at every split, give more capital to the half with the lower variance.

Recursive bisection

Start with all assets in tree order and weight 1. Split the list in half; compute each half’s variance as an inverse-variance portfolio; give the left half the share \(\alpha = 1 - v_L / (v_L + v_R)\); recurse into each half.

Sum 1, every weight positive, largest 0.31 (UUP, the dollar — lowest volatility in its cluster), then LQD and IEF at 0.17, gold 0.12. No short, no inverse, no eigenvalue. Estimation error stays local: a noisy correlation between two energy funds changes their split, not the weight of Treasuries.

Nine years walk-forward: which rule wins what?

Each January, estimate on the previous calendar year, hold for the year. Four rules: equal weight, min-variance (sample), min-variance (Ledoit–Wolf), HRP.

Before running: which rule will have the lowest volatility, and which the highest turnover?

  • Lowest vol: HRP; highest turnover: equal weight
  • Lowest vol: min-variance (sample); highest turnover: min-variance (sample)
  • Lowest vol: equal weight; highest turnover: HRP
  • Lowest vol: min-variance (LW); highest turnover: HRP

Reading the table

Equal weight: vol 12.6 %, Sharpe 0.67, drawdown −34.5 %, no trading. Min-variance on the sample matrix: vol 3.2 %, Sharpe 0.82 — but it re-trades 148 % of the book every January and holds a 102 % position. Ledoit–Wolf: vol 3.6 %, Sharpe 1.01, drawdown −7.6 %, turnover 0.70 — the best Sharpe with half the trading. HRP: vol 5.4 %, Sharpe 0.84, drawdown −13.9 %, turnover 0.56, long-only, largest weight 0.51. Sharpe ratios are on raw returns, before costs, over nine years (standard error ≈ 0.33): LW’s edge over the others is suggestive, its lower turnover is certain.

What you discovered

  • One year of daily data on 21 ETFs gives a sample covariance with condition number 6 373; Ledoit–Wolf shrinkage (\(\delta\) = 0.03) cuts it to 415 by lifting the noise eigenvalues.
  • The sample min-variance weights moved by 0.99 from 2018 to 2019 (SPY from +10 % to −22 %); the shrunk ones by 0.52. Both under-predicted next year’s volatility — the optimiser bets on estimation error.
  • HRP: correlation distance → single-linkage tree → quasi-diagonal order (adjacent correlation 0.63 vs 0.22) → recursive bisection. Twenty lines, no inverse, long-only, largest weight 0.31.
  • Walk-forward 2016–2024: Sharpe 0.67 / 0.82 / 1.01 / 0.84 for equal, sample, LW, HRP; turnover 0 / 1.48 / 0.70 / 0.56. Shrinkage buys the same risk reduction with half the trading; HRP buys it with no leverage.

Next: §7.5 — before you can train on a trade, you have to decide what “the trade succeeded” means.