Overall Statistics |
Total Trades 4 Average Win 1.32% Average Loss -0.30% Compounding Annual Return 294.636% Drawdown 0.500% Expectancy 1.664 Net Profit 1.008% Sharpe Ratio 14.12 Probabilistic Sharpe Ratio 0% Loss Rate 50% Win Rate 50% Profit-Loss Ratio 4.33 Alpha 5.949 Beta -1.822 Annual Standard Deviation 0.182 Annual Variance 0.033 Information Ratio 2.528 Tracking Error 0.282 Treynor Ratio -1.409 Total Fees $56.00 |
from datetime import timedelta class OptionsTest(QCAlgorithm): def Initialize(self): self.lastDayTraded = None self.SetStartDate(2020, 12, 2) self.SetEndDate(2020, 12, 6) self.SetCash(100000) self.equity = self.AddEquity("SPY", Resolution.Minute) self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw) option = self.AddOption("SPY") self.option_symbol = option.Symbol # set our strike/expiry filter for this option chain # FIXME: If I change timedelta(1) to timedelta(0), sometimes it grabs contracts that already expired option.SetFilter(lambda universe: universe.IncludeWeeklys().Strikes(-5, +5).Expiration(timedelta(1), timedelta(6))) # use the underlying equity as the benchmark self.SetBenchmark("SPY") # Rolling window of close prices for detecting dips self.close = RollingWindow[float](3) def OnData(self,slice): # Conditions when we don't want to open a new position if self.lastDayTraded == self.Time.date(): return if not slice.ContainsKey("SPY"): return if self.Time.hour != 9 or self.Time.minute != 55: return for kvp in slice.OptionChains: if kvp.Key != self.option_symbol: continue chain = kvp.Value # we sort the call contracts to find at the money (ATM) contract with soonest expiration contracts = sorted(sorted(sorted(chain, key = lambda x: abs(chain.Underlying.Price - x.Strike)), key = lambda x: x.Expiry, reverse=False), key = lambda x: x.Right, reverse=False) # Order calls first # If found, trade it if len(contracts) < 1: continue contract = contracts[0] # FIXME: Why are the prices so different (sometimes) here vs Yahoo Finance? self.Log(f"contract={contract}; bid={contract.BidPrice}; ask={contract.AskPrice}") # Open position and stop loss order size = 56 symbol = contract.Symbol stopPrice = contract.AskPrice * 0.5 self.MarketOrder(symbol, size) self.StopMarketOrder(symbol, -size, stopPrice) # Keep track if we traded today so we don't repeat self.lastDayTraded = self.Time.date() # Close position in 13 mins, cancels stop loss order if it's open self.Schedule.On(self.DateRules.Today, self.TimeRules.At(self.Time.hour, self.Time.minute + 13), self.Liquidate) return