| 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)