Overall Statistics |
Total Trades 1309 Average Win 1.28% Average Loss -1.97% Compounding Annual Return 0% Drawdown 100.200% Expectancy -0.155 Net Profit -100.240% Sharpe Ratio -0.441 Probabilistic Sharpe Ratio 0.102% Loss Rate 49% Win Rate 51% Profit-Loss Ratio 0.65 Alpha -1.089 Beta 0.437 Annual Standard Deviation 2.262 Annual Variance 5.115 Information Ratio -0.534 Tracking Error 2.262 Treynor Ratio -2.279 Total Fees $1309.00 Estimated Strategy Capacity $220000.00 Lowest Capacity Asset SPY Y5ANA5ND7886|SPY R735QTJ8XC9X |
# region imports from AlgorithmImports import * from datetime import timedelta #from QuantConnect.Data.Custom.CBOE import * # endregion class HyperActiveTanCow(QCAlgorithm): def Initialize(self): self.SetStartDate(2022, 10, 22) # Set Start Date self.SetEndDate(2023, 2, 25) self.SetCash(5000) # Set Strategy Cash self.equity = self.AddEquity("SPY", Resolution.Minute) # Add the underlying stock: Spy self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw) option = self.AddOption("SPY", Resolution.Minute) # Add the option corresponding to underlying stock self.symbol = option.Symbol #can now symbol back and forth self.contract = str() self.contractsAdded = set() #create array to track n amount of 2min ewo bars self.ewoTracker = [] #this is the array iterator to count each entry space/element self.i = -1 self.needToPop = False self.haveHoldings = False self.buyBar = 0 self.buyCallFlag = False self.inCall = False self.sellCall = False #Have the algo only look at contracts that are 1 row below the strike price and 0dte #option.SetFilter(-1, 1, timedelta(0), timedelta(1)) option.SetFilter(-1, 0, timedelta(0), timedelta(0)) #Create two min consolidator, attach event handler for every 2min, then add consolidator to the engines subscription manager for updates twoMinConsolidator = TradeBarConsolidator(timedelta(minutes=2)) twoMinConsolidator.DataConsolidated += self.TwoMinBarHandler self.SubscriptionManager.AddConsolidator("SPY", twoMinConsolidator) #Create EMA indicators self.ema5 = ExponentialMovingAverage(5, 0.33) self.ema35 = ExponentialMovingAverage(35, 0.055) #Have indicator work w 2min bars self.RegisterIndicator("SPY", self.ema5, twoMinConsolidator) self.RegisterIndicator("SPY", self.ema35, twoMinConsolidator) #Create a scheduled event that sells all holdings before close of day self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 1), self.ClosePositions) def OnData(self, data: Slice): #Ensure indicators are warmed up if not self.ema5.IsReady and self.ema35.IsReady: self.Debug("Indicators not ready") return self.Plot("ExponentialMovingAverage", "ema5", self.ema5.Current.Value) self.Plot("ExponentialMovingAverage", "ema35", self.ema35.Current.Value) #Track for sell #check to see if we have any open option positions, check by making a list of invested securities that are option type option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type == SecurityType.Option] if self.buyCallFlag: self.Debug("if buyCallFlag" + str(self.Time)) chains = str() for j in data.OptionChains: self.Debug(str(j) + "1") chains = j.Value self.Debug(str(j) + "2") self.BuyCall(chains) self.Debug(str(j) + "3") if chains == str(): self.Debug("Empty chain") self.Debug("if buyCallFlag3" + str(self.Time)) self.buyCallFlag = False self.contract = str() return def TwoMinBarHandler(self, sender, consolidated): #ema5 - ema35 to get 2minEWO value self.twoMinEWO = float(self.ema5.Current.Value - self.ema35.Current.Value) #Add current ewo bar to array to track n most recent (still need to implement pop) self.ewoTracker.append(self.twoMinEWO) self.i += 1 #Deciding Entry (ONLY with CALLS) #took out my strategy but feel free to implement some arbitrary buy signal for testing purposes if (self.i >= 3): self.buyCallFlag = True self.Debug("buyCallFlag True " + str(self.Time)) self.buyBar = self.i self.inCall = True #self.MarketOrder("SPY", 100) #Call BuyCall function if self.inCall: if(self.i == 8): #again had to take out the strategy and put something random in there #self.Sell(self.call.Symbol, 1) #self.Sell(option_invested[0], 1) self.sellCall = True self.inCall = False self.Liquidate() #self.buyCallFlag = False #Buy Call Function def BuyCall(self, chains): #If before 1pm, buy 0dte if self.Time.hour < 13: #sorts available chain by expiration date, and pick the closest expiration date expiry = sorted(chains, key = lambda x: x.Expiry, reverse=False)[0].Expiry self.Debug("The expiry is " + str(expiry)) #self.Debug(str(self.Time)) #Filter out only call options with those expiration dates calls = [i for i in chains if i.Expiry == expiry and i.Right == OptionRight.Call] #Sort by strike price, closest to the underlyings price. This is sorted from closest to farthest away from underlying price call_contracts = sorted(calls, key = lambda x: abs(x.Strike - x.UnderlyingLastPrice)) #self.Debug(str(self.call.UnderlyingLastPrice)) #df = pd.DataFrame([[x.Right,x.Strike,x.Expiry,x.BidPrice,x.AskPrice] for x in call_contracts], #index=[x.Symbol.Value for x in call_contracts], #columns=['type(call 0, put 1)', 'strike', 'expiry', 'ask price', 'bid price']) #self.Log(str(df)) #IF after 1pm, buy 1dte elif self.Time.hour >= 13: self.buyCallFlag = False return #sorts available chain by expiration date, and pick the furthest expiration date #expiry = sorted(chains, key = lambda x: x.Expiry, reverse=True)[0].Expiry #self.Debug("The expiry is " + str(expiry)) #self.Debug(str(self.Time)) #Filter out only call options with those expiration dates #calls = [i for i in chains if i.Expiry == expiry and i.Right == OptionRight.Call] #Sort by strike price, closest to the underlyings price. This is sorted from closest to farthest away from underlying price #call_contracts = sorted(calls, key = lambda x: abs(x.Strike - x.UnderlyingLastPrice)) #if list is not empty, save the first element to the call option variable if len(call_contracts) == 0: self.Debug("No available contracts") self.buyCallFlag = False return self.call = call_contracts[0] self.Debug("The call to buy is " + str(self.call) + ". The underlying price is " + str(self.call.UnderlyingLastPrice) + ", and the strike price is " + str(self.call.Strike) + " at " + str(self.Time)) #calculate order quantity #quantity = self.Portfolio.TotalPortfolioValue / self.call.AskPrice #quantity = int(0.05 * quantity / 100) #buy the option self.Buy(self.call.Symbol, 1) self.LimitOrder(self.call.Symbol, -1, (self.call.AskPrice * 1.1)) self.StopMarketOrder(self.call.Symbol, -1, (self.call.AskPrice * 0.8)) self.avgPrice = self.call.AskPrice self.buyCallFlag = False #Liquidate any holdings before close of day def ClosePositions(self): self.i = -1 self.ewoTracker = [] if self.Portfolio.Invested: self.Liquidate() def OnOrderEvent(self, orderEvent): order = self.Transactions.GetOrderById(orderEvent.OrderId) if order.Type == OrderType.OptionExercise: self.Debug(f"{orderEvent.Symbol} Profit: {self.Portfolio[orderEvent.Symbol].Profit}, Total Profit: {self.Portfolio.TotalProfit}")