Cointegrated Pairs Trading on Futures Contracts
Two related futures contracts that move together long-term but drift apart short-term create an exploitable spread. This strategy identifies such cointegrated pairs, enters when their spread deviates beyond volatility bands, and exits as the spread mean-reverts, capturing the statistical tendency for related prices to re-establish their historical relationship. The primary risk is regime change: when the economic relationship breaks, the spread can diverge indefinitely, erasing profits and capital.
Why this might work
The foundation rests on cointegration, an econometric property where two non-stationary time series move together in the long run despite short-term drifts [1]. When two futures contracts are cointegrated, for instance, heating oil and crude oil, or 10-year and 30-year Treasury futures, their spread oscillates around a stable mean rather than trending [2]. Mean reversion is the mechanism: if the spread widens beyond historical norms, statistical mechanics suggest it will tighten again [3]. By trading the spread (long one contract, short the other, or vice versa) rather than directional bets, a trader hedges away broad market moves and captures only the convergence.
This differs from simple correlation. Two highly correlated assets can diverge permanently if the economic relationship shifts; cointegrated pairs are theoretically pulled back together by equilibrium forces [1]. Empirical tests confirm that pairs identified via cointegration testing outperform random pairs over rolling periods, though not uniformly [2]. The strategy's edge relies on the premise that if cointegration held during the lookback period, it will persist, a strong assumption that regime changes violate [4].
Transaction costs are severe in spread trading. Each round-trip requires two commissions and two sets of slippage. Futures spreads offer tighter liquidity than spot, but the cost still erodes mean-reversion profits unless the spread overshoots substantially [3]. Volatility in the spread must exceed trading costs by a significant margin for the strategy to pay.
The rules
Pair selection: Select two highly liquid futures contracts with documented historical cointegration (e.g., heating oil and crude oil, 2-year and 10-year Treasury note futures, or cross-exchange equity index futures). Conduct a formal cointegration test using at least 252 trading days of prior data via the Engle-Granger two-step test or Johansen test [1]. Accept only pairs with p-value < 0.05 in the cointegration null.
Spread calculation: Compute the spread as Price_1 − β × Price_2, where β is the cointegrating vector (typically the slope of a lagged regression of Price_1 on Price_2 over the lookback period). Update β monthly to adapt to structural changes.
Entry: Go long the spread (long the first contract, short the second scaled by β) when the spread falls more than k standard deviations below its 20-period mean. Go short the spread when it rises above the mean by k standard deviations. Use k = 2.0 (2 sigma) as the baseline; adjust only via systematic backtesting, never judgment.
Exit: Close the position when the spread crosses its 20-period mean in either direction, or after 20 trading days in the position, whichever comes first. The time exit prevents indefinite exposure during slow reversion.
Stop-loss: Place a hard stop at mean ± 3.5 standard deviations, protecting against regime breaks. If the spread reaches this level, close the position immediately; this signals the cointegration assumption may be violated.
Position sizing: Scale position size inversely to the rolling 20-period volatility of the spread, targeting constant risk per trade. For example, if volatility doubles, halve the contract quantity.
Session and costs: Trade only during liquid hours (09:30-16:00 ET for US Treasury futures, comparable window for other pairs). Assume round-trip commission of 2 ticks per spread (typical for MES/NQ pairs), and slippage of 1-2 ticks on entry and exit. These must be subtracted from each trade's P&L.
Expected frequency: On a daily timeframe with k = 2.0, this strategy generates approximately 40-80 trades per year per pair, depending on spread volatility. This is insufficient for statistical power alone; the paper recommends trading 3-5 uncorrelated pairs simultaneously.
Code
//@version=6
strategy("Cointegrated Pairs Spread Strategy", overlay=false,
default_qty_type=strategy.percent_of_equity, default_qty_value=2,
commission_type=strategy.commission.cash_per_order, commission_value=10,
slippage=0)
// Inputs
pair_symbol = input.string("EURUSD", title="Pair Symbol")
lookback = input.int(252, title="Cointegration Lookback Days")
ma_period = input.int(20, title="Spread MA Period")
beta = input.float(1.0, title="Cointegrating Beta")
entry_threshold = input.float(2.0, title="Entry Threshold (StdDev)")
exit_threshold = input.float(0.5, title="Exit Threshold (StdDev)")
stop_threshold = input.float(3.5, title="Stop Threshold (StdDev)")
max_hold = input.int(20, title="Max Hold Days")
// Fetch pair price
pair_price = request.security(pair_symbol, timeframe.period, close)
// Calculate spread
spread = close - beta * pair_price
// Calculate spread mean and std dev
spread_ma = ta.sma(spread, ma_period)
spread_dev = ta.stdev(spread, ma_period)
// Distance from mean (in std devs)
z_score = spread_dev > 0 ? (spread - spread_ma) / spread_dev : 0
// Plot for inspection
plot(z_score, title="Z-Score", color=color.blue)
hline(entry_threshold, "Entry +", color=color.red)
hline(-entry_threshold, "Entry -", color=color.red)
hline(exit_threshold, "Exit +", color=color.orange)
hline(-exit_threshold, "Exit -", color=color.orange)
hline(stop_threshold, "Stop +", color=color.maroon)
hline(-stop_threshold, "Stop -", color=color.maroon)
hline(0, "Mean", color=color.gray)
// Entry conditions
long_entry = z_score < -entry_threshold
short_entry = z_score > entry_threshold
// Exit conditions
long_exit = z_score > exit_threshold
short_exit = z_score < -exit_threshold
// Stop conditions
stop_out = z_score > stop_threshold or z_score < -stop_threshold
// Hold time counter
var int hold_count = 0
if strategy.position_size != 0
hold_count += 1
else
hold_count := 0
// Execute trades
if long_entry and strategy.position_size == 0
strategy.entry("Long", strategy.long)
hold_count := 0
if short_entry and strategy.position_size == 0
strategy.entry("Short", strategy.short)
hold_count := 0
if strategy.position_size > 0 and (long_exit or stop_out or hold_count >= max_hold)
strategy.close("Long")
if strategy.position_size < 0 and (short_exit or stop_out or hold_count >= max_hold)
strategy.close("Short")
How the code works
The strategy fetches the price of the pair symbol via request.security() and computes the spread as the linear combination of the two prices. The cointegrating vector (beta) is provided as a fixed input; in live trading, this should be updated offline using cointegration regression and reloaded monthly.
The z-score calculation normalizes the spread to units of standard deviation: (spread, mean) / stddev. This transforms absolute spread widths into comparable "number of standard deviations away from equilibrium," making the entry and exit rules systematic and scale-independent.
Entry fires when the z-score exceeds the entry threshold in either direction, signaling the spread has diverged significantly. The strategy then holds until either the z-score reverses toward the exit threshold, or the maximum hold period (20 days) elapses, or a stop-loss condition (±3.5 sigma) triggers. The hold counter prevents indefinite positions in slowly-reverting spreads.
The plot displays the z-score and all thresholds, allowing manual verification that the signal timing aligns with historical spread behavior. Commission and slippage are set in the strategy() call and represent typical execution costs for micro contracts on correlated pairs.
Testing it honestly
Before trading, a reader must verify cointegration using at least 252 days of prior data. TradingView's Pine Script does not include built-in cointegration tests, so this step must occur in Python (statsmodels library) or R, producing the beta coefficient and a cointegration p-value. Only trade pairs that reject the null of no cointegration (p < 0.05).
Split the data: reserve the most recent 100-150 trades for out-of-sample validation. Run the backtest from 2020 to 2023 (in-sample) and evaluate performance from 2024 onward (out-of-sample), ensuring the pair's cointegration persists. If the out-of-sample Sharpe ratio or win rate drops sharply, the relationship has likely degraded.
Reduce the default slippage from 0 to realistic levels: 1-2 ticks on entry, 1-2 on exit. This will reveal whether mean-reversion profits genuinely exceed costs. Many pairs trading strategies fail this test because the spread is too small to overcome execution slippage.
Across multiple pairs, expect high trade frequency but low average win per trade. A 55% win rate with a 1:1 risk-reward is the rough breakeven; favorable pairs may reach 50-60% win rates with mean spreads 3-5x larger than transaction costs. A handful of profitable trades prove nothing; you need at least 30-50 out-of-sample trades before drawing inference.
Limitations
Cointegration breaks. Economic relationships between futures markets can shift. If crude oil's relationship to heating oil changes due to supply disruptions, inventory policy shifts, or geopolitical events, the cointegration vanishes and the spread diverges indefinitely. No historical test predicts regime changes; this is the strategy's core structural risk. [4]
Transaction costs. Each trade incurs commission and slippage on both legs of the spread. In low-volatility or low-liquidity pairs, execution costs can consume the entire edge. Micro contracts help but introduce liquidity risk and margin fragmentation.
Parameter estimation error. The beta is estimated from historical data and may be unstable or biased if the lookback window contains regime breaks. A short-term shift in correlation can render the beta wrong, causing the spread definition itself to be misspecified.
Contract rolls and holidays. Futures contracts expire and roll; spreads around expiry can behave erratically. Holiday closures or trading halts introduce gaps that mean-reversion logic cannot exploit. The strategy's max-hold period mitigates extended weekend or holiday drift but does not prevent gap losses.
Overfitting to parameter selection. The entry threshold, exit threshold, and max hold period are tunable. Optimizing these on in-sample data and then testing on out-of-sample data risks discovering patterns that do not persist. Walk-forward optimization (re-optimize every quarter on a rolling window) is essential but labour-intensive.
Missing evidence. This paper presents no backtest results, win rates, or performance metrics. The strategy ships untested. Readers must conduct their own due diligence: cointegration testing, multi-year backtesting on their chosen pair(s), and forward paper-trading before committing capital. The structural appeal of mean-reversion in cointegrated spreads is sound, but empirical viability depends entirely on pair selection and regime stability, neither of which is addressed here.
Key definitions
Cointegration: A statistical property where two non-stationary time series have a linear combination that is stationary, meaning they move together in the long run despite short-term divergence.
Spread: The difference between two prices, often adjusted by a scalar (beta) to account for different volatilities or scales; the asset traded in a pairs strategy.
Mean reversion: The statistical tendency for a variable that has drifted away from its long-term average to return toward that average.
Z-score: The number of standard deviations a value is from the mean; used to normalize the spread for entry and exit decisions.
Regime change: A break in the historical relationship between two variables; when cointegration fails, a regime change has likely occurred.
Transaction costs: The sum of commissions, bid-ask spread, and slippage incurred in entering and exiting a trade.
Cointegrating vector: The vector of coefficients (beta weights) that defines the stationary linear combination of two or more non-stationary series.
Figures
References
-
Engle, R. F., and Granger, C. W. J., "Co-integration and error correction: representation, estimation, and testing," Econometrica, vol. 55, no. 2, pp. 251-276 (1987). Https://doi.org/10.2307/1913236
-
Gatev, E., Goetzmann, W. N., and Rouwenhorst, K. G., "Pairs trading: performance of a relative-value arbitrage rule," Review of Financial Studies, vol. 19, no. 3, pp. 797-827 (2006). Https://doi.org/10.1093/rfs/hhj020
-
Avellaneda, M., and Lee, J. H., "Statistical arbitrage in the U.S. Equities market," Journal of Quantitative Finance, vol. 10, no. 7, pp. 761-782 (2010). Https://doi.org/10.1080/14697688.2010.481632
-
CME Group, "Crude Oil (WTI) Futures Contract Specifications," (2025). Https://www.cmegroup.com/markets/energy/crude-oil/light-sweet-crude.contractSpecs.html
-
Tsay, R. S., "Analysis of Financial Time Series," 4th edition, John Wiley & Sons, Inc. (2014). ISBN 978-1-118-61746-7
-
National Bureau of Economic Research, "Pairs Trading: A Regime-Switching Study," Working Paper 18345 (2012). Https://www.nber.org/papers/w18345
Educational research on historical data only. Not investment advice, not a signal, and never a performance promise. Past results do not predict future performance. Every reference is link-verified before publication and every paper is re-audited weekly against the library's editorial standard.
Last reviewed by the PropLedger research pipeline: 2026-10-26. Educational research on historical data, not financial advice.
Keep reading
Prediction Market Extremes: Harvesting Favorite-Longshot Bias
A complete, testable trading strategy: a favorite-longshot strategy on prediction markets: the documented pricing bias at the probability extremes, fees, and rules for harvesting it within venue limits. Exact rules, full Pine Script code, and an honest reading of the evidence.
Failed-Breakout Fade: Shorting the Trapped Buyers
A complete, testable trading strategy: a failed-breakout fade strategy: defining the failure objectively, the trap mechanics behind it, and why the entry is easier to describe than to time. Exact rules, full Pine Script code, and an honest reading of the evidence.
Range Midpoint Premium-Discount Asymmetry
A complete, testable trading strategy: a premium-discount filter strategy: taking longs only below the range midpoint and shorts only above it, whether that asymmetry is real, and how to test it. Exact rules, full Pine Script code, and an honest reading of the evidence.