Overall Statistics |
Total Trades 1508 Average Win 0.00% Average Loss -0.01% Compounding Annual Return -41.963% Drawdown 6.800% Expectancy -0.985 Net Profit -6.813% Sharpe Ratio -29.367 Loss Rate 99% Win Rate 1% Profit-Loss Ratio 0.30 Alpha -0.455 Beta -0.013 Annual Standard Deviation 0.016 Annual Variance 0 Information Ratio -3.424 Tracking Error 0.131 Treynor Ratio 34.276 Total Fees $1508.00 |
import numpy as np # Throws an error, what else? #from Risk.MaximumDrawdownPercentPerSecurity import MaximumDrawdownPercentPerSecurity class VWAPBreakout(QCAlgorithm): def Initialize(self): self.DBG = False # # Chart - Master Container for the Chart: stockPlot = Chart("Custom Plot") stockPlot.AddSeries(Series("Buy", SeriesType.Scatter, 0)) stockPlot.AddSeries(Series("Sell", SeriesType.Scatter, 0)) stockPlot.AddSeries(Series("VWAP", SeriesType.Line, 0)) stockPlot.AddSeries(Series("Price", SeriesType.Candle, 0)) self.AddChart(stockPlot) # #self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.07)) self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage) # # Daily EOD liquidation self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(15, 59, 52),Action(self.End_of_day_liquidate)) # #Initial investment and backtest period self.SetStartDate(2019,7,1) self.SetEndDate(datetime.now().date() - timedelta(1)) #Set End Date self.SetCash(25000) # Adds SPY / QQQ to be used in our technical indicators self.sym = "QQQ" self.res = Resolution.Minute self.SetBenchmark(self.sym) equity = self.AddEquity(self.sym, self.res) # self.tolerance = 1.0025 # threshold to prevent bouncing self.lastPrice = 0 self.lastVwap = 0 # # Rolling Windows to store previous values # https://www.quantconnect.com/docs/algorithm-reference/rolling-window # https://backtest-rookies.com/2018/09/21/quantconnect-accessing-previous-values/ # Creates a Rolling Window indicator to keep the 2 TradeBar # Calculating daily window size relative to sampling size # Trading occurs between 9:30 AM Eastern Time to 4:00 PM Eastern Time. # For 6 hours, 30 minutes or # 6*60 + 30 = 390 minutes # When time sampling is 15 minutes, that means 26 samples a day (390/15) # 390/10 = 39 # 390/15 = 26 # 390/30 = 13 # 390/60 = 6.5 ~6 # dropping last hour self.window_vwap_ten = RollingWindow[TradeBar](39) self.window_vwap_fifteen = RollingWindow[TradeBar](26) self.window_vwap_hour = RollingWindow[TradeBar](6) self.window_vwap_day = RollingWindow[TradeBar](2) # number of previous days self.tradeBar_Window = RollingWindow[TradeBar](2) # number of previous bars on sampling i.e. minute # self.lookback = 15 #1440 # minutes a day self.SetWarmup(self.lookback) #self.SetWarmup(TimeSpan.FromDays(3)) # # vwap indicators # # # PROBLEM: How do I get the updated indicator values for different time frames # stored in the rolling windows? # self.VWAPPeriod = 5 self.vwap_ten = VolumeWeightedAveragePriceIndicator(self.sym, self.VWAPPeriod) self.vwap_fifteen = VolumeWeightedAveragePriceIndicator(self.sym, self.VWAPPeriod) # Creates an indicator and adds to a rolling window when it is updated # https://www.quantconnect.com/docs/algorithm-reference/rolling-window # DOES NOT work: AttributeError : 'VWAPBreakout' object has no attribute 'vwap_fifteen' # #self.vwap_fifteen(self.sym, self.VWAPPeriod).Updated += self.FifteenMinutesUpdated self.vwap_hour = VolumeWeightedAveragePriceIndicator(self.sym, self.VWAPPeriod) self.vwap_day = VolumeWeightedAveragePriceIndicator(self.sym, self.VWAPPeriod) # tenMinutesConsolidator = TradeBarConsolidator(timedelta(minutes =10)) tenMinutesConsolidator.DataConsolidated += self.TenMinutesBarHandler self.SubscriptionManager.AddConsolidator(self.sym, tenMinutesConsolidator) # fifteenMinutesConsolidator = TradeBarConsolidator(timedelta(minutes =10)) fifteenMinutesConsolidator.DataConsolidated += self.FifteenMinutesBarHandler self.SubscriptionManager.AddConsolidator(self.sym, fifteenMinutesConsolidator) # hourlyConsolidator = TradeBarConsolidator(timedelta(hours =1)) hourlyConsolidator.DataConsolidated += self.HourlyBarHandler self.SubscriptionManager.AddConsolidator(self.sym, hourlyConsolidator) # dailyConsolidator = TradeBarConsolidator(timedelta(hours =1)) dailyConsolidator.DataConsolidated += self.DailyBarHandler self.SubscriptionManager.AddConsolidator(self.sym, dailyConsolidator) # # Register the consolidated bar data to automatically update the indicator # https://www.quantconnect.com/docs/algorithm-reference/indicators self.RegisterIndicator(self.sym, self.vwap_ten, tenMinutesConsolidator) self.RegisterIndicator(self.sym, self.vwap_fifteen, fifteenMinutesConsolidator) self.RegisterIndicator(self.sym, self.vwap_hour, hourlyConsolidator) self.RegisterIndicator(self.sym, self.vwap_day, dailyConsolidator) # Consolidate bars for different time sampling # https://www.quantconnect.com/tutorials/api-tutorials/consolidating-data-to-build-bars def TenMinutesBarHandler(self, sender, bar): # TradeBar( DateTime time, Symbol symbol, decimal open, decimal high, decimal low, decimal close, decimal volume) tradeBar = TradeBar(bar.EndTime, bar.Symbol, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume) self.vwap_ten.Update(tradeBar) # Storing the updated bar / value in the rolling window here DOES NOT WORK. Why? #self.window_vwap_ten.Add(self.vwap_ten.Current.Value) def FifteenMinutesBarHandler(self, sender, bar): # TradeBar( DateTime time, Symbol symbol, decimal open, decimal high, decimal low, decimal close, decimal volume) tradeBar = TradeBar(bar.EndTime, bar.Symbol, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume) self.vwap_fifteen.Update(tradeBar) #self.window_vwap_fifteen.Add(self.vwap_fifteen.Current) def HourlyBarHandler(self, sender, bar): # TradeBar( DateTime time, Symbol symbol, decimal open, decimal high, decimal low, decimal close, decimal volume) tradeBar = TradeBar(bar.EndTime, bar.Symbol, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume) self.vwap_hour.Update(tradeBar) def DailyBarHandler(self, sender, bar): # TradeBar( DateTime time, Symbol symbol, decimal open, decimal high, decimal low, decimal close, decimal volume) tradeBar = TradeBar(bar.EndTime, bar.Symbol, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume) self.vwap_day.Update(tradeBar) # # Adds updated values to rolling window # https://quantconnect.com/docs/algorithm-reference/rolling-window def TenMinutesUpdated(self, sender, updated): self.window_vwap_ten.Add(updated) def FifteenMinutesUpdated(self, sender, updated): self.window_vwap_fifteen.Add(updated) def OnData(self, slice): '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. Arguments: data: Slice object keyed by symbol containing the stock data ''' if slice[self.sym] is None: return if not self.vwap_fifteen.IsReady: return # # When this check is enabled, the algo never executes # #if not self.tradeBar_Window.IsReady: return self.tradeBar_Window.Add(slice[self.sym]) self.lastPrice = slice[self.sym].Close self.lastVwap = self.vwap_fifteen.Current.Value #self.Debug(str(self.vwap.Current.Value)) self.Plot('Custom Plot', 'Price', self.lastPrice) self.Plot('Custom Plot', 'VWAP', self.lastVwap) curBar = self.tradeBar_Window[0] self.Debug("Current Price: " + str(curBar.Close)) # Cannot access previous price - WHY? #prvBar = self.tradeBar_Window[1] #self.Debug("Previous Price: " + str(prvBar.Close)) # # THIS IS THE BROKEN PART: How do I get the previous VWAP values from different time frames??? # #curVWAP_vwap_fifteen = self.window_vwap_fifteen[0] #prvVWAP_vwap_fifteen = self.window_vwap_fifteen[1] #self.Debug("Current VWAP: " + str(curVWAP)) #self.Debug("Previous VWAP: " + str(prvVWAP)) # # Same here,how do I store the updated (day sampled) VWAP in the rolling window # so that I can access previous values here? # #today_vwap = self.window_vwap_day[0] #yesterday_vwap = self.window_vwap_day[1] #self.Debug("Today VWAP: " + str(today_vwap)) #self.Debug("Yesterday VWAP: " + str(yesterday_vwap)) price = self.lastPrice * 1.0025 if not self.Portfolio.Invested and self.lastPrice < self.lastVwap: #set stop price and limit price at +-2% twoPercent = 0.98 takeProfit = 1.02 #SL and TP orders to protect investment stopPrice = self.Securities[self.sym].Price * twoPercent limitPrice = self.Securities[self.sym].Price * takeProfit qty = 5 self.MarketOrder(self.sym, 2) self.Plot("Custom Plot", "Buy", self.lastPrice) self.StopLimitOrder(self.sym, -qty, stopPrice, stopPrice) self.LimitOrder(self.sym, qty, limitPrice) if self.Portfolio.Invested and self.lastPrice > self.lastVwap: self.Plot("Custom Plot", "Sell", self.lastPrice) self.Liquidate() def End_of_day_liquidate(self): self.Liquidate() def OnOrderEvent(self, orderEvent): #self.Log(str(orderEvent)) self.Debug(str(orderEvent))