A spread between cointegrated assets does not wander freely; it is pulled toward a long-run level at a rate proportional to its displacement. The diffusion that captures exactly this behaviour is the Ornstein-Uhlenbeck process, and it is tractable enough that its transition law, stationary law, and discrete-time estimation all follow in closed form.
#The mean-reverting equation
The Ornstein-Uhlenbeck process solves the linear stochastic differential equation
with mean-reversion speed , long-run level , volatility , and a Brownian motion.
The affine drift is globally Lipschitz with linear growth, so Equation (1) has a unique strong solution for every square-integrable initial condition [1].
#Closed form
The solution of Equation (1) is
Apply Ito's formula to with . Since is linear in , and the quadratic-variation term vanishes, so Ito reduces to the product rule ,
after substituting Equation (1) and cancelling the terms. Integrating gives , and multiplying by returns Equation (2).
#Transition and stationary laws
Conditional on , the value is Gaussian with
As grows the law converges to the stationary distribution , which is invariant under Equation (1).
The stochastic integral in Equation (2) is a Wiener integral of a deterministic function, hence Gaussian with zero mean, so the conditional mean is the deterministic part of Equation (2). The Ito isometry gives the variance,
Letting grow, the mean tends to and the variance to ; since the conditional law is Gaussian for every , convergence of its mean and variance gives weak convergence to . The solution is a time-homogeneous Markov process, so the law of given is governed by a transition semigroup , and is the marginal of when . If is drawn from independently of , the summands in Equation (2) are independent Gaussians, so has mean and variance , hence for every . Thus for all , so is invariant.
A deviation from the mean decays in conditional expectation as , so it loses half its size over the half-life
a single scalar summarizing the reversion timescale.
#Exact reduction to an autoregression
Sampled at a fixed spacing , the process obeys the exact recursion
where the are independent and .
Write Equation (2) from time to ,
The deterministic part rearranges to . Each innovation is a Wiener integral of the kernel over an interval of common length , hence Gaussian with mean zero and identical variance by the Ito isometry. The integration intervals are disjoint, so the are independent Wiener integrals; together with the common variance this makes them i.i.d.
Equation Equation (7) is a first-order autoregression. Because the innovations are i.i.d. with constant in (homoskedastic), the conditional log-likelihood is . Although is tied to through , the free volatility lets range over for any fixed , so are variation-independent over . Maximising is therefore unconstrained, and for fixed the maximiser over minimises the residual sum of squares independently of , so it is exactly the ordinary least-squares regression of on (the profile over being the residual variance). The slope estimates ; on the event , which has probability tending to one for a genuinely mean-reverting series, this OLS slope is the constrained maximum-likelihood estimate and and the half-life of Equation (6) follow. (For the unconstrained OLS slope leaves the model's feasible region and is no longer recovered this way.)
#Illustration
Simulating the exact recursion Equation (7), regressing successive samples, and recovering the half-life shows the estimator at work.
import numpy as np
from numpy.random import Generator
def simulate_ou(
kappa: float, theta: float, sigma: float, dt: float, n: int, rng: Generator
) -> np.ndarray:
"""Simulate an Ornstein-Uhlenbeck path by its exact discretization.
Args:
kappa: Mean-reversion speed.
theta: Long-run level.
sigma: Volatility.
dt: Sampling spacing.
n: Number of steps.
rng: Seeded generator for reproducibility.
Returns:
The sampled path of length n + 1. It starts at path[0] = theta, the
stationary mean, and converges to the stationary law N(theta,
sigma^2 / (2 kappa)) after a transient initial segment.
"""
phi = np.exp(-kappa * dt)
innovation_sd = sigma * np.sqrt((1.0 - phi**2) / (2.0 * kappa))
noise = rng.normal(0.0, innovation_sd, size=n)
path = np.empty(n + 1)
path[0] = theta
for k in range(n):
path[k + 1] = theta * (1.0 - phi) + phi * path[k] + noise[k]
return path
def estimate_half_life(path: np.ndarray, dt: float) -> float:
"""Estimate the mean-reversion half-life by least squares on the AR(1) form.
Args:
path: A sampled Ornstein-Uhlenbeck trajectory.
dt: The sampling spacing used to generate the path.
Returns:
The estimated half-life ln(2) / kappa.
"""
lagged = path[:-1]
nextval = path[1:]
design = np.vstack([np.ones_like(lagged), lagged]).T
slope = np.linalg.lstsq(design, nextval, rcond=None)[0][1]
kappa = -np.log(slope) / dt
return float(np.log(2.0) / kappa)
rng = np.random.default_rng(0)
path = simulate_ou(kappa=1.5, theta=0.0, sigma=0.3, dt=1.0 / 252.0, n=50_000, rng=rng)
half_life = estimate_half_life(path, dt=1.0 / 252.0)
The closed form Equation (2), the stationary law of Proposition 3, and the autoregressive reduction Equation (7) give the Ornstein-Uhlenbeck process closed-form transition, stationary, and estimation theory.