This is my first attempt at monthly rebalancing, so I'm missing something simple to get it to work. The concept is to coars filter by dollar volume and fundamental data, then fine filter for ROE, and invest monthly in top 20 results.
The error seems to be from SPY with the rebalance action at the end, but i'm stuck. Any help would be appreciated.
My backtest wasn't showing up in the dropdown so here is the code:
from clr import AddReference
AddReference("System.Core")
AddReference("System.Collections")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
from System import *
from System.Collections.Generic import List
from QuantConnect import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
class MonthlyROERebalanceAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2000,1,1) #Set Start Date
self.SetEndDate(2020,8,1) #Set End Date
self.SetCash(100000) #Set Strategy Cash
self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol
# what resolution should the data *added* to the universe be?
self.UniverseSettings.Resolution = Resolution.Daily
# this add universe method accepts two parameters:
# - coarse selection function: accepts an IEnumerable<CoarseFundamental> and returns an IEnumerable<Symbol>
# - fine selection function: accepts an IEnumerable<FineFundamental> and returns an IEnumerable<Symbol>
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
self.numberOfSymbols = 500
self.numberOfSymbolsFine = 20
self._changes = None
# Create the monthly rebalance logic. Check SPY 1 minute after market open to determine the first trading day of the month.
self.Schedule.On(self.DateRules.MonthStart(self.spy),
self.TimeRules.AfterMarketOpen(self.spy,1),
self.rebalance)
def OnData(self, data):
#make sure SPY has data to prevent missing data errors
if data.ContainsKey("SPY") == False: return
pass
# Coarse selection by sorting the symbols by daily dollar volume and define this list as "numbersOfSymbol"
def CoarseSelectionFunction(self, coarse):
# sort descending by daily dollar volume and only those that have fundamental data
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume and x.HasFundamentalData, reverse=True)
# return the symbol objects of the top entries from our sorted collection
return [ x.Symbol for x in sortedByDollarVolume[:self.numberOfSymbols] ]
# sort the data by Return on Equity and take the top ranked symbols as 'NumberOfSymbolsFine'
def FineSelectionFunction(self, fine):
# sort descending by Return On Equity
sortedByROE = sorted(fine, key=lambda x: x.OperationRatios.ROE.Value, reverse=True)
# take the top entries from our sorted collection
return [ x.Symbol for x in sortedByROE[:self.numberOfSymbolsFine] ]
def rebalance(self):
# invest equally in the fine filtered list of stocks
for symbol in self.numberOfSymbolsFine:
self.SetHoldings(symbol, 1)
Adam W
The error you are receiving "'int' object is not iterable" means exactly that - we can't iterate through an integer.
Issue is this line here:
for symbol in self.numberOfSymbolsFine: self.SetHoldings(symbol, 1)
where in Initialize, you defined self.numOfSymbolsFine = 20. Possibly, you meant to do this instead?
def Initialize(self): self.fineFilteredSymbols = [] def FineSelectionFunction(self, fine): # sort descending by Return On Equity sortedByROE = sorted(fine, key=lambda x: x.OperationRatios.ROE.Value, reverse=True) # take the top entries from our sorted collection self.fineFilteredSymbols = [ x.Symbol for x in sortedByROE[:self.numberOfSymbolsFine] ] return self.fineFilteredSymbols def rebalance(self): for symbol in self.fineFilteredSymbols: self.SetHoldings(symbol, 1 / self.numberOfSymbolsFine ) # Allocate portfolio equally to the fine symbols
Mark hatlan
Thanks Adam that worked.
I'm still a beginner, can someone please explain to me why the line "self.fineFilteredSymbols = []" worked. Is it because I needed a higher level symbol grouping to include SPY for the rebalancing action?
Adam W
I don't think SPY is relevant here besides being used for the scheduling times, unless it happened to be in the fine filtered universe.
What you had originally was essentially:
for symbol in 20: self.SetHoldings(*)
where it's unclear for what in 20 to loop over, throwing an error.
self.fineFilteredSymbols works because it is now looping through a list - for each element (symbol) in the list, do something.
By the way, may be a good idea to also handle what happens to symbols that are invested but no longer in the Universe:
def OnSecuritiesChanged(self, changes): # Liquidate securities no longer in universe for security in changes.RemovedSecurities: if security.Invested: self.Liquidate(security.Symbol)
Mark hatlan
Thanks Adam!
Mark hatlan
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!