from datetime import timedelta
from QuantConnect.Data.UniverseSelection import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel
from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel

class SectorBalancedPortfolioConstruction(QCAlgorithm):

def Initialize(self):
self.SetStartDate(2020, 7, 1)
self.SetEndDate(2021, 7, 1)
self.SetCash(100000)
self.UniverseSettings.Resolution = Resolution.Hour
# Set an instance of MyUniverseSelectionModel using self.SetUniverseSelection
self.SetUniverseSelection(MyUniverseSelectionModel())
self.SetAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(1), 0.025, None))
# Set an instance of the MySectorWeightingPortfolioConstructionModel using self.SetPortfolioConstruction
self.SetPortfolioConstruction(MySectorWeightingPortfolioConstructionModel()) #Default (Resolution.Daily))
self.SetExecution(ImmediateExecutionModel())

class MyUniverseSelectionModel(FundamentalUniverseSelectionModel):

def __init__(self):
super().__init__(True, None) #default: super().__init__(True, None)

def SelectCoarse(self, algorithm, coarse):
filtered = [x for x in coarse if x.HasFundamentalData and x.Price > 0]
sortedByDollarVolume = sorted(filtered, key=lambda x: x.DollarVolume, reverse=True)
return [x.Symbol for x in sortedByDollarVolume][:100]

def SelectFine(self, algorithm, fine):
# Save the top 3 securities sorted by MarketCap for the Technology sector to the variable self.technology
filtered = [f for f in fine if f.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Technology]
self.technology = sorted(filtered, key=lambda f: f.MarketCap, reverse=True)[:3]

# Save the top 2 securities sorted by MarketCap for the Financial Services sector to the variable self.financialServices
filtered = [f for f in fine if f.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.FinancialServices]
self.financialServices = sorted(filtered, key=lambda f: f.MarketCap, reverse=True)[:3]

#4. Save the top 1 securities sorted by MarketCap for the Consumer Goods sector to the variable self.consumerDefensive
filtered = [f for f in fine if f.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.ConsumerDefensive]
self.consumerDefensive = sorted(filtered, key=lambda f: f.MarketCap, reverse=True)[:0]
return [x.Symbol for x in self.technology + self.financialServices + self.consumerDefensive]
########################
class MySectorWeightingPortfolioConstructionModel(EqualWeightingPortfolioConstructionModel):
# In the constructor, pass in the rebalance parameter and set it to daily resolution
def __init__(self, rebalance = Resolution.Daily):
# Initialize the underlying class by passing it through
super().__init__(rebalance)
# Initialize an empty dictionary self.symbolBySectorCode to group the securities by sector code
self.symbolBySectorCode = dict()
self.result = dict()

def DetermineTargetPercent(self, activeInsights):
#1. Set the self.sectorBuyingPower before by dividing one by the length of self.symbolBySectorCode
self.sectorBuyingPower = 1 / len(self.symbolBySectorCode)

for sector, symbols in self.symbolBySectorCode.items():
#2. Search for the active insights in this sector. Save the variable self.insightsInSector
self.insightsInSector = [insight for insight in activeInsights if insight.Symbol in symbols]

#3. Divide the self.sectorBuyingPower by the length of self.insightsInSector to calculate the variable percent
# The percent is the weight we'll assign the direction of the insight
self.percent = self.sectorBuyingPower / len(self.insightsInSector)

#4. For each insight in self.insightsInSector, assign each insight an allocation.
# The allocation is calculated by multiplying the insight direction by the self.percent
for insight in self.insightsInSector:
self.result[insight] = insight.Direction * self.percent
return self.result

################################
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.AddedSecurities:
# When new assets are added to the universe, save the Morningstar sector code
# for each security to the variable sectorCode
sectorCode = security.Fundamentals.AssetClassification.MorningstarSectorCode

# If the sectorCode is not in the self.symbolBySectorCode dictionary, create a new list
if sectorCode not in self.symbolBySectorCode:
self.symbolBySectorCode[sectorCode] = list()

# and append the symbol to the list, keyed by sectorCode in the self.symbolBySectorCode dictionary
self.symbolBySectorCode[sectorCode].append(security.Symbol)

for security in changes.RemovedSecurities:
#3. For securities that are removed, save their Morningstar sector code to sectorCode
sectorCode = security.Fundamentals.AssetClassification.MorningstarSectorCode
#4. If the sectorCode is in the self.symbolBySectorCode dictionary
if sectorCode in self.symbolBySectorCode:
symbol = security.Symbol
# If the symbol is in the dictionary's sectorCode list;
if symbol in self.symbolBySectorCode[sectorCode]:
# Then remove the corresponding symbol from the dictionary
self.symbolBySectorCode[sectorCode].remove(symbol)

# We use the super() function to avoid using the base class name explicity
super().OnSecuritiesChanged(algorithm, changes)


Above Code is from the last of the bootcamps but it sends the error message below. What am I missing that causes this error?

Error Message

Runtime Error: AttributeError : 'NoneType' object has no attribute 'AssetClassification'
at OnSecuritiesChanged
sectorCode = security.Fundamentals.AssetClassification.MorningstarSectorCode
===
at Python.Runtime.PyObject.Invoke(PyTuple args in main.py:line 89
AttributeError : 'NoneType' object has no attribute 'AssetClassification'

Stack Trace

AttributeError : 'NoneType' object has no attribute 'AssetClassification'
at OnSecuritiesChanged
sectorCode = security.Fundamentals.AssetClassification.MorningstarSectorCode
===
at Python.Runtime.PyObject.Invoke(PyTuple args in main.py:line 89