Hello guys, can you help me plzzzz..
While testing one options based strategy I encountered an error:
Runtime Error: Exception has been thrown by the target of an invocation. symbol must not contain the characters '|' or ' '.
Parameter name: symbol (Open Stacktrace)
I had the same error before and found out that somehow the options chain request returned a option symbol with a outdated expiry.
This time the symbol (expiry) is ok, but when I place market order, I get this error.
Here I attached the script. It's simplified and does the following:
1. If not invested, it shorts (-1) ATM PUT on SPY with expiry around 1 month.
2. If the PUT is assigned and I get 100 shares of SPY, I place a short ATM CALL option (on SPY) market order.
In this specifically attached script this CALL encounters the error, although I see that the symbol wise it looks ok (when looking in Debug mode).. I couldn't attach backtest by some reason.
Thank you! pls look below for the code:
import pandas as pd
import datetime
class LtShortPuts(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 3, 2) # Set Start Date
self.SetEndDate(2020, 3 , 31)
self.SetCash(100000) # Set Strategy Cash
self.last_slice = None
self.strike = 0
self.stock = "SPY"
self.fillPrice = 0
self.tradingAllowed = False
self.tradingDay = False
self.dt = None
#self.optTrades = pd.DataFrame(columns = ['type', 'symbol', 'price', 'qty', 'underPrice'])
equity = self.AddEquity(self.stock, Resolution.Minute)
equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
option = self.AddOption(self.stock, Resolution.Minute)
self.symbol = option.Symbol
option.SetFilter(lambda universe: universe.IncludeWeeklys().Strikes(-1, 1).Expiration(timedelta(27), timedelta(35)))
# Init
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(9, 30), Action(self.Init))
# check SPY closing price
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(15, 59), Action(self.CheckClose))
def GetOptionContract(self, strike):
# Returns call/put contracts and their details for the given strike
for i in self.last_slice.OptionChains:
if i.Key != self.symbol: continue
optionchain = i.Value
call = [x for x in optionchain if x.Right == 0]
callContract = [x for x in call if x.Strike == strike][0]
call_symbol = callContract.Symbol.Value
put = [x for x in optionchain if x.Right == 1]
putContract = [x for x in put if x.Strike == strike][0]
put_symbol = putContract.Symbol.Value
call_bid = callContract.BidPrice
call_ask = callContract.AskPrice
put_ask = putContract.AskPrice
put_bid = putContract.BidPrice
return(call_symbol, call_bid, call_ask, put_symbol, put_bid, put_ask)
def Init(self):
self.call_ready = False
self.put_ready = False
self.call_symb = None
self.put_symb = None
def CheckClose(self):
stockPrice = self.Securities[self.stock].Close
self.Log("Closing price: " + str(stockPrice))
def CheckOptions(self):
stockPrice = self.Securities[self.stock].Close
self.strike = round(stockPrice)
self.Log("Strike: " + str(self.strike))
self.dt = self.Time.date()
self.Log("Today: " + str(self.dt))
try:
call_symbol, call_bid, call_ask, put_symbol, put_bid, put_ask = self.GetOptionContract(self.strike)
self.tradingDay = True
self.Log("Trading day lah! Call_symbol: {0}, Put symbol: {1}".format(call_symbol, put_symbol))
d = call_symbol[6:12]
self.dateOfSymbol = datetime.datetime.strptime(d, "%y%m%d").date()
self.Log("Date of symbol: " + str(self.dateOfSymbol))
# I encountered problem before with the same error, and found out that algorithm tried to call options with expired dates
# so here I check whether the expiration date is ahead of the current date
if self.dateOfSymbol < self.dt:
self.Log("Problem!!!!!!! Today is: {0}, but option requested is: {1} ".format(str(self.Time.date(), call_symbol)) )
self.tradingDay = False
except:
self.Log("Not a trading day lahh!")
self.tradingDay = False
#self.Log("CheckOption tradingDay: " + str(self.tradingDay))
def OnData(self, slice):
if (self.Time.hour == 10 and self.Time.minute == 00):
invested = [ x.Symbol.Value for x in self.Portfolio.Values if x.Invested ]
self.Log("invested: " + str(invested))
if len(invested) == 0:
self.last_slice = slice
self.CheckOptions()
if self.tradingDay:
try:
call_symbol, call_bid, call_ask, put_symbol, put_bid, put_ask = self.GetOptionContract(self.strike)
except:
self.Log("Exception!")
marketTicket = self.MarketOrder(put_symbol, -1)
#marketTicket = self.MarketOrder(call_symbol, -1)
#marketTicket = self.MarketOrder(self.stock, 100)
self.fillPrice = marketTicket.AverageFillPrice
self.Debug("Open position Fill Price: {0}".format(self.fillPrice))
elif len(invested)>2: # something went wrong
self.Log("SOMETHING WENT WRONG. LIQUIDATING ALL POSITIONS!")
self.Liquidate()
else:
for opt in invested:
if (opt == 'SPY' and len(invested) == 1):
price = self.Portfolio[self.stock].Price
self.Log("We have only SPY position priced at {0} and need to add CALL".format(price))
self.last_slice = slice
self.CheckOptions()
if self.tradingDay:
try:
call_symbol, call_bid, call_ask, put_symbol, put_bid, put_ask = self.GetOptionContract(self.strike)
self.call_ready = True
self.call_symb = call_symbol
except:
self.Log("Exception!")
'''
try:
marketTicket = self.MarketOrder(call_symbol, -1)
self.fillPrice = marketTicket.AverageFillPrice
self.Debug("Opened short CALL for: {0}".format(self.fillPrice))
except:
pass
'''
# !!!!!!!!!!!!!!!!!!
# This is where it get error about wrong symbol
# ---------------------------------------------
if (self.Time.hour == 10 and self.Time.minute == 10):
if self.call_ready:
marketTicket = self.MarketOrder(self.call_symb, -1)
self.fillPrice = marketTicket.AverageFillPrice
self.Debug("Opened short CALL for: {0}".format(self.fillPrice))
Iouri Verchok
I think I found the solution. I expanded number of strikes in option.SetFilter .. Seems like it helped:
option.SetFilter(lambda universe: universe.IncludeWeeklys().Strikes(-40, 40).Expiration(timedelta(27), timedelta(35)))
Iouri Verchok
When doing wider dates backtest, the error still pops up even with strikes pool from -60 to 60 from ATM.. So, unfortunately, problem persists :(
Rahul Chowdhury
Hey Iouri,
The error is being caused because self.call_symb refers to the ticker of the contract rather than the Symbol object. It is best practice to use the Symbol object to identify securities rather than the ticker. I updated self.GetOptionContract with
call_symbol = callContract.Symbol put_symbol = putContract.Symbol
and self.CheckOptions with
d = call_symbol.ID.Date
This lets you access the expiry date for that contract.
Learn more about symbols and tickers in the security identifiers documentation.
Best
Rahul
Iouri Verchok
Hi Rahul,
Thanks a lot !
Iouri Verchok
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!