Overall Statistics |
Total Trades 52 Average Win 0.06% Average Loss 0% Compounding Annual Return -21.236% Drawdown 1.600% Expectancy 0 Net Profit -1.278% Sharpe Ratio -4.07 Probabilistic Sharpe Ratio 2.346% Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha -0.009 Beta -0.206 Annual Standard Deviation 0.038 Annual Variance 0.001 Information Ratio -5.117 Tracking Error 0.17 Treynor Ratio 0.757 Total Fees $52.00 Estimated Strategy Capacity $0 Lowest Capacity Asset SPY 32577EAWK0TPI|SPY R735QTJ8XC9X |
# region imports from AlgorithmImports import * from QuantConnect.Securities.Option import OptionPriceModels # endregion class CalmVioletWhale(QCAlgorithm): def Initialize(self): self.SetStartDate(2022, 12, 25) # Set Start Date self.SetEndDate(datetime.now()) self.SetCash(100000) # Set Strategy Cash self.equity = self.AddEquity("SPY", Resolution.Minute) self.symbol = self.equity.Symbol self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw) self.SetBenchmark(self.symbol) self.SPYoption = self.AddOption("SPY", Resolution.Minute) # Strikes in the filter need to be made dynamic, a % on current price self.SPYoption.SetFilter(-150, 150, timedelta(0), timedelta(65)) self.SPYoption.PriceModel = OptionPriceModels.BjerksundStensland() self.targetdelta = 0.2 self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("SPY", 10), self.OpenCondor) underlyingPriceChart = Chart("Underlying Price") self.AddChart(underlyingPriceChart) underlyingPriceChart.AddSeries(Series("Underlying Price", SeriesType.Line)) underlyingPriceChart.AddSeries(Series("Call Strike Chosen", SeriesType.Line)) def OnData(self, data: Slice): pass def OpenCondor(self): def RoundBaseFive(x, base=5): return base * round(x/base) longPut = None shortPut = None shortCall = None longCall = None # Dynamically filter available options based on current underlying price filterLowerBound = int(self.Securities[self.symbol].Price * 0.7) filterUpperBound = int(self.Securities[self.symbol].Price * 1.3) self.SPYoption.SetFilter(filterLowerBound, filterUpperBound, timedelta(0), timedelta(65)) for i in self.CurrentSlice.OptionChains: chain = [x for x in i.Value] # If no option chain, return if (self.CurrentSlice.OptionChains.Count == 0): return # Sort option chain by expiration, choose furthest date expiry = sorted(chain, key = lambda x: x.Expiry)[-1].Expiry self.Log(str("Chosen expiry") + str(expiry)) # filter calls and puts call = [i for i in chain if i.Right == OptionRight.Call and i.Expiry == expiry] put = [i for i in chain if i.Right == OptionRight.Put and i.Expiry == expiry] # sort calls by delta call_sorted = sorted(call, key = lambda x: (x.Strike)) # get strike of call contract with target delta call_delta = min(call_sorted, key = lambda x: abs(x.Greeks.Delta - self.targetdelta)).Strike self.Log(str("Call Strike Chosen: ") + str(call_delta)) # round to nearest base 5 to get a more liquid strike call_strike = RoundBaseFive(call_delta) self.Log(str("Underlying Price") + str(self.Securities[self.symbol].Price)) # set long call strike +10 above call_strike_long = call_strike + 10 # select both calls shortCall = min(call_sorted, key = lambda x: abs(x.Strike - call_strike)) longCall = min(call_sorted, key = lambda x: abs(x.Strike - call_strike_long)) # -- Same for puts -- # sort puts by delta put_sorted = sorted(put, key = lambda x: (x.Strike), reverse=True) # get strike of put contract with target delta put_delta = min(put_sorted, key = lambda x: abs(x.Greeks.Delta <= -abs(self.targetdelta))).Strike self.Log(str("Put Strike Chosen: ") + str(put_delta)) # Round to nearest base 5 to get more liquid strike put_strike = RoundBaseFive(put_delta) self.Log(str("Put Strike Rounded: ") + str(put_strike)) # Set long put strike -10 below put_strike_long = put_strike - 10 # Select both puts shortPut = min(put_sorted, key = lambda x: abs(x.Strike - put_strike)) longPut = min(put_sorted, key = lambda x: abs(x.Strike - put_strike_long)) shortPutDelta = shortPut.Greeks.Delta self.Log(str("Short Put Delta: ") + str(shortPutDelta)) shortCallDelta = shortCall.Greeks.Delta self.Log(str("Short Call Delta: ") + str(shortCallDelta)) # Size the position based on premiums # Open the condor self.Buy(longCall.Symbol, 1) self.Sell(shortCall.Symbol, 1) self.Sell(shortPut.Symbol, 1) self.Buy(longPut.Symbol, 1) # order logic? Limit order, etc self.Plot("Underlying Price", "Underlying Price", self.Securities[self.symbol].Price) self.Plot("Call Strike Chosen", "Call Strike Chosen", call_delta)