US Equities Pairs Trading Strategy with Six-Month Mean Reversion Holding
Log in to collectOnsite backtest IDE
Quant Buffet native backtest IDEEdit and run Quant Buffet Python for US Equities Pairs Trading Strategy with Six-Month Mean Reversion Holding in the browser. Results update live with equity, drawdown, and metrics charts. Allowed: backtest.data, backtest.engine, backtest.metrics, numpy, pandas. Define ASSETS and make_on_day(prices). Shortcut: Ctrl+Enter. API docs →
Quant Buffet syntax cheat sheet (copy / insert)
Paste these fragments into the editor. The sandbox rejects QuantConnect, os, and network libraries.
from __future__ import annotations
import numpy as np
import pandas as pd
from backtest.data import load_daily_prices
from backtest.engine import EngineConfig, PortfolioEngine
from backtest.metrics import compute_metricsASSETS = ["SPY", "QQQ", "TLT", "GLD", "BIL"]def make_on_day(prices: pd.DataFrame):
cols = [c for c in ASSETS if c in prices.columns]
sma = prices[cols].rolling(200, min_periods=200).mean()
state = {"last": None}
def on_day(engine: PortfolioEngine, dt: pd.Timestamp) -> None:
if sma.loc[dt].isna().all():
return
key = (dt.year, dt.month)
if state["last"] == key:
return
state["last"] = key
long = [
s for s in cols
if pd.notna(prices.at[dt, s]) and pd.notna(sma.at[dt, s])
and prices.at[dt, s] > sma.at[dt, s]
]
weights = {} if not long else {s: 1.0 / len(long) for s in long}
engine.set_target_weights(dt, weights)
ready = sma.dropna(how="all").index.min() if sma.notna().any().any() else None
return on_day, readyengine.set_target_weights(dt, {"SPY": 0.60, "BIL": 0.40})Live backtest performance
Export to your platform
Transform Quant Buffet lab code (ASSETS + make_on_day / PortfolioEngine) into native classes for a third-party IDE — then copy and paste.
# Generated from Quant Buffet → QuantConnect LEAN
# Strategy: US Equities Pairs Trading Strategy with Six-Month Mean Reversion Holding
# Detected pattern: SMA trend
# Source uses Quant Buffet lab APIs (ASSETS + make_on_day / PortfolioEngine).
# Review fees, data, and risk before live trading — educational export only.
from AlgorithmImports import *
class QuantBuffetExport(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)
tickers = ["SPY", "TLT", "GLD", "BIL"]
self.symbols = []
for t in tickers:
if "-" in t: # crypto proxy e.g. BTC-USD
self.symbols.append(self.AddCrypto(t.replace("-USD", ""), Resolution.Daily).Symbol)
else:
self.symbols.append(self.AddEquity(t, Resolution.Daily).Symbol)
self.Schedule.On(
self.DateRules.MonthStart(self.symbols[0]),
self.TimeRules.AfterMarketOpen(self.symbols[0], 30),
self.Rebalance,
)
# Logic: Long assets where close > SMA(200); equal-weight; monthly.
def Rebalance(self):
longs = []
for symbol in self.symbols:
hist = self.History(symbol, 200 + 5, Resolution.Daily)
if hist.empty: continue
close = hist["close"].unstack(level=0).iloc[:, 0] if hasattr(hist["close"], "unstack") else hist["close"]
if len(close) < 200: continue
if float(close.iloc[-1]) > float(close.iloc[-200:].mean()):
longs.append(symbol)
weight = 1.0 / len(longs) if longs else 0.0
for symbol in self.symbols:
self.SetHoldings(symbol, weight if symbol in longs else 0.0)
Exported code uses the platform’s native classes and libraries. Install dependencies in your third-party IDE, then run. Validate before live trading.
Academic paper
Pairs Trading: Performance of a Relative Value Arbitrage Rule
Evan Gatev; William N. Goetzmann; K. Geert Rouwenhorst
- CASimon Fraser University
- National Bureau of Economic Research
- ?National Bureau of Economic Research (NBER)
- ?Yale School of Management - International Center for Finance
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=141615

Strategy in a nutshell
The strategy selects stocks from NYSE, AMEX, and NASDAQ, excluding illiquid ones. Stocks are normalized to $1, forming a cumulative total return index. Over twelve months, pairs are formed based on minimum squared deviations between their price series. The top 20 pairs with the smallest historical distance are identified for trading. In the subsequent six-month trading period, a long-short strategy is executed, initiating positions when pair prices diverge by two standard deviations and closing them upon price convergence, capitalizing on the pairs' historical pricing relationships and expected mean reversion.
Economic rationale
Nunzio Tartaglia, a pioneer in pairs trading, attributed the strategy's success to exploiting the psychological tendencies of investors who hesitate to buy stocks when they fall, unlike pairs traders who capitalize on such moments. The strategy banks on the historical co-integration of stock prices, predicting that pairs with past close correlations are likely to revert to common price movements after a divergence due to temporary shocks, offering arbitrage opportunities. Continuous updates to the pair selection process ensure only those with high convergence probabilities are traded, excluding pairs that drift apart. Research by Chen, Chen, and Li further delves into the economic underpinnings of pairs trading, discovering that returns are not solely based on short-term reversal patterns but significantly on correlations explainable by common financial factors. The strategy's performance varies with market conditions, demonstrating challenges during liquidity crises and a diminishing return over time, suggesting a need for evolving the pairs trading approach to maintain its effectiveness.