Hi! I am new to the QuantConnect Platform, and have been finding a peculiar issue that I can't troubleshoot very well.
I have some code cloned from here. I have been messing around with single file algorithms just learning, and they work great. The second that I have been trying to create multiple files and import modules, I get thrown this error:
It states that my module is not defined, however, it certainly is. From the author of the code that I cloned from, it works perfectly well. I attempted to dig into the files for the engine and I simply could not figure it out. There are only two files of relevance… main.py & AlphaModel.py, seen below:
main.py:
from AlphaModel import *
from AlgorithmImports import *
class UglyFluorescentYellowFox(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 1, 1)
self.SetEndDate(2021, 1, 1)
self.SetCash(100000)
# Universe selection
self.month = 0
self.num_coarse = 500
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
# Alpha Model
self.AddAlpha(FundamentalFactorAlphaModel())
# Portfolio construction model
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(self.IsRebalanceDue))
# Risk model
self.SetRiskManagement(NullRiskManagementModel())
# Execution model
self.SetExecution(ImmediateExecutionModel())
# Share the same rebalance function for Universe and PCM for clarity
def IsRebalanceDue(self, time):
# Rebalance on the first day of the Quarter
if time.month == self.month or time.month not in [1, 4, 7, 10]:
return None
self.month = time.month
return time
def CoarseSelectionFunction(self, coarse):
# If not time to rebalance, keep the same universe
if not self.IsRebalanceDue(self.Time):
return Universe.Unchanged
# Select only those with fundamental data and a sufficiently large price
# Sort by top dollar volume: most liquid to least liquid
selected = sorted([x for x in coarse if x.HasFundamentalData and x.Price > 5],
key = lambda x: x.DollarVolume, reverse=True)
return [x.Symbol for x in selected[:self.num_coarse]]
def FineSelectionFunction(self, fine):
# Filter the fine data for equities that IPO'd more than 5 years ago in selected sectors
sectors = [
MorningstarSectorCode.FinancialServices,
MorningstarSectorCode.RealEstate,
MorningstarSectorCode.Healthcare,
MorningstarSectorCode.Utilities,
MorningstarSectorCode.Technology]
filtered_fine = [x.Symbol for x in fine if x.SecurityReference.IPODate + timedelta(365*5) < self.Time
and x.AssetClassification.MorningstarSectorCode in sectors
and x.OperationRatios.ROE.Value > 0
and x.OperationRatios.NetMargin.Value > 0
and x.ValuationRatios.PERatio > 0]
return filtered_fine
AlphaModel.py:
class FundamentalFactorAlphaModel(AlphaModel):
def __init__(self):
self.rebalanceTime = datetime.min
# Dictionary containing set of securities in each sector
# e.g. {technology: set(AAPL, TSLA, ...), healthcare: set(XYZ, ABC, ...), ... }
self.sectors = {}
def Update(self, algorithm, data):
'''Updates this alpha model with the latest data from the algorithm.
This is called each time the algorithm receives data for subscribed securities
Args:
algorithm: The algorithm instance
data: The new data available
Returns:
New insights'''
if algorithm.Time <= self.rebalanceTime:
return []
# Set the rebalance time to match the insight expiry
self.rebalanceTime = Expiry.EndOfQuarter(algorithm.Time)
insights = []
for sector in self.sectors:
securities = self.sectors[sector]
sortedByROE = sorted(securities, key=lambda x: x.Fundamentals.OperationRatios.ROE.Value, reverse=True)
sortedByPM = sorted(securities, key=lambda x: x.Fundamentals.OperationRatios.NetMargin.Value, reverse=True)
sortedByPE = sorted(securities, key=lambda x: x.Fundamentals.ValuationRatios.PERatio, reverse=False)
# Dictionary holding a dictionary of scores for each security in the sector
scores = {}
for security in securities:
score = sum([sortedByROE.index(security), sortedByPM.index(security), sortedByPE.index(security)])
scores[security] = score
# Add best 20% of each sector to longs set (minimum 1)
length = max(int(len(scores)/5), 1)
for security in sorted(scores.items(), key=lambda x: x[1], reverse=False)[:length]:
symbol = security[0].Symbol
# Use Expiry.EndOfQuarter in this case to match Universe, Alpha and PCM
insights.append(Insight.Price(symbol, Expiry.EndOfQuarter, InsightDirection.Up))
return insights
def OnSecuritiesChanged(self, algorithm, changes):
'''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'''
# Remove security from sector set
for security in changes.RemovedSecurities:
for sector in self.sectors:
if security in self.sectors[sector]:
self.sectors[sector].remove(security)
# Add security to corresponding sector set
for security in changes.AddedSecurities:
sector = security.Fundamentals.AssetClassification.MorningstarSectorCode
if sector not in self.sectors:
self.sectors[sector] = set()
self.sectors[sector].add(security)
Marc Daoust
Leo;
You need to also insert
in the AlphaModel.py file.
I would recommend moving that line to the top in your main.py, but that is just my coding style.
Leo Kamgar
Hi Marc,
Thank you for your response. That indeed did fix the issue. However, I have no understanding as to why it did. My reasoning is that when you are importing a module, you are essentially placing code from that module into the file that is importing. In main.py, I import AlgorithmImports, placing the necessary code from this library within main.py. Additionally, I attempt to import AlphaModel.py. This compiled file would already have AlgorithmImports, so I am confused as to why it would require a second import of the same library. It would seem as though it would not be needed to be imported into AlphaModel.py just for that file to be imported into main, compiling 2 copies of AlgorithmImports into main.py (provided the compiler is not structured to remove code redundancies, which I have no knowledge of). It would seem that this would only create coding inefficiencies.
Leo Kamgar
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!