Trading Dev AcademyFree quant education

Free lesson · Quant strategy development

05 / Mean reversion and relative value

Open interactive lessonPractice calculationsExplore labs

Start with the idea

Mean reversion is an economic and statistical hypothesis that a deviation will tend to shrink. A normalised residual describes how unusual the current deviation is under a fitted model; it does not measure the probability of a profitable exit.

Symbols, units & horizon
  • P_A,ₜ and P_B,ₜ: positive prices of assets A and B
  • β: fitted log-price hedge coefficient
  • sₜ: log spread, distinct from a signal score elsewhere
  • μ̂,σ̂: historical spread mean and SD
  • zₜ: standardised spread
  • μ: equilibrium spread
  • φ: positive AR decay coefficient below 1
  • εₜ₊₁: mean-zero innovation
  • h: horizon in periods
  • h₁/₂: shock half-life
  • Δŝ: forecast spread change, not currency P&L

When and why to use this

Use spread models for related assets where costs, borrow and the relationship itself can be justified. Compare expected convergence time with carrying and execution costs.

st=ln⁡PA,t−βln⁡PB,t,zt=st−μ^tσ^t
Algebra and arithmetic

Construct a log spread and score it

  1. Use ln⁡PA−βln⁡PB=ln⁡(PAPBβ). Subtract the fitted spread mean and divide by its positive SD.
  2. For small changes, ds≈dPAPA−βdPBPB. Thus a log-spread exposure corresponds locally to dollar exposure ratios 1:−β, not share quantities 1:−β.
Work it by hand

Pₐ=110,Pᵦ=100,β=1 gives spread ln1.1=.09531. With mean .07531 and SD .01, z=2.

st+1−μ=ϕ(st−μ)+εt+1,h12=ln⁡(12)ln⁡ϕ,0<ϕ<1
Algebra and arithmetic

Solve reversion speed from repeated decay

  1. Iterating the centred AR(1) gives a conditional deviation ϕh(st−μ). With 0<φ<1, half-life solves φʰ=.5.
  2. Take logarithms and divide: h=ln⁡(.5)ln⁡ϕ. Conversely a chosen half-life implies ϕ=2−1h.
Work it by hand

φ=.8 implies 3.106 periods. A four-period half-life implies φ≈.840896.

The spread is a statistical residual, not a guaranteed tradable portfolio. For log-price spreads, β is a relative sensitivity; convert it into dollar notionals and share quantities at current prices. Half-life is a model estimate in observation periods. Structural breaks, stale quotes, or borrow constraints can dominate its value.

A common research design enters at an outer z-score threshold and exits at a smaller threshold. The gap introduces hysteresis and may reduce rapid re-entry. Test time stops, relationship-break exits, financing costs, and delayed fills within the same frozen strategy. Threshold tuning is still multiple testing.

Δs^t:h=(μ^−st)(1−ϕ^h)
Algebra and arithmetic

Calculate expected spread convergence

  1. The h-step expected level is μ+ϕh(st−μ). Subtract today’s sₜ.
  2. Collect terms: (μ−st)(1−ϕh). A short spread gains from a negative change, after translating the spread into position P&L.
Work it by hand

sₜ=5,μ=3,φ=.8,h=2 gives (3−5)(1−.64)=−.72; a correctly defined short spread unit has expected gross gain .72.

Under the fitted AR(1), this is the expected spread change over h steps. Turn it into a dollar forecast using actual hedge quantities, then subtract both legs’ execution costs, borrow and funding. A z-score of 2 is neither a 95% probability of reversal nor a guaranteed profit.

  • Economic link: shared business exposure, related claims, a cash-and-derivative relationship, or a defensible pricing identity.
  • Hedge stability: estimate β on prior observations and inspect how sensitive trades are to estimation error.
  • Statistical checks: residual stationarity with appropriate critical values, changing variance, half-life uncertainty, and out-of-sample decay.
  • Implementation: asynchronous prices, both-leg fills, short availability, and the cost of unwinding an incomplete hedge.

Python implementation

Self-contained teaching example. Python 3.10+; dependencies and input conventions are shown in the code and notation. Run in your own Python environment.

from math import log

def log_spread(pa, pb, beta, training_mean, training_sd):
    if min(pa,pb,training_sd) <= 0:
        raise ValueError("Positive prices and training SD required")
    spread = log(pa)-beta*log(pb)
    return spread, (spread-training_mean)/training_sd

def mean_reversion(current_spread, equilibrium, phi, horizon):
    if not 0 < phi < 1 or horizon < 0:
        raise ValueError("Require 0 < phi < 1 and horizon >= 0")
    return log(.5)/log(phi), (equilibrium-current_spread)*(1-phi**horizon)

print(mean_reversion(2, 0, .8, 3))

Continue learning

Quant Strategy Development — all lessons
  1. 01 / Start with a source of return
  2. 02 / The variables that actually enter the decision
  3. 03 / Test predictive information before a complex model
  4. 04 / Momentum and trend: information that persists
  5. 05 / Mean reversion and relative value
  6. 06 / Carry, events, and liquidity provision
  7. 07 / Convert a forecast into a trade decision
  8. 08 / Build a bot that preserves the experiment
  9. 09 / Decide whether the edge is real enough to continue

Quantitative finance and development glossary · Python resources and libraries · Research sources and limitations