Statistical ArbitrageRisk: Low

Kalman Pair

Pair trading with a Kalman filter that learns the hedge ratio as the market shifts

Risk

Low

Holding Period

Days to weeks

Best For

Pairs whose β visibly drifts over time

How it works

The classic OLS pair trade fits a fixed β once and trades the spread forever. But when the true relationship drifts — central bank regime shifts, currency pegs changing, balance-sheet rebalancing — that static β becomes stale and the 'spread' systematically diverges. Kalman pair treats (α, β) as hidden state following a random walk and re-estimates it every bar. The innovation (y − α − β·x) is the tradable spread.

Mathematical Foundation

[α_t, β_t] = [α_{t−1}, β_{t−1}] + w_t, w_t ~ N(0, Q=δ/(1−δ)·I) z = e_t / std_window(e)

Signal Generation Logic

  1. 1For every asset pair, initialize the state [α=0, β=1] with large initial uncertainty (P₀ = 10³·I)
  2. 2At each bar t, run one Kalman update: predict, compute innovation e_t = y_t − α_t − β_t · x_t, update gain, update state
  3. 3Compute a z-score of the innovation series using a 60-bar rolling std — this is the 'normalized spread'
  4. 4Enter long spread when z < −2 (spread is cheap relative to recent innovations)
  5. 5Enter short spread when z > +2
  6. 6Exit when |z| < 0.5 — spread has reverted through the filter's live estimate
  7. 7Skip the first 60 bars (burn-in) so the filter's state has time to converge

Parameters Explained

delta

Kalman process-noise scaling. Larger delta = β adapts faster to regime changes but becomes noisier; Chan's book default is 1e-5. Try 1e-3 for more responsive tracking.

Default

1e-5
v_epsilon

Observation-noise variance. Larger = trust observations less, filter stays closer to its prior. Default is adequate for log-price-scale pairs.

Default

1e-3
entry_z

Absolute z-score threshold to open a position. Same semantics as the static pair_trading strategy.

Default

2
exit_z

Absolute z-score threshold to close. Tighter than entry_z for faster mean-reversion harvest.

Default

0.5
z_window

Rolling window (bars) for computing the innovation std — this is the denominator of the trading z-score.

Default

60
burn_in

Bars skipped at the start so the filter's state converges before signals fire.

Default

60

When It Works

Pairs whose true hedge ratio drifts over time — central bank regime transitions, currency-peg adjustments, balance-sheet rebalancing. Kalman keeps the β fresh where static OLS would become stale.

When It Fails

Pairs without true cointegration — the filter will happily track spurious β paths and generate garbage signals. Also sensitive to δ tuning: too large and the filter chases noise; too small and it's slow. Burn-in period means no signals in the first ~3 months.

Risks & Limitations

  • Parameter sensitivity: δ and v_epsilon require tuning per asset class; default (1e-5 / 1e-3) is a starting point, not a free lunch
  • Spurious cointegration: the filter doesn't reject the pair — it will trade nonsense if you feed it nonsense
  • Same-bar-β issue: asset_label carries the β observed at signal time, but the spread rehedges continuously; a backtest engine that doesn't support time-varying β will approximate performance
  • No automatic re-entry after stop-out — if |z| > stop_z you should manually reset the filter state or wait for a clean signal

Implementation

Plain 2D Kalman filter in pure numpy (no external library) — ~30 lines. State is [alpha, beta]; observation is y_t = H · state + noise with H = [1, x_t]. Random-walk dynamics: state_{t+1} = state_t + N(0, Q). Initial P = 10³·I so the first few observations move freely; the filter then settles down.

Model parameters

Entry Z

|z| threshold to open a pair position

2.0

Exit Z

|z| threshold to close once spread normalizes

0.5

δ (delta)

Process-noise scaling — smaller = slower β adaptation

1e-5

z Window

Rolling window for innovation z-score denominator

60d

Burn-in

Bars skipped at start for filter convergence

60d

Academic background

Academic Basis

Based on Chan (2009) 'Algorithmic Trading: Winning Strategies and Their Rationale', Chapter 3 on Kalman-filter hedge ratio estimation

Backtest this strategy

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

Backtest This