from Execution.ImmediateExecutionModel import ImmediateExecutionModel
import pandas as pd
class CalibratedUncoupledRadiator(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
days = 0
def Initialize(self):
self.SetStartDate(2007, 1, 1)
self.SetEndDate(2020, 11, 19)
self.SetCash(100000)
#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.spy.SetLeverage(4)
self.UniverseSettings.MinimumTimeInUniverse = 10
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.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday), self.TimeRules.BeforeMarketClose("SPY", 0), self.ClosingBar)
self.SetExecution(ImmediateExecutionModel())
def OpeningBar(self):
for holding in self.Portfolio.Values:
if holding.Symbol != self.spy.Symbol and holding.Invested:
self.Error("Assignment/expiration failed")
self.Quit()
self.spyOption = None
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(self.spy.Symbol)
'''
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[self.spy.Symbol].Close)/high > self.withinYearlyHighPct:
self.Debug("Too far away from yearly high: " + str(self.Securities[self.spy.Symbol].Close) + " vs " + str(high))
return
options = self.OptionChainProvider.GetOptionContractList(self.spy.Symbol, self.Time)
if options is None or len(options) == 0:
self.Error("No options found")
return
callsExpiringToday = [o for o in options if o.ID.Date.date() == self.Time.date() and o.ID.OptionRight == OptionRight.Call]
sortedByStrike = sorted(callsExpiringToday, key = lambda o: o.ID.StrikePrice)
for option in sortedByStrike:
id = option.ID
if id.StrikePrice >= self.Securities[self.spy.Symbol].Open + self.callOtmAmount:
self.spyOption = self.AddOptionContract(option, Resolution.Minute)
self.Debug(str(id.Date) + " " + str(id.StrikePrice) + " " + str(id.OptionRight))
break
'''
if self.days > 30:
self.Quit()
self.days = self.days+1
'''
def ClosingBar(self):
self.spyOption = None
def OnData(self, slice):
if self.spyOption is not None and self.Securities[self.spyOption.Symbol].Price != 0:
self.MarketOrder(self.spyOption.Symbol, -5)
self.spyOption = None
return
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))