Spread Trading with ADRs
Log in to collectAcademic paper
Strategy in a nutshell
The investment universe consists of two ETFs: SPY (S&P500 ETF) representing the US market and FXI (iShares China Large-Cap ETF) representing Chinese ADRs. The investor sets a threshold of -0.4% for the daily spread between ADR and SPY. When the spread falls below this value, the investor opens positions, going long on FXI and short on SPY. The position is held for one day and closed at market close. The portfolio is equally weighted, and the strategy is rebalanced daily.
Economic rationale
The strategy exploits the time-inconsistent behavior of ADRs, especially those from Asian countries. These ADRs are influenced by both U.S. and home market sentiments, leading to asynchronous price movements. This creates spreads between ADR prices and SPY, which the strategy assumes will revert to the mean, allowing profitable trades based on the threshold.
Backtest performance
Full Python code
from AlgorithmImports import *
class SpreadTradingADRs(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)
self.symbols = ['SPY', 'FXI']
self.k = -0.004
for symbol in self.symbols:
self.AddEquity(symbol, Resolution.Minute)
self.spy_open_price = 0
self.fxi_open_price = 0
self.Schedule.On(self.DateRules.EveryDay(self.symbols[0]), self.TimeRules.AfterMarketOpen(self.symbols[0], 1), self.MarketOpen)
self.Schedule.On(self.DateRules.EveryDay(self.symbols[0]), self.TimeRules.BeforeMarketClose(self.symbols[0], 1), self.Rebalance)
def MarketOpen(self):
if self.Securities.ContainsKey(self.symbols[0]) and self.Securities.ContainsKey(self.symbols[1]):
spy_price = self.Securities[self.symbols[0]].Open
fxi_price = self.Securities[self.symbols[1]].Open
if spy_price != 0 and fxi_price != 0:
self.spy_open_price = spy_price
self.fxi_open_price = fxi_price
def Rebalance(self):
self.Liquidate()
if self.Securities.ContainsKey(self.symbols[0]) and self.Securities.ContainsKey(self.symbols[1]):
spy_price = self.Securities[self.symbols[0]].Close
fxi_price = self.Securities[self.symbols[1]].Close
if spy_price != 0 and fxi_price != 0 and self.spy_open_price != 0 and self.fxi_open_price != 0:
spy_ret = spy_price / self.spy_open_price - 1
fxi_ret = fxi_price / self.fxi_open_price - 1
if fxi_ret - spy_ret < self.k:
self.SetHoldings('FXI', 1/2)
self.SetHoldings('SPY', -1/2)
self.spy_open_price = 0
self.fxi_open_price = 0