0bps

Learn / Track V / lesson 2 of 5

Mean reversion and the Ornstein–Uhlenbeck process

Betting that stretched prices snap back — the model, the z-score trade, and the risk that "cheap" gets cheaper.

11 min read

Mean reversion is the opposite bet to momentum: when something has moved far from “normal”, expect it to come back. It works on the right objects — spreads, ratios, short-horizon returns — and fails dangerously on the wrong ones.

The Ornstein–Uhlenbeck process

The continuous-time model of a mean-reverting quantity XtX_t is

dXt=θ(μ−Xt) dt+σ dWtdX_t = \theta(\mu - X_t)\,dt + \sigma\,dW_t
  • μ\mu is the long-run mean the process is pulled towards,
  • θ\theta is the speed of reversion,
  • σ\sigma is the noise.

The further XX is from μ\mu, the stronger the pull. Its stationary distribution is normal with variance σ2/(2θ)\sigma^2 / (2\theta), and the half-life of a deviation is

h=ln⁡2θh = \frac{\ln 2}{\theta}

In discrete time this is the AR(1) process from stationarity, with ϕ=e−θ Δt\phi = e^{-\theta\,\Delta t}. You estimate θ\theta by regressing Xt−Xt−1X_t - X_{t-1} on Xt−1X_{t-1}.

The z-score trade

Standardise the deviation:

zt=Xt−μ^tσ^tz_t = \frac{X_t - \hat\mu_t}{\hat\sigma_t}

using a rolling mean and standard deviation. A classic rule: short when z>2z > 2, long when z<−2z < -2, exit when zz crosses 0. Bollinger Bands are this exact rule applied to price, and RSI-oversold entries are a cousin of it — which is why they dominate the mean-reversion section of the vault.

The lookback should match the half-life

A rolling window much shorter than the half-life chases noise; much longer, and the mean it uses is stale. Estimating the half-life first and setting the window around it is one of the simplest ways to make a mean-reversion system less arbitrary.

Where mean reversion is real

  • Spreads between related assets — the basis of pairs trading.
  • Very short horizons — bid–ask bounce and liquidity provision create reversal over minutes to a day.
  • Volatility itself — implied volatility reverts much more reliably than price.
  • Funding rates and basis in crypto perpetuals, pulled back by arbitrageurs (see carry).

Single asset prices over medium horizons are mostly not mean-reverting; they behave closer to random walks with momentum.

The risks

Mean reversion has the negative skew that momentum avoids: many small wins and occasional large losses, when a “deviation” turns out to be a regime change. The spread that was 2σ cheap becomes 5σ cheap because one company is going bankrupt, or a stablecoin is losing its peg.

Controls every mean-reversion system needs
  • A stop in z-score or price, even though it fights the logic of the trade.
  • A time stop: if the trade hasn’t reverted within two or three half-lives, the model is probably wrong.
  • A regime filter: stand aside when volatility spikes or the relationship’s stationarity test fails.
  • Never average down without a hard limit. That is how mean reversion becomes martingale.

Put it to work

Build this idea

A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.

in Claude Code, Cursor, Codex & 4 more
/agenkit build a mean-reversion bot that trades a z-score of price versus its rolling mean, with half-life estimation, a time stop, a volatility circuit-breaker, and paper trading by default
  1. npx agenkit install engineering-kit in your project
  2. Paste the command into your agent and approve each phase
  3. Get tests, backtest, risk controls and a paper-trading switch
esc

Try , , or .

↑↓ move↵ open