Lesson 5.2: Mean reversion and pairs trading
Learn mean reversion: z-score entries, the Ornstein-Uhlenbeck model and half-life, pairs trading, and why a high win rate can hide rare, large losses.
By the end of this lesson you will be able to describe the mean-reverting model that sits behind pairs trading and compute its half-life and its normal range, build a z-score entry and exit rule using only past data, work out the reward, the risk and the break-even win rate of a trade, explain why mean reversion wins often and loses rarely and big, and design the stops and checks that protect against a relationship that breaks. You will show that a spread with a daily reversion coefficient of 0.9 has a half-life of 6.6 days and a normal range of 2.29 units, that the same rule has a Sharpe ratio of 1.78 and a 99 per cent win rate while the relationship holds, and a Sharpe ratio of 0.55 with an average loss of 16.7 against an average win of 4.4 when it breaks, and that a trade that risks 3.3 to make 2.7 needs to win 55 per cent of the time to break even. You should have read Lessons 2.3, 2.4, 4.2 and 5.1. The mathematics is standard deviations, a logarithm and a ratio. This course is education about how markets and research work, not investment advice.
Trend following bets that moves continue. Mean reversion bets the opposite: that when something has moved far from its normal level, it will come back. The two are not contradictory, since they work on different horizons and in different instruments. Momentum tends to show up over months. Reversal tends to show up over days and weeks, and in spreads between related assets. A trader needs to know both, and to know their different personalities, because mean reversion feels pleasant until the day it does not.
The idea and where it comes from
If the price of an asset, or the gap between two related assets, fluctuates around a stable level, then an unusually high value is likely to be followed by a fall and an unusually low value by a rise. Sources of reversion include:
Liquidity provision. A large seller pushes the price down temporarily. Someone who steps in to buy is paid for supplying liquidity, as the price drifts back.
Overreaction. News is over-weighted at first, and the price returns part of the way.
Economic links. Two companies in the same business, or a stock and its futures, are tied by arbitrage and by common drivers, so that their price gap cannot wander far, as in the cointegration of Lesson 2.3.
Inventory pressure. Market makers who build up a position need to lay it off, which pushes prices back.
A mean-reverting series is stationary in the sense of Lesson 2.4. A raw stock price usually is not, which is why mean reversion is mostly applied to spreads, residuals or ratios between related assets, and to very short-term moves.
The model: the Ornstein–Uhlenbeck process
The standard continuous-time model of a series that reverts to a level is the Ornstein–Uhlenbeck process: the change in X over a short time is a pull towards the mean μ at a speed θ, plus a random shock.
change in X = θ × (μ − X) × (time step) + σ × (random shock)
The larger θ, the faster the pull. Three results follow, and they match the discrete AR(1) model of Lesson 2.4.
Half-life: the time for the gap to the mean to halve is ln 2 ÷ θ.
Normal range: the long-run standard deviation of X is σ ÷ √(2θ), so a bigger shock or a slower pull gives a wider range.
Link to AR(1): over one day, the autoregressive coefficient is φ = e^(−θ), so θ = −ln φ.
Worked example 1. A spread has a daily coefficient φ = 0.9 and unit shocks. Then θ = −ln 0.9 = 0.105 a day, and the half-life is 0.693 ÷ 0.105 = 6.6 days, the same number as in Lessons 2.3 and 2.4. The long-run standard deviation is 1 ÷ √(1 − 0.9²) = 2.29 units. So the spread usually stays within about ±4.6 units, two standard deviations, of its mean, and each time it strays beyond that, half the excess disappears in about a week.
A trading rule
The simplest rule uses the z-score, the distance of the spread from its recent mean measured in standard deviations:
z = (spread − rolling mean) ÷ rolling standard deviation
Enter when |z| exceeds a threshold, such as 2: sell the spread if z is above it and buy the spread if z is below it.
Exit when z returns to zero, taking profit as the spread comes back to its mean.
The mean and standard deviation use only past data, for example the last 250 days, as the pipeline of Lesson 3.2 requires. A z-score computed with the whole sample leaks the future.
The arithmetic of a trade
Measure everything in the spread's own units. Suppose its standard deviation is 1.5 units, you enter at z = 2 and exit at z = 0, and a round trip costs 0.3 units.
Gain if the spread returns to its mean: 2 × 1.5 − 0.3 = 2.7 units.
Loss if you set a stop at z = 4, two further standard deviations against you: (4 − 2) × 1.5 + 0.3 = 3.3 units.
Break-even win rate: the proportion of winning trades needed for zero profit is loss ÷ (gain + loss) = 3.3 ÷ 6.0 = 55 per cent.
The same logic as Lesson 2.1 holds: what counts is the win rate together with the sizes of the win and the loss. A trade that risks 3.3 to make 2.7 is a good trade only if it wins more than 55 per cent of the time. A mean-reverting spread usually does win more often than that, but how much more depends on whether the relationship is stable.
Mean reversion wins often and loses big, rarely
This arithmetic shows the personality of the strategy. When the relationship holds, a trade is very likely to win, because the spread really does come back. A stop is rarely hit. The profit per trade is small and steady. But when the relationship breaks, the spread does not come back. It carries on moving away, and the trade, which was designed to be held until the spread reverted, goes deeply against you.
We simulated this. The spread follows an autoregressive process with a coefficient of 0.9 and unit shocks, so the long-run standard deviation is 2.29 and the half-life 6.6 days. The rule enters when the z-score, measured against the previous 250 days, passes 2 and exits when it returns to zero, with a round-trip cost of 0.3 units. We ran 100 ten-year histories for three cases and averaged. In the break cases the relationship fails on a random day between years four and seven, after which the spread drifts away as a random walk with an upward trend.
Case · Sharpe ratio · Win rate · Average win (units) · Average loss (units) · Worst trade (units)Relationship holds · 1.78 · 99% · 4.24 · 0.14 · +0.7
Relationship breaks, no stop · 0.55 · 89% · 4.44 · 16.74 · −22.8
Relationship breaks, stop after a 5-unit loss · 0.76 · 78% · 4.64 · 5.54 · −7.2
While the relationship holds, the rule wins 99 per cent of its trades, and the average win of 4.24 is close to the entry distance of 2 × 2.29 = 4.58 less the 0.3 cost, as the arithmetic says. Then comes the break. With no stop, the win rate is still 89 per cent, a number that looks reassuring, but the average loss is 16.74 against an average win of 4.44, nearly four times the size, and the worst trade loses 22.8, five times the typical win. The Sharpe ratio falls from 1.78 to 0.55. A stop that cuts any trade 5 units against you, followed by a 60-day pause, limits the average loss to 5.54 and the worst to 7.2, and raises the Sharpe ratio to 0.76, at the price of a lower win rate of 78 per cent because some stopped trades would have come back.
This is the same shape as selling insurance in Lesson 4.2: a steady stream of small gains and an occasional large loss. The Sharpe ratio and the win rate of a mean-reversion strategy tend to look better in a backtest than in the live record, because the backtest period may not contain a break, and a break may be a rare event that is yet to happen. As the saying goes, mean reversion is picking up pennies in front of a steamroller. The remedy is not to avoid it, but to size it and protect it with care.
Pairs trading in practice
Pairs trading is the most familiar form of mean reversion. You find two related assets, estimate the hedge ratio between them (Lesson 2.3), form the spread and trade it with a rule like the one above. The steps are:
1. Choose pairs with an economic link. Two companies in the same industry or a company and its listed subsidiary tie to a common reason for moving together. A pair chosen only because its past prices happened to be correlated is likely to be a coincidence, as the multiple-testing lesson (3.4) warned.
2. Test the spread. Check for cointegration and estimate the half-life. A half-life of a few days to a few weeks is workable. Much shorter, and costs eat the profit. Much longer, and capital is tied up and the relationship may change before it pays.
3. Estimate the hedge ratio on past data only, and re-estimate it from time to time.
4. Trade both legs together, sizing them so the exposure to common moves cancels. In Indian equities, taking a short position in a share for more than a day is usually done through single-stock futures, which are available only for a limited list of shares.
5. Account for costs on two legs, as in Lesson 4.4.
Single-asset reversal
A second form applies the same idea to one asset's own return over a short horizon: stocks that fell over the last week or month tend, on average, to rebound a little, and those that rose to give back a little. Narasimhan Jegadeesh in 1990 and Bruce Lehmann in 1990 documented this for US stocks. It is usually explained as the price of liquidity: the sellers who pushed the price down temporarily paid a premium to get out. The effect is small per trade and turnover is high, so costs matter a great deal, and it works best in a diversified, market-neutral form, which is the subject of Lesson 5.3.
Protecting a mean-reversion strategy
Use a stop. A loss limit, in spread units or as a share of capital, caps the damage of a break. Expect some stopped trades that would have come back.
Use a time stop. If a trade has not closed after about three half-lives, in which time 87.5 per cent of the gap should have closed, treat it as a failed trade. For a half-life of 6.6 days that is 20 days.
Watch the health of the relationship. Re-test cointegration and re-estimate the half-life on a rolling window. If the spread stops looking stationary, or the half-life lengthens a lot, stop trading it.
Diversify across many pairs, so that the break of one is a small part of the book.
Size small and cap the exposure to any one relationship.
Beware the rolling estimate. A rolling mean and standard deviation adapt to a trend, so the z-score may never look extreme enough to trigger a stop. Use a stop in the spread's own units, as in the simulation.
Know the event risks. A merger, a takeover bid, a regulatory change or a business shock can sever the link for good.
The code below simulates the spread, runs the z-score rule with and without a break and a stop, and works out the arithmetic of a trade.
python
import numpy as np
import pandas as pd
from math import sqrt, log
PHI = 0.9
STATIONARYSD = 1 / sqrt(1 - PHI 2)
def makespread(seed, n=2520, breaks=False):
"""An AR(1) spread with mean zero. If the relationship breaks, the spread trends away after a random day."""
rng = np.random.defaultrng(seed)
x = np.zeros(n)
e = rng.normal(0, 1, n)
b = int(rng.integers(1000, 1800)) if breaks else n + 1
for t in range(1, n):
x[t] = PHI x[t - 1] + e[t] if t < b else x[t - 1] + 0.03 + e[t]
return x
def backtest(x, entry=2.0, stopunits=None, cost=0.3, window=250):
s = pd.Series(x)
mean = s.shift(1).rolling(window).mean() # only past data
sd = s.shift(1).rolling(window).std(ddof=0)
z = ((s.shift(1) - mean) / sd).fillna(0).values
n = len(x)
pos, entryt, cooldown = 0, 0, 0
pnl, trades = np.zeros(n), []
for t in range(window, n):
pnl[t] += pos (x[t] - x[t - 1]) # the open position earns the spread's change
if pos == 0 and t >= cooldown:
if z[t] > entry:
pos, entryt = -1, t; pnl[t] -= cost / 2 # spread too high: sell it
elif z[t] < -entry:
pos, entryt = 1, t; pnl[t] -= cost / 2 # spread too low: buy it
elif pos != 0:
backtomean = (pos == -1 and z[t] <= 0) or (pos == 1 and z[t] >= 0)
adverse = pos (x[t - 1] - x[entryt - 1]) # profit so far, in spread units
stopped = stopunits is not None and adverse <= -stopunits
if backtomean or stopped:
pnl[t] -= cost / 2
trades.append(pnl[entryt:t + 1].sum())
pos = 0
if stopped and not backtomean:
cooldown = t + 60 # stay out for 60 days after a stop
if pos != 0:
trades.append(pnl[entryt:].sum())
return pnl[window:], np.array(trades)
def sharpeof(pnl):
return pnl.mean() 252 / (pnl.std() sqrt(252)) if pnl.std() > 0 else 0.0
print("stationary sd of the spread", round(STATIONARYSD, 2), "| half-life", round(log(0.5) / log(PHI), 1), "days")
for label, breaks, stop in (("relationship holds", False, None), ("relationship breaks, no stop", True, None),
("relationship breaks, stop at 5 units", True, 5.0)):
sr, win, avgwin, avgloss, worst, peryear = [], [], [], [], [], []
for seed in range(100):
pnl, tr = backtest(makespread(seed, breaks=breaks), stopunits=stop)
sr.append(sharpeof(pnl))
if len(tr) > 3:
win.append((tr > 0).mean())
avgwin.append(tr[tr > 0].mean())
avgloss.append(abs(tr[tr <= 0].mean()) if (tr <= 0).any() else 0)
worst.append(tr.min()); peryear.append(len(tr) / 9)
print(f"{label}: Sharpe {np.mean(sr):.2f} | win rate {np.mean(win):.2f} | average win {np.mean(avgwin):.2f}"
f" | average loss {np.mean(avgloss):.2f} | worst trade {np.mean(worst):.1f} | trades a year {np.mean(peryear):.1f}")
arithmetic of one trade in spread units
sdunits, entryz, exitz, stopz, cost = 1.5, 2.0, 0.0, 4.0, 0.3
gain = (entryz - exitz) sdunits - cost
loss = (stopz - entryz) sdunits + cost
print("gain", gain, "loss", loss, "break-even win rate", round(loss / (gain + loss), 2))
print("share of the gap closed after 3 half-lives:", 1 - 0.5 3, "| time stop for phi 0.9:", round(3 log(0.5) / log(PHI), 1), "days")
Common mistakes
Judging the strategy by its win rate. A 99 per cent win rate with an average loss four times the average win is not safe.
Backtesting through a period with no breaks. The rare event is the one that matters.
Computing the z-score with the whole sample. Use only data available at the time.
Relying on a rolling mean to tell you the trade has failed. It adapts to the drift, so use a stop in spread units.
Trading a spread with no economic link. A correlation found by searching is often a coincidence.
Averaging down. Adding to a losing trade as the spread widens turns a break into a disaster.
Ignoring the cost of two legs and of borrowing the short. The profit per trade is small.
Running too few pairs. One break should be a small part of the book.
Confusing fast reversal with momentum's opposite on every horizon. Reversion in days and trends over months can both hold.
Key takeaways
Mean reversion bets that a spread or a short-term move returns to its normal level. The sources are liquidity provision, overreaction, economic links and inventory pressure.
The Ornstein–Uhlenbeck model has a half-life of ln 2 ÷ θ and a normal range of σ ÷ √(2θ). A daily coefficient of 0.9 gives θ = 0.105, a half-life of 6.6 days and a normal range of 2.29 units.
A z-score rule enters at |z| above 2 and exits at 0, using only past data. A trade with a gain of 2.7 and a stop loss of 3.3 needs to win 55 per cent of the time to break even.
In simulation the rule had a Sharpe ratio of 1.78 and won 99 per cent of trades while the relationship held. When it broke, the win rate was still 89 per cent but the average loss was 16.74 against an average win of 4.44, and the Sharpe ratio fell to 0.55.
A stop in spread units and a 60-day pause cut the average loss to 5.54 and the worst trade to −7.2, and raised the Sharpe ratio to 0.76.
Mean reversion has the shape of selling insurance: small regular wins and rare large losses. Protect it with stops, time stops, monitoring of the relationship, diversification across many pairs and small size.
Pairs trading needs an economic link, a stable cointegrating relationship, a workable half-life, two-leg costs and, in India, shares that can be shorted through futures.
Check yourself
1. A spread has a daily coefficient of 0.95. What are its half-life and a sensible time stop at three half-lives?
Half-life = ln 0.5 ÷ ln 0.95 = 13.5 days. Three half-lives are about 40 days.
2. A trade enters at z = 2.5 and exits at 0. The spread's standard deviation is 2 units and the round-trip cost is 0.4. What is the gain?
2.5 × 2 − 0.4 = 4.6 units.
3. The stop is placed at z = 4.5 for that trade. What is the loss, and what win rate breaks even?
Loss = (4.5 − 2.5) × 2 + 0.4 = 4.4 units. Break-even win rate = 4.4 ÷ (4.6 + 4.4) = 49 per cent.
4. A strategy has a backtest win rate of 95 per cent and a Sharpe ratio of 2.0 over six years with no losing year. Why should you still be cautious?
The history may contain no break of the relationship, and a mean-reversion strategy has rare large losses. Look at the sizes of the worst trades, the number of independent pairs and what would happen in a break.
5. Why can a rolling z-score fail to trigger a stop during a trend that carries the spread away?
The rolling mean and standard deviation adapt to the new level and to the greater spread, so the z-score stays moderate while the position keeps losing. A stop in the spread's own units, or on profit and loss, does not have that weakness.
Try this
Set aside forty-five minutes. Use daily prices for two shares in the same industry, such as two large private banks, for at least five years.
1. Regress one price on the other to find a hedge ratio, form the spread and plot it. Use data from the first half only for the regression.
2. Estimate the half-life from the change in the spread against its previous level, as in Lesson 2.3, and compute the z-score using a 250-day rolling mean and standard deviation of past data.
3. Run the rule: enter at |z| above 2 and exit at 0, with a cost of your choice, for the second half of the data. Report the number of trades, the win rate, the average win and the average loss.
4. Add a stop at 4 units of the spread's standard deviation and a time stop of three half-lives. How do the results change?
5. Use the first simulator with your numbers to find the reward, the risk and the break-even win rate.
6. Look for the worst trade, plot the spread around it and say what happened to the relationship.
7. Write a short note: the pair and why it should be linked, the half-life, the results with and without stops, and what would make you stop trading it.
A good result is a table with the win rate and the average win and loss, a chart of the spread with the entry and exit points, and a clear statement of what the worst trade teaches. The next lesson widens the idea from one pair to hundreds of stocks at once: statistical arbitrage and factor investing.
Read more
Narasimhan Jegadeesh's 1990 paper "Evidence of Predictable Behavior of Security Returns" in the Journal of Finance and Bruce Lehmann's 1990 paper "Fads, Martingales, and Market Efficiency" in the Quarterly Journal of Economics document short-term reversal. Evan Gatev, William Goetzmann and K. Geert Rouwenhorst's 2006 paper "Pairs Trading: Performance of a Relative-Value Arbitrage Rule" tests a simple pairs strategy. Marco Avellaneda and Jeong-Hyun Lee's 2010 paper "Statistical Arbitrage in the US Equities Market" in Quantitative Finance builds on residuals. Ernest Chan's Algorithmic Trading has practical chapters on mean reversion and on the Ornstein–Uhlenbeck model, and Ganapathy Vidyamurthy's Pairs Trading is a practitioner's text.
Tags: Quant Trader Mean reversion Pairs trading Ornstein-Uhlenbeck Half-life