Skip to content

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 risk

Core 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

  1. 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.
  2. Negative weights possible — the plain iteration does not enforce w ≥ 0; negatively-dominated inputs go long-short; production callers must detect it.
  3. Weak convergence guarantees — ill-conditioned Σ (condition number > 1e6) may not converge in 500 iterations; no diagnostics output.
  4. Rounding: weights / vol round(6), RC% round(2).
  5. 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-identical
  • equal_risk_contribution_achieved — semantic pin: each RC ≈ 100/N ± 0.05pp
  • weights_sum_to_one — normalization contract
  • rejects_single_asset — N<2 → error payload
  • target_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)

Verifiable intelligence for the decisions that demand scrutiny.