Mean Reversion and Statistical Arbitrage › Testing for Mean Reversion

Michael BrenndoerferDecember 27, 202511 min read
Quantitative FinanceAll chapters
Part 11 of 15Quantitative Trading Strategies
Chapter 60Mean Reversion and Statistical Arbitrage › Testing for Mean Reversion
Reading section 3 of 12 · Testing for Mean Reversion · 11 minSection 3 of 12 · 11 min

Book contents

Section 3 of 12 · 11 min read

Mean Reversion and Statistical Arbitrage › Testing for Mean ReversionOne section · Sections in this chapter3 / 12 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Before trading a mean reversion strategy, you must verify that mean reversion exists in your target series. This verification step is essential. A random walk has no mean reversion: past deviations provide no information about future movements. Trading mean reversion on a random walk is a losing proposition because you are betting on convergence that has no statistical tendency to occur.

The distinction between a mean-reverting process and a random walk can be easy to miss. Both exhibit random fluctuations, and both can appear to drift away from their starting point over short horizons. The difference lies in long-term behavior: a mean-reverting process has a "gravitational center" that pulls it back toward equilibrium, while a random walk has no such anchor and can drift arbitrarily far from any reference point.

The Ornstein-Uhlenbeck Process

The canonical model for a mean-reverting process is the Ornstein-Uhlenbeck (OU) process. This stochastic differential equation captures the essential dynamics of mean reversion in continuous time, and gives a mathematically tractable framework for analysis and parameter estimation. The OU process is defined by:

dXt=κ(μ−Xt)dt+σdWtdX_t = \kappa(\mu - X_t)dt + \sigma dW_t

where:

  • dXtdX_t: change in the process value
  • XtX_t: value of the process at time tt
  • κ\kappa: speed of mean reversion (higher values mean faster reversion)
  • μ\mu: long-run mean level
  • dtdt: small time increment
  • σ\sigma: volatility of the process
  • dWtdW_t: standard Brownian motion increment

The intuition behind this equation becomes clear when we examine its two components. The first term, κ(μ−Xt)dt\kappa(\mu - X_t)dt, represents the deterministic drift that creates mean reversion. When Xt>μX_t > \mu, the quantity (μ−Xt)(\mu - X_t) is negative, making the drift term κ(μ−Xt)\kappa(\mu - X_t) negative, which pushes the process down toward μ\mu. Conversely, when Xt<μX_t < \mu, the drift is positive, pushing the process up toward μ\mu. The further the process deviates from μ\mu, the stronger this restoring force becomes, much like a spring that pulls harder when stretched further.

The parameter κ\kappa controls how quickly this reversion occurs. A high κ\kappa means strong mean reversion, where deviations correct rapidly. A low κ\kappa means weak mean reversion, where the process meanders more before returning to equilibrium. The second term, σdWt\sigma dW_t, represents random shocks that continuously buffet the process, creating the fluctuations around the mean that generate trading opportunities.

The half-life of mean reversion provides a practical measure of how quickly deviations decay. It is the expected time for a deviation to shrink by half:

τ1/2=ln⁡(2)κ\tau_{1/2} = \frac{\ln(2)}{\kappa}

where:

  • τ1/2\tau_{1/2}: expected time for a deviation to decay by 50%
  • κ\kappa: speed of mean reversion

The half-life determines the expected holding period for trades. If the half-life is too long relative to your trading horizon, you may not capture the reversion before other factors dominate. For instance, if a spread has a half-life of six months but you need to close positions within weeks due to margin constraints or reporting requirements, you face significant risk that the spread hasn't reverted by the time you must exit. Conversely, if the half-life is very short, perhaps hours or minutes, the strategy may require high-frequency execution capabilities that introduce additional costs and complexity.

Out[2]:
Visualization
Line plot of OU process with kappa=0.1 showing slow, wide oscillations around mean 100.
OU process with κ=0.1 (half-life ≈ 6.9 periods). Weak mean reversion produces slow, wide oscillations around the long-run mean of 100.
Line plot of OU process with kappa=0.3 showing moderate oscillations around mean 100.
OU process with κ=0.3 (half-life ≈ 2.3 periods). Moderate mean reversion produces more contained oscillations around the mean.
Line plot of OU process with kappa=0.7 showing tight, rapid oscillations around mean 100.
OU process with κ=0.7 (half-life ≈ 1.0 period). Strong mean reversion produces tight, rapid oscillations around the long-run mean.

The Augmented Dickey-Fuller Test

The Augmented Dickey-Fuller (ADF) test is the workhorse for testing whether a time series is stationary (mean-reverting) or contains a unit root (random walk). The test is constructed around a clever regression specification that directly tests for the presence of mean-reverting behavior. The test estimates the regression:

Δyt=α+βt+γyt−1+∑i=1pδiΔyt−i+εt\Delta y_t = \alpha + \beta t + \gamma y_{t-1} + \sum_{i=1}^{p} \delta_i \Delta y_{t-i} + \varepsilon_t

where:

  • Δyt\Delta y_t: change in the series value at time tt
  • α\alpha: drift constant
  • β\beta: coefficient on the time trend tt
  • γ\gamma: coefficient testing for mean reversion (unit root)
  • δi\delta_i: coefficients on lagged changes capturing serial correlation
  • pp: number of lag terms
  • εt\varepsilon_t: error term

The key parameter is γ\gamma, which determines the long-run dynamics of the series. The null hypothesis is that γ=0\gamma = 0, indicating a unit root: the lagged level yt−1y_{t-1} has no power to predict the current change Δyt\Delta y_t. Under this null, the series follows a random walk and exhibits no mean reversion.

The alternative hypothesis is γ<0\gamma < 0, indicating mean reversion. The intuition here is subtle but important. A negative coefficient on the lagged level means that when the series is high (large yt−1y_{t-1}), the expected change is negative (pushing the series down). When the series is low (small yt−1y_{t-1}), the expected change is positive (pushing the series up). This is precisely the behavior we want: a restoring force that pulls the series back toward its long-run trend.

The lagged changes Δyt−i\Delta y_{t-i} are included to absorb any serial correlation in the data, so the test statistic has the correct distribution. A more negative test statistic provides stronger evidence against the null, indicating more convincing mean reversion.

In[3]:
Code
import numpy as np
from statsmodels.tsa.stattools import adfuller

np.random.seed(42)

# Generate a mean-reverting series (OU process)
n = 500
kappa = 0.5  # Mean reversion speed
mu = 100  # Long-run mean
sigma = 2  # Volatility
dt = 1

ou_series = np.zeros(n)
ou_series[0] = mu
for t in range(1, n):
    ou_series[t] = (
        ou_series[t - 1]
        + kappa * (mu - ou_series[t - 1]) * dt
        + sigma * np.sqrt(dt) * np.random.randn()
    )

# Generate a random walk for comparison
random_walk = np.cumsum(np.random.randn(n)) + 100

# Run ADF tests
adf_ou = adfuller(ou_series, maxlag=10, autolag="AIC")
adf_rw = adfuller(random_walk, maxlag=10, autolag="AIC")
Out[4]:
Console
ADF Test Results
==================================================

Mean-Reverting Series (OU Process):
  Test Statistic: -13.0600
  p-value: 0.0000
  Critical Values: 1%: -3.444, 5%: -2.867

Random Walk:
  Test Statistic: -0.3119
  p-value: 0.9238
  Critical Values: 1%: -3.444, 5%: -2.867

The OU process shows a highly negative test statistic well below the critical values, leading us to reject the null hypothesis of a unit root. The random walk, by contrast, has a test statistic close to zero, and we cannot reject the null. This distinction is fundamental: the OU process is suitable for mean reversion trading, while the random walk is not.

Out[5]:
Visualization
Line chart of mean-reverting OU process oscillating around mean 100.
Ornstein-Uhlenbeck process oscillating around its long-run mean of 100. The restoring force prevents indefinite drift.
Line chart of a random walk drifting away from its starting value.
Random walk starting near 100 but drifting without bound. No restoring force acts on the series.

Estimating Mean Reversion Parameters

Once you've established that a series is mean-reverting, you need to estimate the parameters κ\kappa, μ\mu, and σ\sigma to design trading rules. These parameters have direct practical implications: μ\mu determines the target level for convergence trades, κ\kappa determines how long you should expect to hold positions, and σ\sigma determines the typical magnitude of fluctuations and hence appropriate position sizing.

The discrete-time analog of the OU process sets up parameter estimation:

Xt−Xt−1=κ(μ−Xt−1)Δt+σΔtεtX_t - X_{t-1} = \kappa(\mu - X_{t-1})\Delta t + \sigma\sqrt{\Delta t}\varepsilon_t

where:

  • XtX_t: value of the process at time tt
  • κ\kappa: speed of mean reversion
  • μ\mu: long-run mean
  • Δt\Delta t: time step size
  • σ\sigma: volatility parameter
  • εt\varepsilon_t: standard normal random variable

This equation shows that the change in the process depends on how far the current value is from the long-run mean, scaled by the mean reversion speed and time step, plus a random shock. Rearranging terms allows us to formulate a linear regression that can be estimated using standard OLS techniques. We begin by expanding the drift term and regrouping:

Xt=Xt−1+κμΔt−κXt−1Δt+σΔtεt(expand drift term)=κμΔt+(1−κΔt)Xt−1+σΔtεt(group terms by Xt−1)\begin{aligned} X_t &= X_{t-1} + \kappa\mu\Delta t - \kappa X_{t-1}\Delta t + \sigma\sqrt{\Delta t}\varepsilon_t && \text{(expand drift term)} \\ &= \kappa\mu\Delta t + (1 - \kappa\Delta t)X_{t-1} + \sigma\sqrt{\Delta t}\varepsilon_t && \text{(group terms by } X_{t-1} \text{)} \end{aligned}

This algebraic manipulation reveals that the OU process, when discretized, takes the form of a simple autoregressive model. The current value depends linearly on the previous value plus a constant and noise. This matches the form of a simple linear regression:

Xt=a+bXt−1+ηtX_t = a + bX_{t-1} + \eta_t

where:

  • a=κμΔta = \kappa\mu\Delta t: regression intercept
  • b=1−κΔtb = 1 - \kappa\Delta t: regression slope
  • ηt=σΔtεt\eta_t = \sigma\sqrt{\Delta t}\varepsilon_t: regression residual with variance σ2Δt\sigma^2\Delta t

The power of this formulation is that simple OLS regression yields estimates of aa and bb, from which you can recover the underlying OU parameters. Specifically, solving for κ\kappa from the slope coefficient gives κ=(1−b)/Δt\kappa = (1-b)/\Delta t, and substituting into the intercept equation gives μ=a/(κΔt)\mu = a/(\kappa \Delta t). The volatility parameter can be estimated from the standard deviation of the residuals.

In[6]:
Code
from scipy import stats


def estimate_ou_parameters(series, dt=1):
    """Estimate OU process parameters from time series data."""
    X_t = series[1:]
    X_t_1 = series[:-1]

    # OLS regression: X_t = a + b * X_{t-1}
    slope, intercept, r_value, p_value, std_err = stats.linregress(X_t_1, X_t)

    # Extract OU parameters
    b = slope
    a = intercept

    kappa = (1 - b) / dt
    mu = a / (kappa * dt)

    # Estimate sigma from residuals
    residuals = X_t - (a + b * X_t_1)
    sigma = np.std(residuals) / np.sqrt(dt)

    # Calculate half-life
    half_life = np.log(2) / kappa if kappa > 0 else np.inf

    return {
        "kappa": kappa,
        "mu": mu,
        "sigma": sigma,
        "half_life": half_life,
        "r_squared": r_value**2,
    }


ou_params = estimate_ou_parameters(ou_series)
Out[7]:
Console
Estimated OU Parameters
========================================
Mean reversion speed (κ): 0.5120
Long-run mean (μ): 100.04
Volatility (σ): 1.9584
Half-life: 1.35 periods
R-squared: 0.2377

True parameters: κ=0.50, μ=100.00, σ=2.00

The estimated parameters closely match the true values used to generate the series, validating our estimation procedure. The half-life of approximately 1.4 periods tells us that deviations from the mean shrink by half in about 1-2 time steps, indicating quite fast mean reversion.