Overall Statistics
Total Orders
21
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Start Equity
100000
End Equity
101159.28
Net Profit
0%
Sharpe Ratio
0
Sortino Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$28.16
Estimated Strategy Capacity
$7900000.00
Lowest Capacity Asset
QQQ RIWIV7K5Z9LX
Portfolio Turnover
2067.55%
from AlgorithmImports import *

# QuantConnect algorithm to reproduce results in
# Zarattini, Carlo and Aziz, Andrew,
# Volume Weighted Average Price (VWAP) The Holy Grail for Day Trading Systems (November 13, 2023).
# Available at SSRN: https://ssrn.com/abstract=4631351 or http://dx.doi.org/10.2139/ssrn.4631351

class VWAPTrendTradingAlgorithm(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2023, 11, 10)
        self.SetEndDate(2023, 11, 10)
        self.SetCash(100000)
        self.symbol = self.AddEquity("QQQ", Resolution.Minute).Symbol
        self.vwap = self.VWAP(self.symbol)

        self.Schedule.On(self.DateRules.EveryDay(self.symbol), 
                         self.TimeRules.BeforeMarketClose(self.symbol, 1), 
                         self.EndTrading)

        chart = Chart("Chart")
        chart.AddSeries(CandlestickSeries("QQQ", "$"))
        chart.AddSeries(Series("WVAP", SeriesType.LINE, "$", Color.Blue))
        chart.AddSeries(Series("Buys", SeriesType.SCATTER, "$", Color.Green, ScatterMarkerSymbol.TRIANGLE))
        chart.AddSeries(Series("Sells", SeriesType.SCATTER, "$", Color.Red, ScatterMarkerSymbol.TRIANGLE_DOWN))
        self.AddChart(chart)

    def EndTrading(self):
        self.ExitPosition()

    def OnData(self, data):
        if not data.ContainsKey(self.symbol) or data[self.symbol] is None:
            return

        self.plot("Chart", "Candles", data[self.symbol])
        price = data[self.symbol].Close

        if not self.vwap.IsReady:
            return

        self.Plot("Chart", "VWAP", self.vwap.Current.Value)

        if not self.Portfolio[self.symbol].Invested:
            self.EnterPosition(price)
        else:
            if self.Portfolio[self.symbol].IsLong and price < self.vwap.Current.Value:
                self.stopLoss()
                self.EnterPosition(price)
            elif self.Portfolio[self.symbol].IsShort and price > self.vwap.Current.Value:
                self.stopLoss()
                self.EnterPosition(price)

    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Filled:
            # Retrieve the fill price from the order event
            fillPrice = orderEvent.FillPrice
            
            # Check the order direction and plot accordingly
            if orderEvent.Direction == OrderDirection.Buy:
                self.Plot("Chart", "Buys", fillPrice)
            elif orderEvent.Direction == OrderDirection.Sell:
                self.Plot("Chart", "Sells", fillPrice)

    def EnterPosition(self, price):
        if self.vwap.Current.Value < price:
            self.SetHoldings(self.symbol, 1) # go long
        else:
            self.SetHoldings(self.symbol, -1) # go short

    def stopLoss(self):
        self.Liquidate(self.symbol)

    def ExitPosition(self):
        self.Liquidate(self.symbol)

    def OnEndOfDay(self, symbol: Symbol):
        pass