| Overall Statistics |
|
Total Trades 44 Average Win 1.90% Average Loss -4.01% Compounding Annual Return 19.890% Drawdown 5.400% Expectancy 0.326 Net Profit 17.238% Sharpe Ratio 1.52 Loss Rate 10% Win Rate 90% Profit-Loss Ratio 0.47 Alpha 0.077 Beta 0.667 Annual Standard Deviation 0.1 Annual Variance 0.01 Information Ratio 0.474 Tracking Error 0.082 Treynor Ratio 0.229 Total Fees $83.75 |
from datetime import datetime
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from sklearn import linear_model
import numpy as np
from scipy import stats
class PairsTradingAlgorithm(QCAlgorithm):
def Initialize(self):
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
self.SetStartDate(2014,1,5)
self.SetEndDate(2014,11,20)
self.SetCash(100000)
self.numdays = 120 # set the length of training period
self.ticker = ["XLK","QQQ"]
self.syl = []
self.threshold = 2
self.coef = None
self.mean, self.std = None, None
for i in self.ticker:
equity = self.AddSecurity(SecurityType.Equity, i, Resolution.Daily)
self.syl.append(equity.Symbol)
self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Monday),self.TimeRules.At(10, 0), Action(self._set_signal))
#self.Schedule.On(self.DateRules.MonthStart(self.syl[0]), self.TimeRules.AfterMarketOpen(self.syl[0],30), Action(self._set_signal))
#self.Schedule.On(self.DateRules.MonthStart(self.syl[1]), self.TimeRules.AfterMarketOpen(self.syl[1],30), Action(self._set_signal))
#self.Schedule.On(self.DateRules.EveryDay(self.syl[0]),self.TimeRules.AfterMarketOpen(self.syl[0],30),Action(self._set_signal))
#self.Schedule.On(self.DateRules.EveryDay(self.syl[1]),self.TimeRules.AfterMarketOpen(self.syl[1],30),Action(self._set_signal))
def _set_signal(self):
history = self.History(self.numdays,Nullable[Resolution](Resolution.Daily))
logprice = {}
for j in range(len(self.syl)):
close = []
for slice in history:
bar = slice[self.syl[j]]
close.append(bar.Close)
logprice[self.ticker[j]] = np.log([float(z) for z in close]) # generate the log return series of stock price
# run linear regression over the two history log price series
reg = linear_model.LinearRegression()
x,y = logprice[self.ticker[0]],logprice[self.ticker[1]]
reg.fit([[n] for n in x],y)
self.coef = reg.coef_ # reg.intercept_
self.spread = y - self.coef * x #compute the spread series based on regression result
self.mean, self.std = np.mean(self.spread),np.std(self.spread)
def OnData(self,data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.'''
if self.mean == None or self.std == None: return
else:
logprice_x = np.log(float(self.Portfolio[self.syl[0]].Price))
logprice_y = np.log(float(self.Portfolio[self.syl[1]].Price))
syl_x, syl_y = self.syl[0],self.syl[1]
quantity = float(self.CalculateOrderQuantity(syl_y,0.4))
current_spread = float(logprice_y) - self.coef * float(logprice_x)
if self.mean == None or self.std == None: return
else:
if current_spread > self.mean + self.threshold * self.std:
self.Sell(syl_y, 1 * quantity)
self.Buy(syl_x, self.coef * quantity)
self.Log('Trade I : ' + str(syl_y)+' , '+str(quantity)+' , '+str(syl_x)+' , '+str(self.coef*quantity))
elif current_spread < self.mean - self.threshold * self.std:
self.Buy(syl_y, 1 * quantity )
self.Sell(syl_x, self.coef * quantity)
self.Log('Trade II : ' + str(syl_y)+' , '+str(quantity)+' , '+str(syl_x)+' , '+str(self.coef*quantity))
if self.Portfolio[self.syl[0]].Quantity != 0 and self.Portfolio[self.syl[1]].Quantity != 0:
if current_spread < 0.5 * self.std and current_spread > -0.5 * self.std:
self.Liquidate(self.syl[0])
self.Liquidate(self.syl[1])