| Overall Statistics |
|
Total Trades 124 Average Win 1.04% Average Loss -0.77% Compounding Annual Return -2.959% Drawdown 7.400% Expectancy -0.127 Net Profit -6.165% Sharpe Ratio -0.512 Loss Rate 63% Win Rate 37% Profit-Loss Ratio 1.35 Alpha -0.084 Beta 2.838 Annual Standard Deviation 0.055 Annual Variance 0.003 Information Ratio -0.871 Tracking Error 0.055 Treynor Ratio -0.01 Total Fees $124.00 |
import numpy as np
import decimal as d
class PairsDualListedArbitrage(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2016,1,1)
self.SetEndDate(2017,12,1)
self.SetCash(1000)
self.TakeProfit = d.Decimal(1.025)
self.StopLoss = d.Decimal(1.01)
self.StringSymbols = ["DISCA", "DISCK"]
self.symbols = [
self.AddEquity(self.StringSymbols[0], Resolution.Minute).Symbol,
self.AddEquity(self.StringSymbols[1], Resolution.Minute).Symbol
]
for i in self.symbols:
i.fast = self.SMA(i, 20, Resolution.Daily)
i.slow = self.SMA(i, 50, Resolution.Daily)
self.AddEquity("SPY", Resolution.Minute)
self.Schedule.On(self.DateRules.EveryDay("SPY"),
self.TimeRules.AfterMarketOpen("SPY",0),
Action(self.SetBenchmark))
self.Schedule.On(self.DateRules.EveryDay("SPY"),
self.TimeRules.AfterMarketOpen("SPY", 60),
Action(self.Rebalance1))
self.Schedule.On(self.DateRules.EveryDay("SPY"),
self.TimeRules.AfterMarketOpen("SPY", 380),
Action(self.Reset))
self.SetWarmUp(int(6.5*60*50))
def OnData(self, data):
if self.IsWarmingUp: return
def SetBenchmark(self):
# Returns a spread for the premium of owning X stock over the
# past 100 days
# The mean of those 100 spreads becomes the Benchmark Spread that we base our
# predictions off of
mainHistoricalClose = self.History([self.StringSymbols[1]], 100, Resolution.Minute).loc[self.StringSymbols[1]]["close"]
dualHistoricalClose = self.History([self.StringSymbols[0]], 100, Resolution.Minute).loc[self.StringSymbols[0]]["close"]
spread = dualHistoricalClose - mainHistoricalClose
self.benchmarkSpread = spread.mean()
self.benchmarkSpread = float(self.benchmarkSpread)
def Rebalance1(self):
mainPrice = self.Securities[self.StringSymbols[1]].Price
dualPrice = self.Securities[self.StringSymbols[0]].Price
currentSpread = float(dualPrice - mainPrice)
self.PercentDiff = (currentSpread - self.benchmarkSpread)/self.benchmarkSpread
for i in self.symbols:
i.IsUpTrend = i.fast.Current.Value > i.slow.Current.Value
if self.symbols[1].IsUpTrend and self.PercentDiff > .070:
if self.Portfolio[self.symbols[1]].Quantity <= 0:
self.MarketOrder(self.symbols[1], int(self.Portfolio.TotalPortfolioValue/mainPrice))
self.LimitOrder(self.symbols[1], -1*abs(self.Portfolio[self.symbols[1]].Quantity), d.Decimal(mainPrice)*self.TakeProfit, tag="Short")
self.StopMarketOrder(self.symbols[1], -1*abs((self.Portfolio[self.symbols[1]].Quantity)), d.Decimal(mainPrice)/self.StopLoss, tag="Short")
elif self.symbols[0].IsUpTrend and self.PercentDiff < -.070:
if self.Portfolio[self.symbols[0]].Quantity <= 0:
self.MarketOrder(self.symbols[0], int(self.Portfolio.TotalPortfolioValue/dualPrice))
self.LimitOrder(self.symbols[0], -1*abs((self.Portfolio[self.symbols[0]].Quantity)), d.Decimal(dualPrice)*self.TakeProfit, tag="Short")
self.StopMarketOrder(self.symbols[0], -1*abs((self.Portfolio[self.symbols[0]].Quantity)), d.Decimal(dualPrice)/self.StopLoss, tag="Short")
def Reset(self):
self.Liquidate()
def OnOrderEvent(self, orderEvent):
order = self.Transactions.GetOrderById(orderEvent.OrderId)
if order.Status == OrderStatus.Filled:
if order.Type == OrderType.Limit or order.Type == OrderType.StopMarket:
self.Transactions.CancelOpenOrders(order.Symbol)