Filter / OverlayRisk: Low

VIX Regime Filter

Cut gross exposure when the VIX spikes — carry and momentum hate risk-off regimes

Risk

Low

Holding Period

Matches the wrapped child strategy

Best For

Risk-on/off cycles where VIX leads currency moves

How it works

Most return-harvesting strategies (carry, trend-momentum, ML direction models) have their worst drawdowns during risk-off episodes — 2008, March 2020, October 2022. These crises all show up in VIX first, spiking past 25-30 before propagating through FX and rates. The VIX filter is a meta-strategy that gates any child signals: full size when VIX < 20, trim to 70% between 20-30, cut to 30% when VIX > 30. Wrapped around carry by default (the most vol-sensitive strategy).

Mathematical Foundation

final_size = original_size · M(VIX_t) where M(v) = 1 if v<20, 0.7 if 20≤v≤30, 0.3 if v>30

Signal Generation Logic

  1. 1Collect signals from all wrapped child strategies (default: Carry Trade)
  2. 2For every signal, look up the latest VIX close on-or-before the signal timestamp (no look-ahead)
  3. 3Map VIX level to a size multiplier: <20 (calm) = 1.0 full size, 20-30 (elevated) = 0.7 trim, >30 (panic) = 0.3 flight-to-safety
  4. 4Rewrite signal.final_size = original · multiplier
  5. 5Relabel signal.strategy = 'vix_filter'
  6. 6If VIX data is missing from `data`, fail OPEN (multiplier = 1.0) and log a warning — safer than silently flat-lining

Parameters Explained

wrapped_strategies

Child strategies whose signals get gated. Default wraps Carry (most vol-sensitive); works well on Momentum too.

Default

[Carry]
low_threshold

VIX level below which we run full size. Calibrated to the long-run VIX average (~19 since 1990).

Default

20
high_threshold

VIX level above which we cut to flight-to-safety size. 30 is the historical threshold for 'significant stress'.

Default

30
size_multiplier_low

Scalar for low-VIX regime. Usually 1.0 = no change.

Default

1
size_multiplier_mid

Scalar for elevated VIX. 0.7 is a moderate trim.

Default

0.7
size_multiplier_high

Scalar for panic VIX. 0.3 leaves meaningful exposure but caps damage.

Default

0.3

When It Works

Strategies whose drawdowns cluster with VIX spikes — carry unwinds, trend reversals, credit-linked trades. Historically VIX leads currency and credit moves by 1-3 days during crises.

When It Fails

Slow-burn drawdowns (think 2018 Q4 grind lower) where VIX only modestly elevates. Also penalizes legitimate high-vol opportunities (breakouts often fire right when VIX is elevated).

Risks & Limitations

  • VIX lag: by the time VIX is at 30, most carry damage is already done; the filter reduces further damage but doesn't undo the first hit
  • False positives: one-off VIX spikes (Feb 2018 VIX-maggeddon) trigger the filter but don't persist — get cut right before bounce-back
  • Data dependency: missing VIX feed → pass-through (see fail-open policy). In prod, wire VIX from Yahoo ^VIX or FRED VIXCLS
  • Not a substitute for proper risk limits; VIX filter reduces size, it doesn't enforce stop-outs

Implementation

Same meta-pattern as risk_parity. Expects VIX OHLCV under data['VIX'] — deployment hooks into Yahoo '^VIX' which we already fetch in live_signals. Dataclasses.replace rewrites the immutable Signal; multiplier is bucketed (not interpolated) to keep the behavior interpretable.

Model parameters

Child Strategy

Default wrapped strategy — most vol-sensitive

Carry

Low Threshold

VIX below this = full size (×1.0)

20

High Threshold

VIX above this = flight-to-safety size (×0.3)

30

Mid Multiplier

Size scale when VIX is between low and high

0.7

Academic background

Academic Basis

Based on Moreira & Muir (2017), 'Volatility-Managed Portfolios', Journal of Finance

Backtest this strategy

Run the exact model on your selected assets and date range. See trade-by-trade performance.

Backtest This