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)