Overall Statistics
Total Trades
21854
Average Win
0.77%
Average Loss
0.07%
Compounding Annual Return
-11.648%
Drawdown
49.000%
Expectancy
1.065
Net Profit
-46.194%
Sharpe Ratio
-0.588
Sortino Ratio
-0.708
Probabilistic Sharpe Ratio
0.004%
Loss Rate
84%
Win Rate
16%
Profit-Loss Ratio
11.83
Alpha
0
Beta
0
Annual Standard Deviation
0.156
Annual Variance
0.024
Information Ratio
-0.455
Tracking Error
0.156
Treynor Ratio
0
Total Fees
$22517.61
Estimated Strategy Capacity
$12000000.00
Lowest Capacity Asset
QQQ RIWIV7K5Z9LX
Portfolio Turnover
2107.52%
# region imports
from AlgorithmImports import *
from QuantConnect.Data import Slice
# endregion

# Fee model to test zero fees
class CustomFeeModel(FeeModel):
    def __init__(self):
        pass  
    def GetOrderFee(self, parameters: OrderFeeParameters) -> OrderFee:
        return OrderFee.Zero

# Buying power model so that we can aoivd trading single shares
class MinimumOrderSizeBuyingPowerModel(BuyingPowerModel):
    def __init__(self, min_order_size):
        self.min_order_size = min_order_size

    def GetMinimumOrderQuantityForResolution(self, security, targetOrderValue):
        return OrderQuantity(self.min_order_size, 0)

    def GetBuyingPower(self, parameters):
        return BuyingPower(self.Portfolio.Cash, 0)



class Vwaptrend(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2018, 11, 10)
        self.SetEndDate(2023, 11, 11)
        self.SetCash(25000)
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) # Equal weighting with assets
        self.SetExecution(ImmediateExecutionModel())
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)

        self.asset1 = self.AddEquity("QQQ", Resolution.Minute)
        self.asset1.SetDataNormalizationMode(DataNormalizationMode.Raw)
        self.asset1.SetBuyingPowerModel(MinimumOrderSizeBuyingPowerModel(10))  # Set minimum order size to 10 so that insights don't trade single shares

        self.asset1_vwap = self.VWAP(self.asset1.Symbol)
        self.asset1_long = None

        self.period = timedelta(days=1) # Insight period, but we're not using it here as the execution model is with market orders

        # Turn off fees here, comment out for normal IB fees
        # self.asset1.SetFeeModel(CustomFeeModel())

    def OnData(self, slice: Slice) -> None:
        if not self.asset1_vwap.IsReady or (self.Time.hour == 9 and self.Time.minute == 30) or (self.Time.hour == 16 and self.Time.minute == 0):
            return

        # exit position EOD
        if self.Time.hour == 15 and self.Time.minute == 59:
            asset1_insight = Insight.Price(self.asset1.Symbol, self.period, InsightDirection.Flat)
            self.EmitInsights(asset1_insight)
            self.Log(f'Exiting position at EOD')
            self.asset1_long = None
            return
        
        # If getting second resolution data but don't want to trade every second
        # if not self.Time.second == 0:
        #     return
        
        # If we want to trade every 5 minutes
        # if not self.Time.minute % 5 == 0:
        #     return
        
        price1 = self.asset1.Close
        vwap1 = round(self.asset1_vwap.Current.Value, 2)
        diff = price1 - vwap1
        minimum = 0
        if diff > minimum and (not self.asset1_long or self.asset1_long is None):
            asset1_insight = Insight.Price(self.asset1.Symbol, self.period, InsightDirection.Up)
            self.EmitInsights(asset1_insight)
            self.asset1_long = True
            self.Log(f'vwap: {round(self.asset1_vwap.Current.Value, 2)} price: {price1} Flipping to long')

        if diff < -1 * minimum and (self.asset1_long or self.asset1_long is None):
            asset1_insight = Insight.Price(self.asset1.Symbol, self.period, InsightDirection.Down)
            self.EmitInsights(asset1_insight)
            self.asset1_long = False
            self.Log(f'vwap: {round(self.asset1_vwap.Current.Value, 2)} price: {price1} Flipping to short')

        # do this every few minutes
        # if self.Time.minute % 1  == 0:    
        #     self.Plot("IntradayVwap", "vwap", self.asset1_vwap.Current.Value)
        #     self.Plot("IntradayVwap", "price", price1)
        #     self.Log(f"vwap: {self.asset1_vwap.Current.Value} price: {price1}")