Mean Reversion Trading Explained: Stocks, Crypto and When It Works

Mean reversion trading monetizes the tendency of a stationary series to return to its conditional mean. The operative word is stationary: there is no edge in fading a series that has no fixed mean to revert to. For a professional, mean reversion is therefore a two-part problem — first prove the series (or, more often, a constructed spread) is mean-reverting and estimate its speed, then build an entry/exit rule whose holding period matches that speed. Everything else — RSI, Bollinger bands, "oversold" — is a low-information proxy for the same underlying state and should be treated as a weak feature to be tested, not as edge.

The payoff is the mirror of trend following: negative skew — many small wins, rare large losses — produced by a high hit rate that breaks catastrophically when the "mean" was actually moving. Managing that skew is the whole job.

The right model: Ornstein-Uhlenbeck

The clean continuous-time model for a mean-reverting series is the Ornstein-Uhlenbeck process:

dx_t = theta * (mu - x_t) dt + sigma dW_t

theta is the speed of reversion, mu the long-run mean, sigma the noise. The single most useful derived quantity is the half-life of a deviation:

half_life = ln(2) / theta

If the half-life is 3 days, a strategy that holds for 30 days is mismatched to the dynamics and will sit through noise; if it is 90 days, an intraday entry rule is fighting the process. Estimate it by regressing the change on the level (the discrete AR(1)/OU mapping):

import numpy as np
import statsmodels.api as sm

def ou_half_life(series):
    """Estimate OU mean-reversion speed and half-life from a level series."""
    s = series.dropna()
    lag = s.shift(1).dropna()
    delta = (s - s.shift(1)).dropna()
    lag, delta = lag.align(delta, join="inner")
    beta = sm.OLS(delta, sm.add_constant(lag)).fit().params.iloc[1]
    theta = -beta                       # delta_x = -theta * x + noise
    return np.log(2) / theta if theta > 0 else np.inf

A negative or near-zero theta (positive beta) means no reversion — the series is trending or a random walk, and any mean-reversion rule on it is fitting noise.

Prove stationarity before you trade

Do not assume a mean exists; test for it.

the spread. A raw stock price almost never passes; a well-chosen spread can.

  • Hurst exponent < 0.5 indicates mean-reverting dynamics —

Hurst exponent. H ≈ 0.5 is a random walk (no edge); H > 0.5 is trending (fade it and you bleed).

(Johansen / VECM) rather than correlation — correlated assets can still drift apart forever.

The key structural insight: single asset prices are rarely stationary, but spreads can be. Trading the ETH/BTC ratio rather than ETH outright removes the common crypto-beta and isolates a far more stationary relative series — the same logic behind pairs trading and statistical arbitrage.

Why "oversold" indicators are weak features

RSI, Bollinger bands, and a rolling z-score are monotonic transforms of the same deviation-from-mean state and are roughly 90% correlated with each other. None of them tests whether a mean exists; they assume it. Treat them as candidate features and measure their predictive content with the information coefficient — the correlation between the signal and forward returns — and track its decay:

import pandas as pd

def signal_ic(signal, fwd_ret, by="W"):
    """Rolling information coefficient: predictive correlation of signal vs forward return."""
    df = pd.concat([signal.rename("sig"), fwd_ret.rename("ret")], axis=1).dropna()
    return df.groupby(pd.Grouper(freq=by)).apply(
        lambda g: g["sig"].corr(g["ret"], method="spearman"))

Run this on an RSI-30 signal across a liquid universe and you typically find a small IC that is regime-dependent and has decayed as the rule became widely known. "RSI < 30 = buy" is not edge; it is a crowded, easily-arbitraged threshold whose IC you must verify out-of-sample. The z-score is preferable only because it is explicitly volatility-normalized and maps cleanly to the OU model.

FeatureWhat it really measuresWhy it's weak
Rolling z-scorestd-devs from rolling meanassumes stationarity; window-sensitive
RSI(14)smoothed up/down ratio, boundedstays "oversold" in a trend; low IC
Bollinger touchz-score in disguise (MA ± k·std)identical info to z; lags on vol shifts

A survivable z-score rule with a hard stop

The dangerous failure is "average down forever." A defensible rule exits both toward the mean and on a divergence stop that concedes the thesis is wrong:

import numpy as np
import pandas as pd

def mean_reversion_with_stop(spread, window=20, entry_z=2.0, exit_z=0.5, stop_z=4.0):
    """Trade a (proven-stationary) spread; hard stop when deviation keeps widening."""
    mu = spread.rolling(window).mean()
    sd = spread.rolling(window).std()
    z = (spread - mu) / sd

    pos = np.zeros(len(spread)); cur = 0
    for i in range(1, len(spread)):
        zi = z.iloc[i]
        if cur == 0:
            if zi < -entry_z: cur = 1
            elif zi > entry_z: cur = -1
        elif abs(zi) < exit_z or abs(zi) > stop_z:        # revert OR regime break
            cur = 0
        pos[i] = cur
    return pd.Series(pos, index=spread.index).shift(1).fillna(0)   # lag

stop_z is the line between renting out patience and catching a falling knife: a move to 4σ against you is overwhelmingly a structural break (re-rating, de-pegging, fraud), not noise. Set the rolling window to roughly the estimated half-life — that is the parameter that ties the rule to the dynamics rather than to a backtest sweet spot.

Parameter sensitivity and overfitting

Mean-reversion backtests are the most overfit in the business because the rolling statistics invite look-ahead leakage — computing the z-score with a window that includes the current bar, then trading that bar, manufactures phantom edge. Other sensitivities:

  • Window vs. half-life mismatch silently changes the strategy you are

actually running.

  • Entry/exit thresholds are easy to tune to history; sweep them and you will

always find a 2.1σ that "worked." Validate with walk-forward optimization and discount for the search via deflated Sharpe.

  • Survivorship bias. Backtesting reversion on today's index constituents

excludes the names that mean-reverted to zero — see backtesting biases.

Backtest with realistic costs (Python backtesting): high-frequency reversion is cost-sensitive, and the transaction costs on frequent round-trips quietly erase a thin edge.

Crypto specifics

Short-horizon BTC/ETH and alt spreads revert sharply after liquidation cascades, and extreme funding flags crowded positioning — deeply negative funding means crowded shorts whose squeeze fuels a violent reversion up (good for early longs, lethal for late shorts). Trade the ratio (ETH/BTC) to strip market beta and improve stationarity, and watch that an exchange/protocol break does not turn a "temporary" dislocation into a permanent one.

When it has no edge

  • Trending / non-stationary regimes. Fading a real trend is the canonical way

to lose; gate signals on a regime filter — formally regime detection via HMM, or simply require H < 0.5 / low trend strength.

  • Informed flow. When the "temporary" seller is informed (a forced

deleveraging that precedes more selling), reversion fails. You cannot distinguish this ex-ante, which is why the hard stop exists.

  • Negative-skew blowups. A 70% hit rate breeds oversizing right before the

one name that gaps to zero. This is the central risk; manage it with strict position sizing, CVaR rather than variance, and by tracking your largest losses, not your win rate.

Conclusion

Mean reversion is the business of estimating an OU half-life, proving the spread is stationary, matching holding period to reversion speed, and capping the negative-skew tail with hard stops and small size. RSI, Bollinger bands, and z-scores are interchangeable, low-IC proxies for one deviation state — useful only when their predictive content is verified out-of-sample and their decay monitored. Prefer stationary spreads over raw prices, gate on regime, and respect that the rare large loss — not the frequent small win — determines whether the strategy survives. For the market-neutral extensions, see pairs trading, statistical arbitrage, and the Kalman-filter approach to time-varying hedge ratios.

#mean reversion #oversold overbought #RSI trading #statistical trading #quantitative trading