Classic pairs trading strategies have suffered deteriorating returns over time. Can a research pipeline that facilitates the identification and selection of ETF pairs help make pairs trading viable again? This post investigates such a pipeline.
The problem: pairs wander away
Source: Ernie Chan, Algorithmic Trading: Winning Strategies and Their Rationale, Wiley, May 28, 2013, chapter 4.
Pairs trading is a classic arbitrage strategy on securities in the same industry (for example, Coke and Pepsi) in which the trader buys one security and sells the other when the spread between them widens, then closes the positions when the spread narrows again.
In his book Algorithmic Trading, Ernie Chan notes that pairs trading of stocks has become more difficult over time. Two stocks may cointegrate in-sample, but they often wander apart out-of-sample as the fortunes of the respective companies diverge. However, Chan finds more fertile ground for pairs trading among ETFs.
I backtest a pairs trading strategy using an ETF pair from Chan’s book, GLD and GDX (the Gold ETF and Gold Miners ETF).
Based on the tendency of pairs to eventually stop cointegrating, I hypothesize that successful pairs trading might require a robust pipeline for continually identifying and selecting new pairs to trade. I attempt to construct such a pipeline using a 3-step process:
- For a universe of all liquid US ETFs, I test all possible pairs for cointegration using the Johansen test in an in-sample window.
- I run in-sample backtests on all cointegrating pairs and select the 5 best performing pairs.
- I run an out-of-sample backtest on a portfolio of the 5 best performing pairs.
Pairs trading strategy
I create a Moonshot pairs trading strategy that replicates the trading rules in Chan’s book. A few code snippets are highlighed here. The strategy calculates daily hedge ratios using the Johansen test:
from statsmodels.tsa.vector_ar.vecm import coint_johansen # The second and third parameters indicate constant term, with a lag of 1. # See Chan, Algorithmic Trading, chapter 2. result = coint_johansen(pair_prices, 0, 1) # The first column of eigenvectors contains the best weights hedge_ratios = list(result.evec)
The timing of entries and exits is based on Bollinger Bands set one standard deviation away from the spread’s moving average:
# Compute spread and Bollinger Bands spreads = (pair_prices * hedge_ratios).sum(axis=1) means = spreads.fillna(method="ffill").rolling(20).mean() stds = spreads.fillna(method="ffill").rolling(20).std() upper_bands = means + stds lower_bands = means - stds # Long (short) the spread when it crosses below (above) the lower (upper) # band, then exit when it crosses the mean long_entries = spreads < lower_bands long_exits = spreads >= means short_entries = spreads > upper_bands short_exits = spreads <= means
See the full source code and read the rest of the article on QuantRocket website.
Disclosure: Interactive Brokers
Information posted on IBKR Traders’ Insight that is provided by third-parties and not by Interactive Brokers does NOT constitute a recommendation by Interactive Brokers that you should contract for the services of that third party. Third-party participants who contribute to IBKR Traders’ Insight are independent of Interactive Brokers and Interactive Brokers does not make any representations or warranties concerning the services offered, their past or future performance, or the accuracy of the information provided by the third party. Past performance is no guarantee of future results.
This material is from QuantRocket LLC and is being posted with permission from QuantRocket LLC. The views expressed in this material are solely those of the author and/or QuantRocket LLC and IBKR is not endorsing or recommending any investment or trading discussed in the material. This material is not and should not be construed as an offer to sell or the solicitation of an offer to buy any security. To the extent that this material discusses general market activity, industry or sector trends or other broad based economic or political conditions, it should not be construed as research or investment advice. To the extent that it includes references to specific securities, commodities, currencies, or other instruments, those references do not constitute a recommendation to buy, sell or hold such security. This material does not and is not intended to take into account the particular financial conditions, investment objectives or requirements of individual customers. Before acting on this material, you should consider whether it is suitable for your particular circumstances and, as necessary, seek professional advice.
In accordance with EU regulation: The statements in this document shall not be considered as an objective or independent explanation of the matters. Please note that this document (a) has not been prepared in accordance with legal requirements designed to promote the independence of investment research, and (b) is not subject to any prohibition on dealing ahead of the dissemination or publication of investment research.
Any trading symbols displayed are for illustrative purposes only and are not intended to portray recommendations.