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