Overall Statistics |
Total Trades 13654 Average Win 0.06% Average Loss -0.04% Compounding Annual Return 15.169% Drawdown 64.500% Expectancy 0.179 Net Profit 32.982% Sharpe Ratio 0.508 Probabilistic Sharpe Ratio 17.912% Loss Rate 56% Win Rate 44% Profit-Loss Ratio 1.71 Alpha 0.261 Beta -0.225 Annual Standard Deviation 0.49 Annual Variance 0.24 Information Ratio 0.37 Tracking Error 0.523 Treynor Ratio -1.106 Total Fees $33705.62 Estimated Strategy Capacity $0 Lowest Capacity Asset ZC Y4B76QPA3Z8L |
#region imports from datetime import datetime, timedelta import datetime from AlgorithmImports import * import pandas as pd from QuantConnect.Python import * from QuantConnect.Indicators import RollingWindow #endregion class RetrospectiveTanButterfly(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 9, 17) # Set Start Date self.SetEndDate(2022, 9, 23) self.SetCash(1000000) # Set Strategy Cash self.symbolData = {} self.canLong = True self.canShort = True self.contract = self.AddFuture(Futures.Grains.Corn , Resolution.Tick, extendedMarketHours = False, dataNormalizationMode = DataNormalizationMode.BackwardsRatio, dataMappingMode = DataMappingMode.OpenInterest , contractDepthOffset = 0) symbol = self.contract.Symbol #symbol.SetFilter(0, 90) #Futures.Grains.Corn, Futures.Indices.SP500EMini, Futures.Energies.CrudeOilWTI #Energies.CrudeOilWTI self.symbolData[symbol] = SymbolData() self.symbolData[symbol].bidPrice = self.Securities[symbol].BidPrice self.symbolData[symbol].askPrice = self.Securities[symbol].AskPrice self.v_quantity_window = RollingWindow[float](10000) self.v_price_window = RollingWindow[float](10000) #symbol.SetFilter(lambda x: x.FrontMonth().OnlyApplyFilterAtMarketOpen()) self.marketclose = 17*60 self.tickcount = 0 #self.treset = datetime(2000,7,6,10,0,0) self.askcooldown = True self.bidcooldown = True self.bidreset = 0 self.askreset = 0 self.pricehreset = 0 self.pricelreset = 0 self.tickcount = 0 self.orderIDs = pd.DataFrame([],columns=['id','fillprice','quantity','time']) self.BuyFlag = False self.trigger = False self.ticklist = [] def OnData(self, data): for changedEvent in data.SymbolChangedEvents.Values: if changedEvent.Symbol == self.contract.Symbol: self.Log(f"SymbolChanged event: {changedEvent}") self.Log(f"contract mapped symbol: {self.contract.Mapped}") for symbol, symbolData in self.symbolData.items(): if not data.Ticks.ContainsKey(symbol): continue #underlying = symbol.Underlying ticks = data.Ticks[symbol] for tick in ticks: if tick.TickType == TickType.Quote: symbolData.bidPrice = tick.BidPrice if tick.BidPrice != 0 else symbolData.bidPrice symbolData.askPrice = tick.AskPrice if tick.AskPrice != 0 else symbolData.askPrice #symbolData.bidSize = tick.BidSize if tick.BidSize != 0 else symbolData.bidSize #symbolData.askSize = tick.AskSize if tick.AskSize != 0 else symbolData.askSize if tick.TickType == TickType.Trade: self.tickcount += 1 if symbolData.bidIceberg == 0 and symbolData.bidPrice != 0: #fix this logic, how do i know if its a ask ice or bid ice symbolData.bidIceberg = symbolData.bidPrice symbolData.bidCounter = 0 if tick.Price < symbolData.bidIceberg: symbolData.bidIceberg = tick.Price symbolData.bidCounter = 0 self.pricelreset += 1 self.bidcooldown = True if tick.Price == symbolData.bidIceberg: symbolData.bidCounter += tick.Quantity if tick.Price > symbolData.bidIceberg / 0.995: symbolData.bidIceberg = 0 symbolData.bidCounter = 0 self.bidreset += 1 #delete self.bidcooldown = True if symbolData.askIceberg == 0 and symbolData.askPrice != 0: symbolData.askIceberg = symbolData.askPrice symbolData.askCounter = 0 if tick.Price > symbolData.askIceberg: symbolData.askIceberg = tick.Price symbolData.askCounter = 0 self.pricehreset += 1 self.askcooldown = True if tick.Price == symbolData.askIceberg: symbolData.askCounter += tick.Quantity if tick.Price < symbolData.askIceberg * 0.995: symbolData.askIceberg = 0 symbolData.askCounter = 0 self.askreset += 1 #delete self.askcooldown = True if symbolData.bidSize > 400: symbolData.bidPacman = symbolData.bidPrice if symbolData.askSize > 400: symbolData.askPacman = symbolData.askPrice #symbolData.bidPrice = symbolData #mark bid price as variable, so that price cant be used as an iceberg #if self.tickcount < 1075 and self.tickcount > 1000: #self.Log(f"tick price->: {tick.Price} tick quantity->: {tick.Quantity} bid ice->: {symbolData.bidIceberg} ask ice->: {symbolData.askIceberg} bid count->: {symbolData.bidCounter} ask count->: {symbolData.askCounter} bid price->: {symbolData.bidPrice} ask price->: {symbolData.askPrice} tick sus->: {tick.Suspicious}") #if tick.Time > datetime(2020,7,6,10,0,0) and tick.Time < datetime(2020,7,6,10,0,10):#2020-07-06 10:00:03 #self.Log(f"tick price->: {tick.Price} tick quantity->: {tick.Quantity} bid ice->: {symbolData.bidIceberg} ask ice->: {symbolData.askIceberg} bid count->: {symbolData.bidCounter} ask count->: {symbolData.askCounter} bid price->: {symbolData.bidPrice} ask price->: {symbolData.askPrice} tick sus->: {tick.Suspicious}") #if symbolData.askCounter < 100: # symbolData.askIceberg = 0 # symbolData.askCounter = 0 # self.askreset += 1 #delete if symbolData.askCounter > 200 and self.askcooldown: #and symbolData.askPacman == symbolData.askIceberg: self.BuyFlag = True self.MarketOrder(self.contract.Mapped, 1) self.askcooldown = False self.Log(f"ask counter: {symbolData.askCounter}") symbolData.askCounter = 0 symbolData.askIceberg = 0 if symbolData.bidCounter > 200 and self.bidcooldown: # and symbolData.bidPacman == symbolData.bidIceberg: self.BuyFlag = True self.MarketOrder(self.contract.Mapped, -1) self.bidcooldown = False self.Log(f"bid counter: {symbolData.bidCounter}") symbolData.bidCounter = 0 symbolData.bidIceberg = 0 def OnEndOfDay(self, symbol): #symbolData = self.symbolData[symbol] x = 5 #self.Debug(f"{symbol.Value}'s buy volume is {symbolData.buyVolume} and sell volume is {symbolData.sellVolume} for today") #self.Log(f"{symbol.Value}'s buy volume is {symbolData.buyVolume} and sell volume is {symbolData.sellVolume} for today") #self.v_quantity_window.Reset() #self.v_price_window.Reset() #self.Log(f"bid resets for today {self.bidreset}") #self.Log(f"ask resets for today {self.askreset}") #self.bidreset = 0 #self.askreset = 0 #self.Log(f"bid higher resets for today {self.pricehreset}") #self.Log(f"ask lower resets for today {self.pricelreset}") #self.pricehreset = 0 #self.pricelreset = 0 class SymbolData: def __init__(self): self.buyVolume = 0 self.sellVolume = 0 self.bidPrice = 0 self.askPrice = 0 self.bidCounter = 0 self.askCounter = 0 self.bidIceberg = 0 self.askIceberg = 0 self.bidSize = 0 self.askSize = 0 self.bidPacman = 0 self.askPacman = 0