Learn › EAs and automated trading

Pairs Trading and Cointegration: Why Correlation Is Not Enough

Trading the spread between two assets: hedge ratio by regression, z-score, half-life and what happens when the relationship breaks, with costs on both legs.

Advanced 12 min read 21 October 2026

What you will learn
  • Two highly correlated assets can still drift apart forever. You need cointegration, a spread that gets pulled back, before waiting for the spread to return makes sense
  • The hedge ratio comes from regressing one price on the other, then you test whether what is left (the spread) really reverts to its mean, following the Engle–Granger two-step idea
  • The basic rule enters when the spread z-score reaches ±2 and exits at 0, and it needs a stop, because the relationship can break at any time
  • Every trade has two legs, so you pay spread, swap and margin twice. Profit per trade is usually small, so costs take a large share

Pairs trading means trading the gap between two assets that normally move together. When the gap stretches unusually wide, you sell the expensive one and buy the cheap one at the same time, then wait for the gap to close. It belongs to the statistical arbitrage family and is popular for EAs because the rules are purely numerical. This article explains the mechanics step by step: why correlation is not enough, how to find the hedge ratio, the z-score and half-life, and what happens when the relationship breaks. Every number comes from simulated prices we computed with a script, not from a real market.

Where the profit comes from

A pairs trade always has two legs, for example Sell 1 unit of B and Buy β units of A. If the whole market rises or falls, the two legs mostly cancel out. What is left is the profit or loss on the spread, the scaled gap between them.

spread = price B − α − β × price A

If there is a real economic reason tying the two together, the spread swings around its mean: it stretches and gets pulled back. So you are not guessing the market’s direction, you are betting that “the gap will come back”. That is an assumption you have to prove, not something that is always true.

The study most often cited is Gatev, Goetzmann and Rouwenhorst (2006). They paired US stocks whose prices had moved closely together in the past and opened positions when the gap widened beyond two standard deviations, which is where the common ±2 rule comes from.

Correlation is not enough: you need cointegration

In the correlation article we said to measure correlation on bar-by-bar returns, not on price lines. For portfolio risk that is right. For pairs trading the question changes. We are not asking “do the two move together today?” We are asking “once they drift apart, do they come back?”

  • High correlation = they usually move the same way each bar, but small daily differences can add up and carry the two further and further apart, with nothing pulling them back
  • Cointegration = each price can wander randomly, but there is a ratio β that makes the spread revert to its mean. Picture a person walking a dog: both can go anywhere, but the leash keeps them from getting far apart

We built 500 bars of simulated prices. Price A is a random walk. We then built two versions of price B from the same A: the first adds a spread that is pulled back to zero, the second adds a random walk with no pull back.

  1. The bar-by-bar return correlation between A and B is 0.79 for the first and 0.75 for the second, almost the same
  2. But the first spread stays between −2.57 and +2.94 for all 500 bars, while the second goes as far as −10.62
β estimated here (bars 0–249)After that (bars 250–499) Cointegrated: keeps returning to zero · DF t = −5.33 Only correlated: wanders away · DF t = −1.73 −10−505
Simulated prices, not a real market. Both pairs share the same price A. The blue pair adds a spread that is pulled back to zero; the coral pair adds a random walk with no pull back. Their bar-by-bar return correlations are almost the same (0.79 and 0.75), but the spreads behave completely differently.

If you pick pairs by correlation alone, both pass. But nothing guarantees the second pair’s spread will ever come back.

The hedge ratio from regression

The hedge ratio (β) is the number of units of A you hold against 1 unit of B. The basic method is an OLS regression (Ordinary Least Squares, the straight line closest to all the points) of price B on price A.

B = α + β × A + residual

That residual is our spread. Estimate it on one stretch of data (the estimation window), then apply that β to the data that follows. Never compute β from all the data and then test on the same period, because that peeks into the future. More on this in repainting indicators and look-ahead.

Two things to know:

  • β is an estimate. We built the data with a true value of 0.8, but regression on 250 bars gives 0.854. Real data can be off by more
  • Regressing B on A and A on B gives different β values and different test results. Pick one and stay with it

The Engle–Granger two-step test

The idea comes from Engle and Granger (1987). It has two steps:

  1. Regression to find α and β, then compute the spread
  2. Test whether the spread reverts: when the spread is high, does it tend to fall on the next bar? Fit Δspread = b × previous spread. A clearly negative b means there is a pull back. The decision uses the t-stat of b (a Dickey–Fuller test)

A common mistake: the critical value in step 2 is not the one from an ordinary Dickey–Fuller test, because the regression already chose the β that makes the spread look as stable as possible. You need Engle–Granger critical values (MacKinnon’s tables), which for two variables at the 5% level are about −3.34, not the roughly −2.86 of a single-series test. Most statistics libraries have this test with the correct critical values built in.

Results from our example (250-bar estimation window):

  • Cointegrated pair: b = −0.2071, t = −5.33, below −3.34, so it passes
  • Correlated-only pair: t = −1.73, fails

The test can be wrong both ways. We repeated the simulation 1,000 times with the same rules. The cointegrated pair passed 99.9% of the time, but the non-cointegrated pair still passed by chance 4.3% of the time, close to the 5% error the significance level allows. Screen 100 candidate pairs and several fakes will slip through. It is the same problem as in multiple testing and data snooping.

Half-life: how fast the spread comes back

The usual model is the Ornstein–Uhlenbeck process. Put simply: on every bar the spread is pulled back towards its mean by a fixed fraction of the distance, plus random noise. The further away it is, the stronger the pull, like a spring.

The half-life is the number of bars it takes for the average distance to halve. You get it directly from b in step 2:

half-life = −ln 2 ÷ ln(1 + b)

In our example b = −0.2071, so −0.6931 ÷ ln(0.7929) = −0.6931 ÷ (−0.2320) = 3.0 bars. (The true value we built in is 4.3 bars. Across 1,000 simulations the median estimate was 3.7. Estimating from a spread the regression has already fitted tends to show faster reversion than the truth.)

What half-life is for:

  • Choosing a timeframe: a 3-bar half-life on H1 is a few hours, on D1 it is several days, which brings swap with it
  • Setting a time stop: if you have held for several half-lives and the spread still hasn’t come back, its behaviour may have changed (a rule of thumb, not something tested in this article)
  • If the half-life is long compared with your data, say 100 bars out of 250, the test result means very little

The z-score rule: enter at ±2, exit at 0

The z-score says how many SDs (standard deviations) the spread is from its mean:

z = (spread − mean) ÷ SD

The basic rule, with the mean and SD taken from the estimation window only:

  • z ≥ +2 → Sell the spread: Sell 1 unit of B, Buy β units of A
  • z ≤ −2 → Buy the spread: Buy 1 unit of B, Sell β units of A
  • Exit when z returns to 0
  • Stop when |z| ≥ 4, then stop trading the pair until it is re-tested

Worked example, step by step

500 bars of simulated prices: the first 250 for estimation, the last 250 for trading. Cost is 0.04 per unit per leg per round trip (in and out).

  1. Regression gives α = 5.137 and β = 0.8541. The spread mean is ≈ 0 and its SD = 0.7745
  2. On bar 278, price B = 80.383 and price A = 85.021 spread = 80.383 − 5.137 − 0.8541 × 85.021 = 80.383 − 5.137 − 72.616 = 2.630 z = 2.630 ÷ 0.7745 = 3.40 (the bar before, z was 1.79, so it jumped past 2 in one bar)
  3. z ≥ 2, so Sell 1 unit of B at 80.383 and Buy 0.8541 units of A at 85.021
  4. On bar 293 z = −1.04, past 0, so close both legs at B = 75.627 and A = 83.481
  5. Leg B: 80.383 − 75.627 = +4.756 Leg A: 0.8541 × (83.481 − 85.021) = 0.8541 × (−1.540) = −1.315 Total before costs = 4.756 − 1.315 = +3.44
  6. Cost = 0.04 × (1 + 0.8541) = 0.074, net +3.37

Notice that leg A lost money, but leg B made more. The profit came from the gap closing, not from guessing the market’s direction.

Over the whole trading window there were 8 trades, 18.78 before costs, costs of 8 × 0.074 = 0.59, net +18.19 price units per 1 unit of B. All 8 won, because we built this data to be truly cointegrated throughout. Real markets are never this clean.

Price B 5.14 + 0.854 × price A Spread z-score Trading starts → Entry (z reaches ±2) Exit (z back to 0) 708090+20−2
Simulated prices over 500 bars, not a real market. The hedge ratio and the spread mean and SD come from the first 250 bars only and are applied unchanged to the last 250, so nothing peeks into the future.

When the relationship breaks

The link between two assets rests on economic reasons, and those reasons can change (structural change): two central banks start moving rates in opposite directions, the price of one country’s main export swings hard, or one company in a stock pair is taken over. More in market regime change.

We kept every price the same, but from bar 330 we made the spread drift up by 0.06 per bar (the old relationship breaks), and ran the same rules.

  • No stop: the first two trades still win, but the third opens a Sell spread on bar 341 (z = 2.18) and the spread never comes back. By bar 499 z = 12.64. That trade loses −8.17, and equity falls from a peak of +5.25 to −3.08. Interestingly, most of the loss came from leg A falling 8.76 while B did not follow
  • Stop at |z| = 4: the third trade is closed on bar 355, but z jumped to 4.70 in one bar, so it lost −2.03, more than the planned (4 − 2) × 0.7745 = 1.55. Trading then pauses, and the run ends at +3.07
  • In the run where the relationship holds, the same stop is never touched, and the result is still +18.19
Spread starts drifting (bar 330) +18.19Stable +3.07Broken, stop at z ±4 −3.08Broken, no stop −505101520 Bars 250 to 499 · price units per 1 unit of B, after costs
Simulated prices, not a real market. Equity is marked to the close of every bar, open trades included, after a cost of 0.04 per unit per leg. The broken run uses the same prices, but the spread shifts up by 0.06 per bar from bar 330.

Results from 1,000 repeated simulations with the same rules (net after costs, price units per 1 unit of B):

ScenarioAverageLosing runsWorst
Stable, no stop+10.380.3%−0.94
Stable, stop at z ±4+9.152.9%−2.24
Broken, no stop−4.1992.6%−11.46
Broken, stop at z ±4+2.0519.2%−3.45
Never cointegrated−0.5647.6%−33.45

A stop has a cost. While the relationship holds, it cuts some trades that would have come back. When the relationship breaks, it is the only thing that stops one trade from eating all the profit, and nobody knows in advance which phase they are in.

This is all synthetic data where we set the mechanism ourselves. The numbers show the direction of the effect, not what a real market would deliver, and past results do not predict the future.

The last row matters. The pair that was never cointegrated averages close to zero, but some runs lose heavily. Whether the same rule looks good or bad depends on whether the assumption is true, not on the rule itself.

The cost of two legs

Every pairs trade is two trades, so costs come in pairs:

  • Spread twice per round trip. See spread cost per trade
  • Swap on both legs: one side may earn, the other may pay. The net depends on each currency’s interest rate and on the broker. See overnight swap fees
  • Margin on both legs: some accounts charge less margin on offsetting positions, some don’t. Check your account’s contract specification
  • Legging risk: the first leg fills, the price of the second moves before it does, and part of the planned profit is gone

Profit per trade in this strategy is usually small. In our example it averaged 2.35 per trade before costs.

Cost per unit per legCost per tradeTotal for 8 tradesNet
0.040.0740.59+18.19
0.250.463.71+15.07
0.500.937.42+11.37

At 0.50, costs take about 40% of the profit before costs. Set the threshold closer, say ±1, and you trade more often, but each trade makes less and costs take a bigger share.

A forex example: AUDUSD and NZDUSD

AUDUSD and NZDUSD are a common example because the Australian and New Zealand economies are close in geography and trading partners. That does not mean they are cointegrated now. Relationships like this can weaken or disappear when the two countries’ interest rate policies diverge. Test it yourself on recent data.

If you test it:

  1. Use closing prices for exactly the same bars of both pairs, on the same timeframe
  2. Regress AUDUSD on NZDUSD in the estimation window to get β, then test the spread with Engle–Granger
  3. Both pairs are quoted in US dollars, and 1 lot is 100,000 units of the base currency, so profit per price point is the same per lot. The lot ratio can therefore equal β directly: 1 lot of AUDUSD against β lots of NZDUSD. Pairs quoted in different currencies need converting first
  4. Test out of sample or with walk-forward testing, and re-test cointegration regularly

Another route is trading AUDNZD directly, whose price equals AUDUSD ÷ NZDUSD. You pay one spread, but the ratio is locked to equal value, not to the β from regression.

Managing the risk

  • Measure risk on the spread, not on one leg. Stop distance = (stop z − entry z) × SD. Here (4 − 2) × 0.7745 = 1.55 price units per 1 unit of B. Size the trade so a loss there stays within your limit, such as 1%, with the lot size calculator
  • Allow for gaps past the stop. The example above lost 2.03 instead of 1.55. On news days it can be further
  • Count it as one bet. If you hold several pairs that share a currency, for example several with AUD, the risks overlap as explained in the correlation article
  • Re-estimate β and re-test cointegration on a schedule. If it no longer passes, stop trading the pair. Don’t change the thresholds to make it look good

Common mistakes

  • Picking pairs by correlation. A high number does not mean the gap will come back
  • Estimating β and SD on all the data, then backtesting the same period. Results look too good, because the spread was already fitted to look as stable as possible there
  • Using ordinary Dickey–Fuller critical values. Non-cointegrated pairs pass more easily
  • Screening hundreds of pairs and keeping the best without testing them out of sample. Fakes get mixed in
  • No stop because “it has to come back”. A broken relationship is where accounts take the biggest hits, much like averaging down
  • Forgetting the second leg’s costs, counting spread and swap on one leg only
  • Thinking two offsetting legs mean no risk. The risk is still there; it just moves from market direction to the spread. See also hedging a losing trade
Try it with your own numbers

Frequently asked questions

Are AUDUSD and NZDUSD cointegrated?

This article does not test real data and does not claim the pair is cointegrated now. The two are a common example because the Australian and New Zealand economies are closely linked, but relationships like this change. Test it yourself on recent data and re-test regularly.

Can I use correlation instead of a cointegration test?

No. Return correlation tells you how often two assets move together bar by bar, not whether the gap between them comes back. In this article's example, the cointegrated pair and the non-cointegrated pair have almost the same return correlation (0.79 and 0.75), yet the second pair's spread keeps wandering away.

If the spread runs past z = 4, should I add to the position?

Not as a rule. A z that far out may mean the relationship has changed, not that the spread is cheaper. Adding there increases the bet on an assumption that may already be broken. Closing at the stop and pausing the pair until you re-test it is safer.

This is general education, not investment advice. Trading is risky and you may lose all of your capital.

Tools Chat on LINE