Hi,
I been struggling with the same error for a bit now,
Runtime Error: Trying to retrieve an element from a collection using a key that does not exist in that collection throws a KeyError exception. To prevent the exception, ensure that the key exist in the collection and/or that collection is not empty. at OnSecuritiesChanged self.activeStocks.remove(x.Symbol) === at Python.Runtime.PyObject.Invoke(PyTuple args in main.py: line 70
I am a bloody beginner and cant figure this one out by myself right now, it might seem obvious to anyone else here on how to fix this.
If anyone has additional recommendations on this code I am thankfull for any suggestions.
class WellDressedSkyBlueSardine(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 2, 25)
# self.SetEndDate(2020, 3, 1)
self.SetCash(100000)
self.SetBenchmark("SPY")
self.rebalanceTime = datetime.min
self.activeStocks = set()
self.AddUniverse(self.CoarseFilter, self.FineFilter)
self.UniverseSettings.Resolution = Resolution.Daily
#self.brokerage = BrokerageName.InteractiveBrokersBrokerage
self.SetBrokerageModel(BrokerageName.AlphaStreams)
#self.SetBrokerageModel(self.brokerage, AccountType.Margin)
self.portfolioTargets = []
self.UniverseSettings.DataNormalizationMode=DataNormalizationMode.SplitAdjusted
#self.UniverseSettings.ExtendedMarketHours = False
self.AddRiskManagement(MyRiskModel(.21))
self.SetExecution(ImmediateExecutionModel())
self.SetAlpha(LongOnlyConstantAlphaCreationModel())
def CoarseFilter(self, coarse):
# Rebalancing monthly
if self.Time <= self.rebalanceTime:
return self.Universe.Unchanged
self.rebalanceTime = self.Time + timedelta(2)
myuniverse = [x for x in coarse if x.Price < 50 and x.DollarVolume > 1000000]
return [x.Symbol for x in myuniverse if x.Price < 50
and x.HasFundamentalData][:2000]
def FineFilter(self, fine):
security_filter = [x for x in fine if x.EarningReports.DilutedEPS.Value > .1
and x.ValuationRatios.PERatio < 25
and x.OperationRatios.RevenueGrowth.ThreeMonths > .05
and x.MarketCap > 100000000
and x.OperationRatios.ROA.ThreeMonths > .02
and x.OperationRatios.ROE.ThreeMonths > .03
and x.EarningRatios.DilutedEPSGrowth.ThreeMonths > .03
and x.OperationRatios.NetMargin.ThreeMonths > .08
and x.ValuationRatios.PSRatio < 1.5]
sorting = sorted(security_filter, key = lambda x: x.ValuationRatios.PSRatio, reverse=False)
self.Log(str([x.OperationRatios.RevenueGrowth.ThreeMonths for x in sorting[:50]]))
self.Log(str([x.MarketCap for x in sorting[:50]]))
self.Log(str([x.OperationRatios.ROE.ThreeMonths for x in sorting[:50]]))
self.Log(str([x.OperationRatios.ROA.ThreeMonths for x in sorting[:50]]))
self.Log(str([x.EarningRatios.DilutedEPSGrowth.ThreeMonths for x in sorting[:50]]))
self.Log(str([x.OperationRatios.NetMargin.ThreeMonths for x in sorting[:50]]))
self.Log(str([x.ValuationRatios.PSRatio for x in sorting[:50]]))
return [x.Symbol for x in sorting[:50]]
def OnSecuritiesChanged(self, changes):
# close positions in removed securities
for x in changes.RemovedSecurities:
self.activeStocks.remove(x.Symbol)
self.Liquidate(x.Symbol)
# can't open positions here since data might not be added correctly yet
for x in changes.AddedSecurities:
self.activeStocks.add(x.Symbol)
# adjust targets if universe has changed
self.portfolioTargets = [PortfolioTarget(symbol, 1/len(self.activeStocks))
for symbol in self.activeStocks]
def OnData(self, data):
if self.portfolioTargets == []:
return
for symbol in self.activeStocks:
if symbol not in data:
return
self.SetHoldings(self.portfolioTargets)
# self.portfolioTargets = []
#Riskmodel not working properly
class MyPortfolioModel(EqualWeightingPortfolioConstructionModel):
def __init__(self):
pass
def CreateTargets(self, algorithm, insights):
# Simple insight weighting PCM
targets = []
for insight in insights:
targ = PortfolioTarget(insight.Symbol, insight.Direction*insight.Weight)
targets.append(targ)
return targets
class MyRiskModel(RiskManagementModel):
def __init__(self, maxDrawdown=.21):
self.maxDrawdown = maxDrawdown
self.liquidatedSymbols = set() # Tracks symbols that have been liquidated
self.currentTargets = [] # Tracks state of current targets
def ManageRisk(self, algorithm, targets):
# Reset trackers on new targets
if (set(targets) != self.currentTargets) and len(targets)>0:
algorithm.Log(f'New Targets. Quantity: {targets[0].Quantity}')
self.liquidatedSymbols = set()
self.currentTargets = set(targets)
riskAdjustedTargets = []
for _ in algorithm.Securities:
symbol = _.Key # Symbol object
security = _.Value # Security object
ticker = symbol.Value # String ticker
symbolPnL = security.Holdings.UnrealizedProfitPercent # Current PnL
#Liquidate if exceed drawdown
if (symbolPnL < -self.maxDrawdown) or (ticker in self.liquidatedSymbols):
riskAdjustedTargets.append(PortfolioTarget(symbol, 0))
if algorithm.Securities[symbol].Invested:
self.liquidatedSymbols.add(ticker)
algorithm.Log(f'Trailing stop loss triggered for {ticker}.')
return riskAdjustedTargets
class LongOnlyConstantAlphaCreationModel(AlphaModel):
'''
Description:
This Alpha model creates InsightDirection.Up (to go Long) for a duration of 1 day, every day for all active securities in our Universe
Details:
The important thing to understand here is the concept of Insight:
- A prediction about the future of the security, indicating an expected Up, Down or Flat move
- This prediction has an expiration time/date, meaning we think the insight holds for some amount of time
- In the case of a constant long-only strategy, we are just updating every day the Up prediction for another extra day
- In other words, every day we are making the conscious decision of staying invested in the security one more day
'''
def __init__(self, resolution = Resolution.Daily):
self.insightExpiry = Time.Multiply(Extensions.ToTimeSpan(resolution), 0.25) # insight duration
self.insightDirection = InsightDirection.Up # insight direction
self.securities = [] # list to store securities to consider
def Update(self, algorithm, data):
insights = [] # list to store the new insights to be created
# loop through securities and generate insights
for security in self.securities:
# check if there's new data for the security or we're already invested
# if there's no new data but we're invested, we keep updating the insight since we don't really need to place orders
if data.ContainsKey(security.Symbol) or algorithm.Portfolio[security.Symbol].Invested:
# append the insights list with the prediction for each symbol
insights.append(Insight.Price(security.Symbol, self.insightExpiry, self.insightDirection))
else:
algorithm.Log('excluding this security due to missing data: ' + str(security.Symbol.Value))
return insights
def OnSecuritiesChanged(self, algorithm, changes):
'''
Description:
Event fired each time the we add/remove securities from the data feed
Args:
algorithm: The algorithm instance that experienced the change in securities
changes: The security additions and removals from the algorithm
'''
# add new securities
for added in changes.AddedSecurities:
self.securities.append(added)
# remove securities
for removed in changes.RemovedSecurities:
if removed in self.securities:
self.securities.remove(removed)
Louis Szeto
Hi Patryski
We just need to make sure the Symbol is in the self.activeStocks list.
Best
Louis Szeto
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.
Patryski
Thank you Louis!
I had tried to fix it with a history function…
Patryski
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!