| 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