I am developing a market neutral strategy, where 50% of the portfolio is allocated for stocks that fall under certain fundamental criteria. The other 50% shorts SPY. The backtest seem to run OK, until the very end of the simulations where it shows the error: Object reference not set to an instance object
find below the error and the code (since it does not let me attach it)
May also help that the terminal shows:
Backtest Handled Error: No data loaded for WDFC R735QTJ8XC9X because there were no tradeable dates for this security.
WDFC R735QTJ8XC9X: The security does not have an accurate price as it has not yet received a bar of data. Before placing a trade (or using SetHoldings) warm up your algorithm with SetWarmup, or use slice.Contains(symbol) to confirm the Slice object has price before using the data. Data does not necessarily all arrive at the same time so your algorithm should confirm the data is ready before using it. In live trading this can mean you do not have an active subscription to the asset class you're trying to trade. If using custom data make sure you've set the 'Value' property.
from AlgorithmImports import *
from datetime import timedelta, datetime
from QuantConnect.Data.UniverseSelection import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel
class Third_Attempt(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2021, 1, 1) # Set Start Date
self.SetEndDate(2022, 1, 1) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
self.AddUniverseSelection(Highperformance())
self.UniverseSettings.Resolution = Resolution.Daily
self.AddAlpha(BuyPerformance())
self.SetPortfolioConstruction(PortfolioBuilder())
#self.AddRiskManagement(Trailing_SL_TP())
self.SetExecution(ImmediateExecutionModel())
class Highperformance (FundamentalUniverseSelectionModel):
def __init__(self):
super().__init__( True, None)
self.lastMonth = -1
#creating the SPY symbol (for the index)
self.spy = Symbol.Create('SPY', SecurityType.Equity, Market.USA)
def SelectCoarse(self, algorithm, coarse):
#run the algorithm once a month, return Universe.Unchanged in case we are looking at exactly the same month
if algorithm.Time.month == self.lastMonth:
return Universe.Unchanged
self.lastMonth = algorithm.Time.month
sortedByVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
filteredByFundamentals = [x.Symbol for x in sortedByVolume if x.HasFundamentalData]
return filteredByFundamentals + [self.spy]
def SelectFine(self, algorithm, fine):
sorted_high = sorted([x for x in fine if x.MarketCap > 2e9
and 0.5 > x.OperationRatios.AVG5YrsROIC.FiveYears > 0.20
and 50 > x.ValuationRatios.PERatio > 20
and x.AssetClassification.MorningstarSectorCode != MorningstarSectorCode.FinancialServices
and x.AssetClassification.MorningstarSectorCode != MorningstarSectorCode.Healthcare],
key = lambda x: x.ValuationRatios.PERatio, reverse=True)
#fundamental_universe = [x.Symbol for x in sorted_high[:5]] + [self.spy]
return [x.Symbol for x in sorted_high[:5]] + [self.spy]
class BuyPerformance(AlphaModel):
def __init__(self):
self.lastMonth = -1
self.newAdds = []
self.spy = Symbol.Create('SPY', SecurityType.Equity, Market.USA)
def Update(self, algorithm, data):
if algorithm.Time.month == self.lastMonth:
return []
self.lastMonth = algorithm.Time.month
insights = []
#printing the time (for troubleshooting purposes)
algorithm.Debug(str(algorithm.Time))
# Generate Pos (+) insight if the symbol has been added to 'newAdds', has data to trade and has not been invested before
for added in self.newAdds:
if not algorithm.Securities[added].Invested and algorithm.Securities[added].HasData and algorithm.Securities[added].IsTradable:
algorithm.Debug('Positive Insight : ' + str(added))
insights.append(Insight(added, timedelta(30), InsightType.Price, InsightDirection.Up))
# Generate Flat insight if the symbol is already in the Portfolio, has been invested and it's not in newadds
for x in algorithm.Portfolio:
holding = x.Value
symbol = holding.Symbol
if holding.Invested and (symbol not in self.newAdds):
if symbol not in data.Bars:
continue
insights.append(Insight(symbol, timedelta(30), InsightType.Price, InsightDirection.Flat))
return insights
def OnSecuritiesChanged(self, algorithm, changes):
# When assets are added to the universe, they will trigger OnSecuritiesChanged() event.
#From there, you can initialize any state or history required for the Alpha Model
algorithm.Debug('\n -----ALPHA MODEL ----: ' + str(algorithm.Time))
# Securities added into the universe will be added to self.newAdds
for security in changes.AddedSecurities:
symbol = security.Symbol
if (symbol not in self.newAdds) and (symbol != self.spy):
algorithm.Debug('added symbol : ' + str(symbol))
self.newAdds.append(symbol)
# Securities removed from the universe will be removed from self.newAdds
for security in changes.RemovedSecurities:
symbol = security.Symbol
if symbol in self.newAdds and (symbol != self.spy):
algorithm.Debug('removed symbol symbol : ' + str(symbol))
self.newAdds.remove(symbol)
#Until now we keep excluding the index SPY. We will execute the trade in the portfolio builder
class PortfolioBuilder(PortfolioConstructionModel):
def __init__(self):
self.lastMonth = -1
self.spy = Symbol.Create('SPY', SecurityType.Equity, Market.USA)
def CreateTargets (self, algorithm, insights):
if not algorithm.Time.month == self.lastMonth:
total_equity = algorithm.Portfolio.TotalPortfolioValue
else:
return []
self.lastMonth = algorithm.Time.month
algorithm.Debug('\n -----PORTFOLIO CONSTRUCTION ----: ' + str(algorithm.Time))
# Create a list of PortfolioTarget objects from Insights (just for symbols, excluding SPY)
target_array = []
target = None
new = []
#I am creating a vector of new symbols added to the algorithm
# i will use this vector 'new' to find the lentgh and allocate the right % of the portfolio
for insight in insights:
if not algorithm.Securities[insight.Symbol].Invested:
new.append(insight.Symbol)
for insight in insights:
if insight.Direction == InsightDirection.Flat:
target = PortfolioTarget(insight.Symbol, 0) #Generate the sell order on the flat insight
if insight.Direction == InsightDirection.Up:
#Calculate shares using the half Portfolio value divided in equal amount with the number of symbols recently added.
target = PortfolioTarget.Percent(algorithm, insight.Symbol, 1/(2*len(new)))
target_array.append(target)
#Now i will create the target for the index 'SPY' who's shorting the other half of the portfolio value
for x in algorithm.ActiveSecurities:
holding = x.Value
symbol = holding.Symbol
if not holding.Invested and symbol == self.spy:
target = PortfolioTarget.Percent(algorithm, symbol, -0.5)
target_array.append(target)
return target_array
'''
class Trailing_SL_TP(RiskManagementModel):
def __init__(self):
pass
def ManageRisk(self, algorithm, targets):
pass
'''
Arthur Asenheimer
Hi Jose,
this happens since at least one of the targets in your portfolio construction model was None. The ExecutionModel expects a sequence of PortfolioTarget objects which is why you get this error. Make sure you only append the target to your target_array if it is not None (see also screenshot and backtest attached).
Regarding the error message “Backtest Handled Error: No data loaded for WDFC R735QTJ8XC9X because there were no tradeable dates for this security.”
This has a different cause. Your universe selection model gets an update at the first day of a month. But your backtest also ends at the first day of January which is a public holiday. Hence, there were some securities added to the universe while the backtest stops at the same day, i.e. there were no tradable days for those securities. I recommend to update your universe only on business days. You can use algorithm.TradingCalendar.GetTradingDay().BusinessDay for this purpose (Note: I've already added this in the code attached).
Jose David Delgado Mosquera
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!