Risk Parity
Re-size positions so every asset contributes equal risk — the Bridgewater All Weather playbook
Risk
Low
Holding Period
Matches the wrapped child strategy
Best For
Mixing assets of different vol regimes (FX + commodities + equities)
How it works
An equal-dollar portfolio gives wildly unequal *risk* contributions when asset volatilities differ — the 10% crypto slice ends up dominating daily P&L of a '50/50 stocks and crypto' book. Risk parity scales each position by 1/σ so risk contributions equalize. This is a META-strategy: plug in TSMOM (default), or any other child, and we rewrite its final_size so no single leg swamps the portfolio. Point-in-time EWMA volatility, no look-ahead.
Mathematical Foundation
weight_i = (1 / σ_i) / Σ (1 / σ_j) final_size_i = weight_i · gross_exposureSignal Generation Logic
- 1Collect signals from all wrapped child strategies (default: TSMOM)
- 2Group signals by timestamp — each rebalance batch is normalized independently
- 3For every signal in a batch, look up the underlying asset's EWMA volatility observed at-or-before the signal timestamp (no look-ahead)
- 4Compute inverse-vol weights: w_i = (1/σ_i) / Σ (1/σ_j); pairs/baskets use the first leg as vol proxy
- 5Rewrite signal.final_size = w_i · gross_exposure — so the sum of |final_size| across the batch equals gross_exposure
- 6Relabel signal.strategy = 'risk_parity' for the backtest ledger
Parameters Explained
wrapped_strategiesChild strategies whose signals get re-sized. Default wraps TSMOM; users can substitute Carry, Pair, any subclass of Strategy.
Default
[TSMOM]gross_exposureTotal gross |final_size| per rebalance batch. 1.0 means 'target 100% of capital deployed across all legs combined'.
Default
1vol_halflifeEWMA halflife (bars) for the volatility estimate. Shorter = more responsive to regime change, noisier weights.
Default
30vol_floorMinimum annualized vol used in 1/σ. Prevents ultra-low-vol assets from dominating the weighting.
Default
0.02When It Works
Mixing assets with very different vol regimes — e.g. FX majors (5-8% vol) + commodities (15-25%) + crypto (50-80%). Without risk parity the crypto slice would dominate daily P&L; with it, each asset contributes roughly equally.
When It Fails
When vols change fast (regime shifts), point-in-time vol lags. Also the inverse-vol formula assumes uncorrelated assets — highly correlated legs get over-weighted together. Bridgewater's real All Weather uses correlation-adjusted weights; this MVP doesn't.
Risks & Limitations
- Not a standalone return source — wrapping a bad child strategy with risk parity gives you a bad risk-parity portfolio
- Volatility is a lagging indicator; the weighting underweights assets right after they calm down and overweights right after they blow up
- No correlation adjustment in this MVP — two highly-correlated legs can get nearly double the intended risk
- Vol floor of 2% is arbitrary; tune for your asset set (crypto might want 20%)
Implementation
Meta-pattern identical to HMMRegimeStrategy: collect → reweight → relabel. Uses `dataclasses.replace` to rewrite the immutable Signal tuple. Underlying vol series resolved via _asset_underlying_series which handles direct, PAIR:, and BASKET: labels. Cache-per-asset avoids recomputing EWMA across batches.
Model parameters
Child Strategy
Default wrapped strategy — swap in backtest API
Gross Exposure
Total |final_size| per rebalance batch
Vol Halflife
EWMA halflife for inverse-vol weighting
Vol Floor
Minimum annualized vol — prevents 1/σ blow-up
Academic background
Academic Basis
Based on Qian (2005) 'Risk Parity Portfolios' — and the Bridgewater All Weather implementation framework
Backtest this strategy
Run the exact model on your selected assets and date range. See trade-by-trade performance.
Backtest This →