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)