Want to learn about the Simple Pair Trading Strategy? It’s a trading method that doesn’t rely on market direction. Instead, it focuses on the relationship between two highly linked stocks or financial instruments. The idea is to profit from their relative price changes, not their individual performance. This strategy banks on the principle of mean reversion, believing that the prices of two linked assets will revert to their historical relationship over time.
Why Choose Pair Trading?
Pair trading is seen as less risky than traditional trading strategies. It’s because it hinges on the link between two assets, not the overall market direction. To use the Simple Pair Trading Strategy, you look for two assets that have always been strongly linked. Then, you monitor their price ratio. If it varies greatly from its historical average, it’s time to trade.
Implementing the Simple Pair Trading Strategy
To put this strategy into action, first, find a pair of assets that have a high correlation. This can be done using statistical analysis or by focusing on assets from the same industry, sector, or market. After finding a suitable pair, keep an eye on the price ratio between the two assets. If the ratio differs from its historical average, go long on the underperforming asset and short on the overperforming asset. The hope is that the price ratio will revert to its mean, resulting in profit.
Remember, the success of the Simple Pair Trading Strategy heavily depends on the chosen assets’ correlation staying stable over time. Also, consider transaction costs and other trading expenses, as these can affect overall profitability.
In the following example, we demonstrate a Simple Pair Trading Strategy with the SPY and QQQ ETFs. The algorithm computes the price ratio between the two assets and compares it to the historical average price ratio. If the current ratio deviates significantly from the historical average, the algorithm takes long and short positions in the underperforming and outperforming assets, respectively. Once the price ratio returns to the historical range, the algorithm closes any open positions.
Click on the code to copy it to your clipboard.
Click here for detailed instructions on how to use the scripts in QuantConnect.
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Data.Market import TradeBar
import numpy as np
class SimplePairTradingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 1, 1)
self.SetEndDate(2021, 1, 1)
self.SetCash(100000)
# Define the assets to be traded
self.asset1 = self.AddEquity("SPY", Resolution.Daily).Symbol
self.asset2 = self.AddEquity("QQQ", Resolution.Daily).Symbol
# Set the window size for the price ratio calculation
self.windowSize = 20
self.priceRatio = RollingWindow[float](self.windowSize)
# Set the trading thresholds
self.upperThreshold = 1.02
self.lowerThreshold = 0.98
# Schedule the TradePair function to execute after market open
self.Schedule.On(self.DateRules.EveryDay(self.asset1), self.TimeRules.AfterMarketOpen(self.asset1, 5), self.TradePair)
def TradePair(self):
# Get the current prices of the assets
asset1Price = self.Securities[self.asset1].Price
asset2Price = self.Securities[self.asset2].Price
# Calculate the current price ratio
currentRatio = asset1Price / asset2Price
# Add the current price ratio to the rolling window
self.priceRatio.Add(currentRatio)
# Check if the rolling window is ready (has enough data)
if not self.priceRatio.IsReady:
return
# Calculate the average price ratio
averageRatio = np.mean([x for x in self.priceRatio])
# Execute trades based on the current price ratio compared to the average price ratio and thresholds
if currentRatio > averageRatio * self.upperThreshold:
self.SetHoldings(self.asset1, -0.5) # Short the asset 1
self.SetHoldings(self.asset2, 0.5) # Long the asset 2
elif currentRatio < averageRatio * self.lowerThreshold:
self.SetHoldings(self.asset1, 0.5) # Long the asset 1
self.SetHoldings(self.asset2, -0.5) # Short the asset 2
else:
self.Liquidate(self.asset1) # Close any open positions for asset 1
self.Liquidate(self.asset2) # Close any open positions for asset 2
using System;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;
using QuantConnect.Orders;
namespace QuantConnect.Algorithm.CSharp
{
public class SimplePairTradingAlgorithm : QCAlgorithm
{
// Define the assets to be traded
private Symbol _asset1 = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
private Symbol _asset2 = QuantConnect.Symbol.Create("QQQ", SecurityType.Equity, Market.USA);
// Set the window size for the price ratio calculation
private int _windowSize = 20;
private RollingWindow<decimal> _priceRatio;
// Set the trading thresholds
private decimal _upperThreshold = 1.02m;
private decimal _lowerThreshold = 0.98m;
public override void Initialize()
{
SetStartDate(2020, 01, 01);
SetEndDate(2021, 01, 01);
SetCash(100000);
// Add the assets to the algorithm
AddEquity(_asset1.Value, Resolution.Daily);
AddEquity(_asset2.Value, Resolution.Daily);
// Initialize the rolling window for the price ratio
_priceRatio = new RollingWindow<decimal>(_windowSize);
// Schedule the TradePair function to execute after market open
Schedule.On(DateRules.EveryDay(_asset1), TimeRules.AfterMarketOpen(_asset1, 5), () =>
{
TradePair();
});
}
public void TradePair()
{
// Get the current prices of the assets
decimal asset1Price = Securities[_asset1].Price;
decimal asset2Price = Securities[_asset2].Price;
// Calculate the current price ratio
decimal currentRatio = asset1Price / asset2Price;
// Add the current price ratio to the rolling window
_priceRatio.Add(currentRatio);
// Check if the rolling window is ready (has enough data)
if (!_priceRatio.IsReady) return;
// Calculate the average price ratio
decimal averageRatio = _priceRatio.Sum() / _windowSize;
// Execute trades based on the current price ratio compared to the average price ratio and thresholds
if (currentRatio > averageRatio * _upperThreshold)
{
SetHoldings(_asset1, -0.5); // Short the asset 1
SetHoldings(_asset2, 0.5); // Long the asset 2
}
else if (currentRatio < averageRatio * _lowerThreshold)
{
SetHoldings(_asset1, 0.5); // Long the asset 1
SetHoldings(_asset2, -0.5); // Short the asset 2
}
else
{
Liquidate(_asset1); // Close any open positions for asset 1
Liquidate(_asset2); // Close any open positions for asset 2
}
}
}
}