from Execution.ImmediateExecutionModel import ImmediateExecutionModel
import pandas as pd
class OptimizedTachyonShield(QCAlgorithm):
'''
If SPY is within a certain % of its 52W high, write a call option that is a certain $ above the opening price.
If the option gets assigned, do a limit order for covering at the assignment price.
Pre
'''
# Paramaters
callOtmAmount = 6
withinYearlyHighPct = 10
spy = None
spyOption = None
spyCoverOrderTicket = None
yearlyHigh = None
def Initialize(self):
self.SetStartDate(2000, 1, 1) # Set Start Date
self.SetEndDate(2020, 11, 19) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
#self.callOtmAmount = int(self.GetParameter("callOtmAmount")) # TODO deal with missing parameter
self.spy = self.AddEquity("SPY", Resolution.Minute)
self.spy.SetDataNormalizationMode(DataNormalizationMode.Raw) # Required for working with options
self.spyOption = self.AddOption("SPY")
# Include weekly options, only calls, strikes within underlying price + otmAmount, expiring in next 1 days
self.spyOption.SetFilter( lambda u: u.IncludeWeeklys().CallsOnly().Strikes(self.callOtmAmount, self.callOtmAmount+2).Expiration(0, 1) )
self.yearlyHigh = self.MAX(self.spy.Symbol, 252, Resolution.Daily)
history = self.History(self.spy.Symbol, 252, Resolution.Daily)
for bar in history.itertuples():
self.yearlyHigh.Update(bar.Index[1], bar.high)
self.Debug("SPY yearly high warmed up, value = " + str(self.yearlyHigh.Current.Value))
self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday), self.TimeRules.AfterMarketOpen("SPY", 1), self.OpeningBar)
self.SetExecution(ImmediateExecutionModel())
def OpeningBar(self):
if not self.IsMarketOpen(self.spy.Symbol):
self.Debug("Market not open, returning")
return
self.LogPortfolio()
if self.Portfolio[self.spy.Symbol].Invested:
self.Liquidate("SPY")
'''
if self.spyCoverOrderTicket is None:
self.Debug("Assigned, placing limit order to cover")
self.spyCoverOrderTicket = self.LimitOrder(self.spy.Symbol, -1 * self.Portfolio["SPY"].Quantity, self.Portfolio["SPY"].AveragePrice)
return
'''
high = self.yearlyHigh.Current.Value
if 100 * (high - self.Securities["SPY"].Close)/high > self.withinYearlyHighPct:
self.Debug("Too far away from yearly high: " + str(self.Securities["SPY"].Close) + " vs " + str(high))
return
slice = self.CurrentSlice
optionChain = slice.OptionChains.GetValue(self.spyOption.Symbol)
if optionChain is None:
self.Error(str(self.Time) + " No option chain found")
return
allContracts = [o for o in optionChain]
expiringToday = [o for o in optionChain if o.Expiry.date() == self.Time.date()]
sortedByStrike = sorted(expiringToday, key = lambda o: o.Strike)
if len(sortedByStrike) > 0:
self.MarketOrder(sortedByStrike[0].Symbol, -5)
def OnOrderEvent(self, orderEvent):
self.Debug(str(orderEvent))
if not self.spyCoverOrderTicket is None and orderEvent.OrderId == self.spyCoverOrderTicket.OrderId and self.spyCoverOrderTicket.Status == OrderStatus.Filled:
self.Debug("covered!")
self.spyCoverOrderTicket = None
def LogPortfolio(self):
for symbol in self.Portfolio.Keys:
holding = self.Portfolio[symbol]
if holding.Invested:
self.Debug(str(symbol) + " " + str(holding.Quantity) + " @ " + str(holding.AveragePrice))
def LogContracts(self, optionChain):
df = pd.DataFrame(
[[x.Right,float(x.Strike),x.Expiry,float(x.BidPrice),float(x.AskPrice)] for x in optionChain],
index=[x.Symbol.Value for x in optionChain],
columns=['type(call 0, put 1)', 'strike', 'expiry', 'ask price', 'bid price']
)
self.Debug(str(df))