class VolatilityRiskPremiumEffect(QCAlgorithm):
def Initialize(self):
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage)
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)
underlying = self.AddEquity("SPY", Resolution.Minute)
self.symbol = underlying.Symbol
option = self.AddOption("SPY", Resolution.Minute)
option.SetFilter(-20, 20, 25, 35)
self.last_day = -1
def OnData(self,slice):
# Check once a day.
if self.Time.day == self.last_day:
return
self.last_day = self.Time.day
for i in slice.OptionChains:
chains = i.Value
# checks if the portfolio is empty, if yes then it sells options
if not self.Portfolio.Invested:
# divide option chains into call and put options
calls = list(filter(lambda x: x.Right == OptionRight.Call, chains))
puts = list(filter(lambda x: x.Right == OptionRight.Put, chains))
# if lists are empty return
if not calls or not puts: return
# get the underlying price
underlying_price = self.Securities[self.symbol].Price
# determine expiration date nearly one month
expiries = [i.Expiry for i in puts]
expiry = min(expiries, key=lambda x: abs((x.date()-self.Time.date()).days-30))
# determine at-the-money strike
strikes = [i.Strike for i in puts]
strike = min(strikes, key=lambda x: abs(x-underlying_price))
# select the exact options we want
atm_call = [i for i in calls if i.Expiry == expiry and i.Strike == strike]
atm_put = [i for i in puts if i.Expiry == expiry and i.Strike == strike]
if atm_call and atm_put:
# calculate number of contracts to sell
options_q = int(self.Portfolio.MarginRemaining / (underlying_price * 100))
# sell at-the-money straddle
self.Sell(atm_call[0].Symbol, options_q)
self.Sell(atm_put[0].Symbol, options_q)
# after assigment, it liquidates our SPY position.
invested = [x.Key for x in self.Portfolio if x.Value.Invested]
if len(invested) == 1:
self.Liquidate(self.symbol)