Pairs Trading Explained: How It Works in Crypto and Stocks

Pairs trading is the two-asset base case of statistical arbitrage: construct a stationary spread from two cointegrated assets and trade its deviations from equilibrium. The market-neutral framing — long the cheap leg, short the rich leg — is well known. What separates a tradeable pair from a slow bleed is the estimator behind the hedge ratio, the mean-reversion speed of the spread relative to your costs, and a stop that distinguishes a temporary deviation from a structural break. This piece focuses on those mechanics.

The spread, defined properly

The naive ratio price(A)/price(B) is convenient but not stationary in general. The object you actually want stationary is the residual of a cointegrating regression:

spread_t = log P_A(t) - beta * log P_B(t) - mu

where beta is the cointegrating coefficient (the hedge ratio) and mu the long-run mean. If spread_t is stationary, the pair is cointegrated and the spread is bounded; if it isn't, the two prices drift apart and a pairs trade on them loses money no matter how correlated their returns are. Correlation measures co-movement of returns; cointegration measures whether the level of the spread reverts. You trade the second property — see cointegration, stationarity, and why correlation alone misleads.

Modeling reversion: Ornstein–Uhlenbeck

Treating the spread as IID noise and trading its z-score throws away the most useful information: how fast it reverts. Model it as an Ornstein–Uhlenbeck process:

d(spread) = theta * (mu - spread) dt + sigma dW

theta is the reversion speed; the half-life of a deviation is ln(2) / theta. This single number governs everything downstream:

  • Holding period. Expected time to revert is on the order of the half-life.
  • Cost viability. If the half-life is 2 days and round-trip cost is 0.1%, the

reversion can clear costs; at a 20-day half-life it usually can't.

  • Capital efficiency. Longer half-lives tie up capital and accumulate funding

or borrow cost, shrinking the realized Sharpe even when the signal "works."

Estimate theta by fitting an AR(1) to the spread: the AR(1) coefficient phi maps to theta = -ln(phi) per step. A pair whose half-life drifts upward over time is a pair whose edge is decaying — monitor it.

The z-score and threshold choice

z = (spread - rolling_mean) / rolling_std

Entry at |z| > 2, exit toward z ≈ 0, stop at |z| > 3–4 is the standard template, and the logic is statistical: under approximate normality the spread sits beyond ±2σ only ~5% of the time, so |z| > 2 trades genuinely stretched states rather than noise. But the thresholds interact with the half-life and costs. Wider entry thresholds mean fewer, higher-conviction trades with longer expected holds; tighter thresholds raise turnover and cost. The stop is the admission that not every deviation reverts — when cointegration breaks, the stop is what prevents a "temporary" divergence from becoming a permanent loss.

A spread-trading sketch with an honest backtest guard

import numpy as np
import pandas as pd
from statsmodels.tsa.stattools import coint

def hedge_ratio_kalman(a: pd.Series, b: pd.Series, delta=1e-4, r=1e-3):
    """Time-varying hedge ratio via a 1D Kalman filter (random-walk beta).
    More stable than a short rolling OLS, less stale than a long one."""
    beta = np.zeros(len(a))
    p, beta_t = 1.0, 0.0
    q = delta / (1 - delta)
    for t in range(len(a)):
        p_pred = p + q
        err = a.iloc[t] - beta_t * b.iloc[t]
        s = b.iloc[t] ** 2 * p_pred + r
        k = p_pred * b.iloc[t] / s
        beta_t += k * err
        p = (1 - k * b.iloc[t]) * p_pred
        beta[t] = beta_t
    return pd.Series(beta, index=a.index)

def pairs_signal(a, b, lookback=60, entry=2.0, exit=0.5):
    beta = hedge_ratio_kalman(a, b)
    spread = a - beta * b
    z = (spread - spread.rolling(lookback).mean()) / spread.rolling(lookback).std()
    pos = pd.Series(0.0, index=a.index)
    pos[z > entry] = -1.0    # spread rich -> short A, long B
    pos[z < -entry] = 1.0    # spread cheap -> long A, short B
    pos[z.abs() < exit] = 0.0
    return pos.shift(1).fillna(0.0)   # act next bar -> no lookahead

def cointegrated(a, b, threshold=0.05):
    _, p, _ = coint(a, b)             # Engle-Granger
    return p < threshold, p

Two non-negotiables are encoded here: a time-varying hedge ratio (the Kalman filter avoids both the staleness of long-window OLS and the noise-chasing of short-window OLS), and the .shift(1) that prevents acting on a z-score before it is observable. Validate in a realistic backtest with costs, and judge it on the Sharpe ratio and maximum drawdown.

Stocks: borrow, dividends, corporate actions

Classic candidates are near-substitutes — KO/PEP, V/MA, two banks, or a stock vs. its sector ETF. The market-neutrality is mechanical: with dollar-balanced legs, a broad move cancels.

LegPositionMoveP&L
KOLong $10,000−2%−$200
PEPShort $10,000−7%+$700
Net+$500

The market fell and the long lost money, yet the pair made $500 because KO outperformed PEP — the only thing the trade actually bets on. The frictions that decide whether this survives:

  • Borrow cost and recall. The short leg must be financeable; hard-to-borrow

names carry a fee that directly nets against the spread — see short selling mechanics.

  • Dividends and corporate actions. A dividend on the short leg is yours to pay;

a spin-off or buyback can break the cointegrating relationship overnight.

  • *Equal dollar, not equal share sizing.* Share-balancing leaves you net long

or short and reintroduces market exposure.

Crypto: perps, funding, and 24/7 risk

Crypto suits pairs trading — many tokens co-move with BTC yet dislocate, and shorting via perpetuals is trivial. ETH/BTC is the bluest-chip relationship; two L1s (SOL/AVAX) or a token vs. a sector basket are common. The crypto-specific mechanics that dominate the P&L:

  • Funding on both legs. A long-ETH-perp / short-BTC-perp structure pays or

receives funding every interval on both legs. Over a multi-day hold this can exceed the convergence edge — model it explicitly and pull it via CCXT. If the spread's half-life is long and net funding is against you, the trade is negative-carry even when the signal is right.

  • Liquidation risk. Leveraged perp legs can be liquidated in a violent move

before the spread reverts; size with leverage and margin in mind.

  • Unstable cointegration. Token relationships break on narrative shifts; the

half-life and beta drift faster than in equities, so re-estimate often and trust less. Regime detection helps flag the shift.

  • 24/7 tape. Gaps and liquidation cascades hit at any hour; there is no close to

hide behind.

When it really is different

The hardest moment is a position moving against you: z = -2.5, you're in, and it goes to −3, then −4. Every instinct says average down. Sometimes that's correct — deviations widen before reverting. But sometimes the cointegration has genuinely broken: an acquisition, a depeg, a project collapse, and the spread will never revert. Two structural defenses keep this survivable:

  1. A stop in spread/z terms, honored mechanically, so a broken relationship

caps at a known loss instead of an open-ended one.

  1. Per-pair sizing via position sizing & risk management

so that hitting any single stop is an annoyance, not an account event.

A book of many weakly-correlated pairs — the statistical arbitrage generalization — is the real risk control: no single broken spread dominates, and the breadth is what converts a thin per-pair edge into a stable return. A lone pair, however clean it looks in-sample, is a concentrated bet on one relationship holding.

Monitoring relationship health

A pair is not a static object; the cointegrating relationship ages. Two diagnostics belong in any live book and should be recomputed on a rolling basis, not just at selection:

  • Rolling cointegration p-value. Re-run the Engle–Granger (or ADF on the spread)

over a trailing window. A p-value drifting upward through your threshold is an early warning that the relationship is dissolving — reduce size before it fully breaks.

  • Rolling half-life. Re-estimate the OU half-life from a trailing AR(1). A

half-life that is lengthening means reversion is slowing, which both raises your expected hold and erodes the cost-adjusted edge.

def health_check(a, b, window=250):
    """Returns rolling cointegration p-value and OU half-life over a trailing window."""
    import statsmodels.api as sm
    from statsmodels.tsa.stattools import coint, adfuller
    a_w, b_w = a.iloc[-window:], b.iloc[-window:]
    _, p_coint, _ = coint(a_w, b_w)
    beta = sm.OLS(a_w, sm.add_constant(b_w)).fit().params.iloc[1]
    spread = a_w - beta * b_w
    lag = spread.shift(1).dropna()
    delta = spread.diff().dropna()
    phi = sm.OLS(delta, sm.add_constant(lag.loc[delta.index])).fit().params.iloc[1]
    half_life = -np.log(2) / phi if phi < 0 else np.inf
    return {"coint_p": p_coint, "half_life_days": half_life}

A pair whose p-value is rising and whose half-life is lengthening is telling you the same thing twice: retire it. Acting on these diagnostics is the difference between a book that quietly compounds and one that holds a slowly-dying position until the stop catches it.

Costs, crowding, and edge decay

Pairs trading pays fees and crosses spreads on two legs every entry and exit, so turnover discipline is central — see transaction costs and slippage. The most popular, liquid pairs are also the most crowded: their deviations are arbitraged away fastest and their realized edge is thinnest after costs. The durable opportunity tends to be in pairs that require some work to identify and some tolerance for the borrow, funding, or capacity friction that keeps faster capital away. Guard the research itself against overfitting: a pair that screened as cointegrated across thousands of candidates may simply be the luckiest draw, so confirm out-of-sample before risking capital.

Conclusion

Pairs trading compresses two correlated assets into one mean-reverting bet, isolating relative value while hedging the market. The signal is the easy part. The edge lives in the estimator (a stable, time-varying hedge ratio), in matching the spread's half-life to your cost structure, in modeling borrow and funding honestly, and in a stop that respects the possibility that this time the relationship really did break. Get those right across a diversified book and you have the core machinery behind every market-neutral strategy.

For the multi-asset generalization see statistical arbitrage; for the single-asset analogue see mean reversion; and contrast with trend following. Place it in context via what is quantitative trading.

#pairs trading #statistical arbitrage #mean reversion #market neutral #crypto trading #stock trading