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))