What (One-liner)
Solves an NxN covariance matrix for equal-risk-contribution weights (each asset contributes 1/N of risk). Maillard (2010) fixed-point iteration, 500-iteration cap, 1e-10 tolerance. The core block of Bridgewater All Weather.
How to use
Drag risk_parity_v1 onto the Canvas, fill cov_matrix (required, NxN PSD) + optional target_risk. Output is weights + portfolio_vol + risk_contributions_pct.
Typical usage:
# 4-ETF cross-asset basket
cov = numpy_cov(returns_SPY_TLT_GLD_DBC)
result = risk_parity(cov.tolist())
# result.weights sum to 1, each asset contributes ~25% of portfolio riskCore formulas
Start: w = [1/N, 1/N, ..., 1/N]
Iterate (≤500 times, 1e-10 tolerance):
σ_p = sqrt(wᵀ Σ w)
rc_i = w_i × (Σw)_i / σ_p # each asset's risk contribution
target = σ_p / N
w_new_i = w_i × (target / rc_i)
w_new = w_new / sum(w_new) # normalize
stop if max|Δw| < 1e-10
# Goal: all rc_i = σ_p / N (each asset contributes 1/N of risk)Optional target_risk → returns scaled_weights = w × (target / σ_p) (leverage scaling).
Assumptions & applicability
Assumptions: PSD covariance + long-only not enforced + 500 iterations suffice for well-conditioned cases + equal-weight start.
Fits: equity/bond/commodity/gold diversified baskets (positive / low-positive correlation); long-horizon strategic allocation.
Does not fit: negative-correlation hedges (long-short weights emerge), strict long-only (needs QP), singular covariance, the 2-asset zero-correlation degenerate case.
Known limitations
- 2-asset zero-correlation 2-cycle — oscillates between [0.5, 0.5] ↔ [0.69, 0.31]; convergence fails and the 500-iteration cap picks the endpoint. The golden pins current behaviour; a long-only QP variant is future work.
- Negative weights possible — the plain iteration does not enforce
w ≥ 0; negatively-dominated inputs go long-short; production callers must detect it. - Weak convergence guarantees — ill-conditioned Σ (condition number > 1e6) may not converge in 500 iterations; no diagnostics output.
- Rounding: weights / vol round(6), RC% round(2).
- No PSD check — non-PSD input can produce a complex σ_p.
References
Maillard, Roncalli, Teiletche (2010) ERC original + Qian (2006) risk-contribution additivity + Bai, Scheinberg, Tütüncü (2016) QP variant + Roncalli (2013) textbook. Full citations in the frontmatter.
Golden Test
tests/golden/fixtures/tier2/risk_parity/, 1e-12 tolerance byte-equality on a 4-ETF positive-correlation basket (clean convergence within 12 iterations), 7 tests:
matches_reference— comparison against an independent numpy reimplementation (all fields byte-equal)determinism— 5 reruns byte-identicalequal_risk_contribution_achieved— semantic pin: each RC ≈ 100/N ± 0.05ppweights_sum_to_one— normalization contractrejects_single_asset— N<2 → error payloadtarget_risk_scaling— optional target_risk yields scaled_weights = w × (target/σ_p)known_2_cycle_documented— pins the 2-asset zero-correlation oscillation (inverse induction: switching to a damped iteration later trips this test)
Changelog
- 1.0.0 (2026-04-20) — First Active (Tier 2 batch 2, iterative-optimization pilot)

