Hi there,
I had a recent discussion earlier, and got some help, but wasn't able to complete the whole goal afterwards.
I spliced the call sales into a long term P/B strategy, but am having trouble adding the put sales in too. Goal is to sell cash secured puts until eventually they get filled, then start selling covered calls on those shares. Is there any way to add them in and sell them at 20% below market price?
I will send you some cash via venmo or paypal as gratuity, just leave your username in there.
Thanks for any and all help :)
# Fundemental Data and Technical indicators
from AlgorithmImports import *
class VerticalQuantumInterceptor(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022, 1, 1)
self.SetEndDate(2022, 6, 16)
self.SetCash(100000)
resolution = Resolution.Daily
self.UniverseSettings.Resolution = resolution
self.AddUniverse(self.CoarseSelection, self.FineSelection)
self.symbols = [self.AddEquity(x, resolution).Symbol
for x in ["X", "F", "JPM", "LKQ", "ALLY"]]
self.tickers = ["X", "F", "JPM", "LKQ", "ALLY"]
for ticker in self.tickers:
equity = self.AddEquity(ticker, Resolution.Daily)
equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.stocks = []
self.macd = {}
self.call = str()
for sec in self.symbols:
self.macd[sec] = self.MACD(sec, 12, 26, 9, Resolution.Daily)
def CoarseSelection(self, coarse):
selected = [x for x in coarse if (x.HasFundamentalData) and (float(x.Price) > 10)]
static = [x.Symbol for x in selected if (x.Symbol in self.symbols)]
self.Plot("Universe", "static", len(static))
return static
def FineSelection(self, fine):
pb_ratio_filter = [x.Symbol for x in fine if x.ValuationRatios.PBRatio > 0 and (x.ValuationRatios.PBRatio < 1)]
self.stocks = pb_ratio_filter
self.Plot("Universe", "pb_ratio_filter", len(pb_ratio_filter))
return self.stocks
def UniverseFunc(self, universe):
put = put.SetFilter(-2, 2, timedelta(0), timedelta(182))
call = call.SetFilter(-2, 2, timedelta(0), timedelta(182))
return call, put
def OnData(self, data):
selected = []
for sec in self.stocks:
if self.macd[sec].Current.Value > self.macd[sec].Signal.Current.Value:
selected.append(sec)
self.Plot("Universe", "macd_filter", len(selected))
for sec in self.Portfolio.Keys:
if sec not in selected:
#self.SetHoldings(sec, 0 )
self.Log("Potential Downturn")
for sec in selected:
wt = 1.0/len(selected) if len(selected) > 0 else 0
if self.Portfolio[sec].Quantity == 0:
self.SetHoldings(sec, .05 )
for underlying in self.tickers:
self.underlying = underlying
if self.Portfolio[self.underlying].Invested:
# self.SetHoldings(self.underlying, 0.05) # long the underlying stock
if not (self.Securities.ContainsKey(self.call) and self.Portfolio[self.underlying].Invested):
self.call = self.AddContract(slice) # Add the call option contract (subscribe the contract data)
if self.Securities.ContainsKey(self.call) and not self.Portfolio[self.call].Invested:
self.SetHoldings(self.call, -.005) # short the call option
self.call = str()
#############################################
def AddContract(self,slice):
filtered_contracts = self.InitialFilter(-3, 3, 0, 30)
if len(filtered_contracts) == 0: return str()
else:
call = [x for x in filtered_contracts if x.ID.OptionRight == OptionRight.Call]
# sorted the contracts according to their expiration dates and choose the ATM options
contracts = sorted(sorted(call, key = lambda x: abs(self.Securities[self.underlying].Price- x.ID.StrikePrice)),
key = lambda x: x.ID.Date, reverse=True)
if len(contracts) > 0:
self.AddOptionContract(contracts[0], Resolution.Minute)
return contracts[0]
else:
return str()
###############################################################
def InitialFilter(self, min_strike_rank, max_strike_rank, min_expiry, max_expiry):
''' This method is an initial filter of option contracts
according to the range of strike price and the expiration date '''
contracts = self.OptionChainProvider.GetOptionContractList(self.underlying, self.Time.date())
if len(contracts) == 0 : return []
# fitler the contracts based on the expiry range
contract_list = [i for i in contracts if min_expiry < (i.ID.Date.date() - self.Time.date()).days < max_expiry]
# find the strike price of ATM option
atm_strike = sorted(contract_list,
key = lambda x: abs(x.ID.StrikePrice - self.Securities[self.underlying].Price))[0].ID.StrikePrice
strike_list = sorted(set([i.ID.StrikePrice for i in contract_list]))
# find the index of ATM strike in the sorted strike list
atm_strike_rank = strike_list.index(atm_strike)
try:
strikes = strike_list[(atm_strike_rank + min_strike_rank):(atm_strike_rank + max_strike_rank)]
except:
strikes = strike_list
filtered_contracts = [i for i in contract_list if i.ID.StrikePrice in strikes]
return filtered_contracts
#########################################
def OnOrderEvent(self, orderEvent):
self.Log(str(orderEvent))
def TradeOptions(self,slice):
for underlying in self.tickers:
self.underlying = underlying
optionchain = self.OptionChainProvider.GetOptionContractList(self.underlying, self.Time.date())
put = [x for x in optionchain if x.Right == OptionRight.Put]
price = optionchain.Underlying.Price
contracts = [x for x in put if price - x.Strike > 0]
contracts = sorted(contracts, key = lambda x: x.Expiry, reverse = True)
if len(contracts) == 0:
continue
symbol = contracts[0].Symbol
self.Sell(symbol, 1)
Louis Szeto
Hi Christian
You might want to take a look into the Protective Collar option strategy in the docs. Tweak the implementation with respect to the option universe, ordering time and strike price shall do what you wish for.
Best
Louis
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Christian Olsen
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!