Overall Statistics
Total Trades
1602
Average Win
0.00%
Average Loss
0.00%
Compounding Annual Return
0.187%
Drawdown
0.100%
Expectancy
0.936
Net Profit
0.378%
Sharpe Ratio
1.186
Probabilistic Sharpe Ratio
62.576%
Loss Rate
32%
Win Rate
68%
Profit-Loss Ratio
1.83
Alpha
0.001
Beta
-0.003
Annual Standard Deviation
0.001
Annual Variance
0
Information Ratio
-0.357
Tracking Error
0.152
Treynor Ratio
-0.446
Total Fees
$3444.30
Estimated Strategy Capacity
$0
Lowest Capacity Asset
ES XKGCMV4QK9VL
#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(1000000000)  # Set Strategy Cash
        self.symbolData = {}

        self.canLong = True
        self.canShort = True

        self.contract = self.AddFuture(Futures.Indices.SP500EMini , 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)
        self.marketclose = 17*60
        self.tickcount = 0

        """ test which method is better """
        self.askcooldown = True
        self.bidcooldown = True
        self.askcooldown = datetime(2000,7,6,10,0,0)
        self.bidcooldown = datetime(2000,7,6,10,0,0)

        self.bidreset = 0
        self.askreset = 0
        self.pricehreset = 0
        self.pricelreset = 0
        self.tickcount = 0

        self.ticklist = []
        self.askLimitTicket = 0
        self.bidLimitTicket = 0
        self.asklock = 0
        self.bidlock = 0
        self.ask_ice_exp = 0
        self.ask_ice_exp = 0
        self.askice0reset =0
        self.bidice0reset =0

        self.dbug = False #delete
            
    """ need to add code that will trigger after close and have a 5 min cooldown after open to start algo  """
    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}")

        #if self.ask_ice_exp == 0:
        #    self.ask_ice_exp = self.Time + timedelta(minutes=5)
        #if self.bid_ice_exp == 0:
        #    self.bid_ice_exp = self.Time + timedelta(minutes=5)
            
        #if contract.Exchange.
        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

                    #delete this
                    #if int(self.Time.strftime('%H')) == 1 and int(self.Time.strftime('%M')) == 33 and int(self.Time.strftime('%S')) == 1 and self.dbug:
                    #    self.Log(f'tick price current: {tick.Price}')
                    #    self.Log(f'time {self.Time} ice {symbolData.askIceberg} count {symbolData.askCounter}')
                    #if int(self.Time.strftime('%H')) == 12 and int(self.Time.strftime('%M')) == 43 and int(self.Time.strftime('%S')) == 1 and self.dbug:
                    #    self.Log(f'tick price current: {tick.Price}')

                    def ask_count_reset():
                        symbolData.askCounter = 0
                        if not self.askLimitTicket == 0:
                            askTag = str(symbolData.askCounter)
                            self.askLimitTicket.Cancel(askTag)
                            self.askLimitTicket = 0
                            #self.askcooldown = True
                            #self.ask_ice_exp = self.Time + timedelta(minutes=5)

                    def bid_count_reset():
                        symbolData.bidCounter = 0
                        if not self.bidLimitTicket == 0:
                            bidTag = str(symbolData.bidCounter)
                            self.bidLimitTicket.Cancel(bidTag)
                            self.bidLimitTicket = 0
                            #self.bidcooldown = True
                            #self.bid_ice_exp = self.Time + timedelta(minutes=5)


                    #if self.ask_ice_exp < self.Time:
                    #    ask_count_reset()
                    #    symbolData.askIceberg = 0
                    #    self.Log(f'test ask reset 5 min')

                    #if self.bid_ice_exp < self.Time:
                    #    bid_count_reset()
                    #    symbolData.bidIceberg = 0
                    #    self.Log(f'test bid reset 5 min')


                    if symbolData.bidIceberg == 0 and symbolData.bidPrice != 0: 
                        bid_count_reset()
                        symbolData.bidIceberg = symbolData.bidPrice
                        self.bidice0reset += 1
                        
                    if tick.Price < symbolData.bidIceberg:
                        bid_count_reset()
                        symbolData.bidIceberg = tick.Price
                        self.pricelreset += 1

                    if tick.Price == symbolData.bidIceberg:
                        symbolData.bidCounter += tick.Quantity

                    if tick.Price > symbolData.bidIceberg / 0.995:
                        bid_count_reset()
                        symbolData.bidIceberg = 0
                        self.bidreset += 1 #delete
                        
                    if symbolData.askIceberg == 0 and symbolData.askPrice != 0:
                        ask_count_reset()
                        symbolData.askIceberg = symbolData.askPrice
                        self.askice0reset += 1
                        
                    if tick.Price > symbolData.askIceberg:
                        ask_count_reset()
                        symbolData.askIceberg = tick.Price
                        self.pricehreset += 1

                    if tick.Price == symbolData.askIceberg:
                        symbolData.askCounter += tick.Quantity
                    if tick.Price < symbolData.askIceberg * 0.995:
                        ask_count_reset()
                        symbolData.askIceberg = 0
                        self.askreset += 1 #delete

                    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 > 700 and tick.Time > self.askcooldown and self.asklock != symbolData.askIceberg and not self.contract.Exchange.IsClosingSoon(75): #and symbolData.askPacman == symbolData.askIceberg:
                    
                    self.MarketOrder(self.contract.Mapped, 1)
                    #self.askcooldown = False
                    self.askcooldown = tick.Time + timedelta(minutes=5)
                    self.Log(f"ask counter: {symbolData.askCounter}")
                    self.Log(f"ask lock: {self.asklock}")
                    self.asklock = symbolData.askIceberg

                    #symbolData.askCounter = 0
                    #symbolData.askIceberg = 0
                    self.askLimitTicket = self.LimitOrder(self.contract.Mapped, 1, 1)
                    #self.Log(f'is closing soon {self.contract.Exchange.IsClosingSoon(75)}')
                    
                    
                if symbolData.bidCounter > 700 and tick.Time > self.bidcooldown and self.bidlock != symbolData.bidIceberg and not self.contract.Exchange.IsClosingSoon(75): # and symbolData.bidPacman == symbolData.bidIceberg:

                    self.MarketOrder(self.contract.Mapped, -1)
                    #self.bidcooldown = False
                    self.bidcooldown = tick.Time + timedelta(minutes=5)
                    self.Log(f"bid counter: {symbolData.bidCounter}")
                    self.Log(f"bid lock: {self.bidlock}")
                    self.bidlock = symbolData.bidIceberg
                    #symbolData.bidCounter = 0
                    #symbolData.bidIceberg = 0
                    self.bidLimitTicket = self.LimitOrder(self.contract.Mapped, 1, 1)
                    #self.Log(f'is closing soon {self.contract.Exchange.IsClosingSoon(75)}')
                    


                    
        
    
    def OnEndOfDay(self, symbol):
        symbolData = self.symbolData[symbol]
        #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
        self.Log(f"bid 0 resets for today {self.bidice0reset}")
        self.Log(f"ask 0 resets for today {self.askice0reset}")
        self.bidice0reset = 0
        self.askice0reset = 0
        self.askcooldown = datetime(2000,7,6,10,0,0)
        self.bidcooldown = datetime(2000,7,6,10,0,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