| Overall Statistics |
|
Total Trades 74 Average Win 0.81% Average Loss -0.74% Compounding Annual Return -3.424% Drawdown 7.100% Expectancy -0.263 Net Profit -7.116% Sharpe Ratio -0.869 Loss Rate 65% Win Rate 35% Profit-Loss Ratio 1.10 Alpha -0.081 Beta 2.402 Annual Standard Deviation 0.039 Annual Variance 0.002 Information Ratio -1.379 Tracking Error 0.039 Treynor Ratio -0.014 Total Fees $74.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),
self.AddEquity(self.StringSymbols[1], Resolution.Minute)
]
self.fast = self.SMA(self.StringSymbols[1], 20, Resolution.Daily)
self.slow = self.SMA(self.StringSymbols[1], 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
self.mainHistory = self.History([self.StringSymbols[1]], 50) # Class B shares
self.dualHistory = self.History([self.StringSymbols[0]], 50) # Class A shares
mainBars = self.mainHistory.loc[self.StringSymbols[1]]
mainHistoricalClose = mainBars["close"]
dualBars = self.dualHistory.loc[self.StringSymbols[0]]
dualHistoricalClose = dualBars["close"]
spread = dualHistoricalClose - mainHistoricalClose
self.benchmarkSpread = spread.mean()
self.benchmarkSpread = float(self.benchmarkSpread)
def Rebalance1(self):
main = self.Securities[self.StringSymbols[1]]
dual = self.Securities[self.StringSymbols[0]]
mainPrice = main.Price
dualPrice = dual.Price
currentSpread = dualPrice - mainPrice
currentSpread = float(currentSpread)
self.PercentDiff = (currentSpread - self.benchmarkSpread)/self.benchmarkSpread
self.IsUpTrend = self.fast.Current.Value > self.slow.Current.Value
if self.IsUpTrend:
if self.PercentDiff > .070:
if self.Portfolio[self.StringSymbols[1]].Quantity <= 0:
self.MarketOrder(self.StringSymbols[1], int(self.Portfolio.TotalPortfolioValue/mainPrice))
self.LimitOrder(self.StringSymbols[1], -1*abs((self.Portfolio[self.StringSymbols[1]].Quantity)), d.Decimal(mainPrice)*self.TakeProfit, tag="Short")
self.StopMarketOrder(self.StringSymbols[1], -1*abs((self.Portfolio[self.StringSymbols[1]].Quantity)), d.Decimal(mainPrice)/self.StopLoss, tag="Short")
def Reset(self):
self.Liquidate(self.StringSymbols[1])
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)