#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, 1, 27) # Set Start Date
self.SetEndDate(2020, 2, 4)
self.SetCash(1000000) # 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)
#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 > 400 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 > 400 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
if len(self.orderIDs) > 0:
for position in self.orderIDs.itertuples():
if position.time + timedelta(hours=2) <= self.Time: #or (int(tick.Time.strftime('%H'))*60)+int(tick.Time.strftime('%M')) >= self.marketclose-15:
self.MarketOrder(self.contract.Mapped, (position.quantity)*-1,tag="2hr mark")
self.orderIDs = self.orderIDs[self.orderIDs.id != position.id] # remove row from df
if (int(tick.Time.strftime('%H'))*60)+int(tick.Time.strftime('%M')) >= self.marketclose-15:
for position in self.orderIDs.itertuples():
self.MarketOrder(self.contract.Mapped, (position.quantity)*-1,tag="End of Day")
self.orderIDs = self.orderIDs[self.orderIDs.id != position.id]
"""tick_df = self.PandasConverter.GetDataFrame[Tick](self.volume_window)"""
def OnOrderEvent(self, orderEvent):
if orderEvent.Status == OrderStatus.Filled and self.BuyFlag: #and orderEvent.StopPrice > 0:
x = pd.DataFrame([(orderEvent.OrderId, orderEvent.FillPrice, orderEvent.Quantity, self.Time)],columns=['id','fillprice','quantity','time'])
self.Log(f"dataframe to append: {x}")
self.orderIDs = self.orderIDs.append(x)
#self.Log(f"length of orders df: {len(self.orderIDs)}, 'time:',{self.Time}, 'time + 2hr:',{self.Time + timedelta(hours=2)}")
self.BuyFlag = False
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
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