Good afternoon,
I am working on an algorithm that involves options trading from a coarse and fine selected universe and keep running into this error:
Runtime Error: symbol must not contain the characters '|' or ' '. (Parameter 'symbol') in SecurityIdentifier.cs:line 327
When i add symbols manually in initialize and run the algorithm I don't receive the error, but when I try and trade symbols added in the universe selection model the error keeps popping up. Any help would be appreciated, I cannot attach backtest because it did not finished but I will paste code here.
#region imports
from AlgorithmImports import *
#endregion
import datetime #import timedelta, time
from datetime import datetime
import math
import time as t
from AlgorithmImports import *
from QuantConnect.Data.UniverseSelection import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
holidays = [2021-11-26, 2022-11-25, 2023-11-25, 2023-7-3]
selected = []
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Symbol Data
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
class SymbolData(object):
def __init__(self, algorithm, symbol, criteriaDict):
self.symbol = symbol
self.symbolValue = symbol.Value
self.algorithm = algorithm
self.criteriaDict = criteriaDict
self.highestTrailStopPrice = -1
self.tradeLock = False
self.current = None
self.smaDictionary = {}
self.selectedSymbols = {}
self.avg = {}
self.BuyIn = {}
class ErrorSubmission_TrailStop(QCAlgorithm):
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Iniitalization
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
def Initialize(self):
#-- Date Range
self.SetStartDate(2021, 1, 1) # Set Start Date
self.SetEndDate(2021, 2, 1) # Set End Date
#-- Starting Equity
self.SetCash(10000) # Set Strategy Cash # check if will be replaced
self.UniverseSettings.Resolution = Resolution.Minute
self.AddUniverse(self.CoarseFilterSelection, self.FineFilterSelection)
self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))
self.criteriaDict = {
}
self.averages = {}
self.smavolume = {}
self.purchased_options = []
self.symbolDict = {}
self.symbolWithPositionDict = {}
self.lock = {}
self.SetWarmUp(200, Resolution.Minute)
self.sm = {}
self.smavol = {}
self.BuyIn = {}
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
OnData
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
def OnSecuritiesChanged(self, changes):
for security in changes.RemovedSecurities:
if ((security.Symbol in self.symbolDict) and (security.Symbol not in self.symbolWithPositionDict) and (security.Symbol not in selected) and (security.Symbol not in self.purchased_options)):
symbolData = self.symbolDict[security.Symbol]
del self.symbolDict[security.Symbol]
for security in changes.AddedSecurities:
if security.Symbol not in self.symbolDict:
equity = self.AddEquity(security.Symbol.Value, Resolution.Minute, Market.USA)
self.symbolDict[security.Symbol] = SymbolData(self,security.Symbol,self.criteriaDict)
equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.symbol = equity.Symbol
def TradeOptions(self, contracts, ticker):
filtered_contracts = self.InitialFilter(ticker, contracts, -1, 1, 1, 15)
if filtered_contracts == None:
return
elif len(filtered_contracts) > 0:
expiry = sorted(filtered_contracts,key = lambda x: x.ID.Date, reverse=False)[0].ID.Date
call = [i for i in filtered_contracts if i.ID.Date == expiry and i.ID.OptionRight == 0]
call_contracts = sorted(call,key = lambda x: x.ID.StrikePrice)
self.call = call_contracts[0]
for i in filtered_contracts:
if i.ID.Date == expiry and i.ID.OptionRight == 1 and i.ID.StrikePrice ==call_contracts[0].ID.StrikePrice:
self.put = i
self.AddOptionContract(self.call, Resolution.Minute)
self.AddOptionContract(self.put, Resolution.Minute)
self.purchased_options.append(self.symbol)
self.Buy(self.call, 5)
def InitialFilter(self, underlyingsymbol, symbol_list, min_strike_rank, max_strike_rank, min_expiry, max_expiry):
contract_list = [i for i in symbol_list if min_expiry <= (i.ID.Date.date() - self.Time.date()).days < max_expiry]
try :
atm_strike = sorted(contract_list,
key = lambda x: abs(x.ID.StrikePrice - self.Securities[underlyingsymbol].Price))[0].ID.StrikePrice
strike_list = sorted(set([i.ID.StrikePrice for i in contract_list]))
atm_strike_rank = strike_list.index(atm_strike)
try:
min_strike = strike_list[atm_strike_rank + min_strike_rank]
max_strike = strike_list[atm_strike_rank + max_strike_rank]
except:
min_strike = strike_list[0]
max_strike = strike_list[-1]
filtered_contracts = [i for i in contract_list if i.ID.StrikePrice >= min_strike and i.ID.StrikePrice <= max_strike]
except:
filtered_contracts = None
return filtered_contracts
def OnData(self, data):
if self.IsWarmingUp: return
todaydate = datetime.today().strftime('%Y-%m-%d')
for x in holidays:
if x == todaydate:
return
for symbol in self.symbolDict:
symbolData = self.symbolDict[symbol]
symbolData.CurrentPrice = self.Securities[symbol].Price
if len (self.symbolWithPositionDict) != 0:
continue
if len(selected) != 0:
continue
elif symbol not in selected and symbol not in self.lock:
selected.append(symbol)
self.BuyIn[symbol] = symbolData.CurrentPrice
for symbol in selected:
symbolData = self.symbolDict[symbol]
symbolData.CurrentPrice = self.Securities[symbol].Price
if not self.Portfolio[symbol].Invested:
symbolData.BuyIn = symbolData.CurrentPrice
symbolData.current = self.Time
cash = self.Portfolio.Cash
available = (cash *.5)
purchase = math.floor(available / symbolData.CurrentPrice)
locktime = self.Time
contracts = self.OptionChainProvider.GetOptionContractList(symbol, self.Time.date())
if contracts:
self.Debug('contracts')
self.Debug(contracts)
self.TradeOptions(contracts, symbol.Value)
self.lock[symbol] = locktime
self.MarketOrder(symbol, -purchase)
self.symbolWithPositionDict[symbol] = SymbolData(self,symbol,self.criteriaDict)
for symbol in list(self.symbolWithPositionDict):
symbolData = self.symbolDict[symbol]
if self.Securities[symbol].Price < symbolData.BuyIn * .85 or self.Securities[symbol].Price > symbolData.BuyIn * 1.1: # self.Securities[symbol].Price < symbolData.highestTrailStopPrice * .9
self.Liquidate(symbol)
del self.symbolWithPositionDict[symbol]
selected.remove(symbol)
def CoarseFilterSelection(self, universe):
filtering = []
universe = sorted(universe, key=lambda c: c.DollarVolume, reverse=True)
universe = [c for c in universe]
for coarse in universe:
symbol = coarse.Symbol
options = self.OptionChainProvider.GetOptionContractList(symbol, self.Time.date())
if len(options) == 0:
continue
if symbol not in self.averages:
history = self.History(symbol, 30, Resolution.Daily)
self.averages[symbol] = SelectionData(history)
self.averages[symbol].update(self.Time, coarse.Volume)
if self.averages[symbol].is_ready() and self.averages[symbol].aver.Current.Value > 500000:
filtering.append(symbol)
return filtering
def FineFilterSelection(self, fine):
sortedByShares = sorted(fine, key = lambda f: f.CompanyProfile.SharesOutstanding, reverse = True)
universed = [f for f in sortedByShares if f.CompanyProfile.SharesOutstanding < 15000000 and f.MarketCap < 2000000000]
return [x.Symbol for x in universed]
class SelectionData():
def __init__(self, history):
self.aver = SimpleMovingAverage(30)
for bar in history.itertuples():
self.aver.Update(bar.Index[1], bar.close)
def is_ready(self):
return self.aver.IsReady
def update(self, time, volume):
self.aver.Update(time, volume)
Thank you,
Keenan
Derek Melchin
Hi Keenan,
The error message occurs because the algorithm calls
in OnSecuritiesChanged. We don't need to call AddEquity here because the coarse-fine universe selection already creates the Equity subscription. See the attached backtest for reference.
Best,
Derek Melchin
Want to invest in QuantConnect as we build the Linux of quant finance? Checkout our Wefunder campaign to join the revolution.
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.
Keenan Sivitz
Hi Derek,
I did not realize that, thank you!
Keenan
Keenan Sivitz
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!