Hello,

Just getting started with QC so I tried something simple after going through boot camp. This is a very simple strategy that just picks top shareholder yield companies, holds more a month and then rebalances. Clearly this is not a great strategy but I wanted something simple for learning the algorithm framework.

Can folks more familiar for the Algo framework comment on my usage? Is there anything obvious I could be doing better to exploit the framework? Any obvious errors? Code below. My main concern is making sure I am using the framework apropriately and taking full advantage of it. Thanks!

""" Shareholder Yield Algo.
This is for learning the QuantConnect Algo Framework. I don't expect it to be useful outside of that.

The goal of this algo is:
- create a universe of liquid stocks with the best share holder yield (dividends + buybacks) relative to the market.
- buy an equal weighted portfolio of these stocks.
- rebalance monthly based on share holder yield.

Classes:
- ShareHolderYieldAlgo() is the main class that configures and instantiates the QuantConnect algo framework.
- LiquidTotalYieldUniverseSelectionModel() is a class which creates a liquid universe of stocks ranking by
dollar volume, then filters the list down for the top X yielders based on share holder yield.
- LongShareHolderYieldAlphaModel() is an alpha model class which emits buy and sell signals based on changes
to the universe selection.
"""
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

class ShareHolderYieldAlgo(QCAlgorithm):

def Initialize(self):
self.SetStartDate(2005, 1, 1) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverseSelection(LiquidTotalYieldUniverseSelectionModel())
self.AddAlpha(LongShareHolderYieldAlphaModel())
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
self.SetExecution(ImmediateExecutionModel())

class LiquidTotalYieldUniverseSelectionModel(FundamentalUniverseSelectionModel):

def __init__(self):
super().__init__(True, None, None)
self.lastMonth = -1
# Use this to determined how many stocks we take off the dollar volume sorted list.
self.dollarVolumeListSize = 200
# Number of securities to select and return from universe.
self.selectionSize = 10

def SelectCoarse(self, algorithm, coarse):
if self.lastMonth == algorithm.Time.month:
return Universe.Unchanged
self.lastMonth = algorithm.Time.month

sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData],
key=lambda x: x.DollarVolume, reverse=True)

return [x.Symbol for x in sortedByDollarVolume[:self.dollarVolumeListSize]]

def SelectFine(self, algorithm, fine):
sortedByYields = sorted(fine, key=lambda f: f.ValuationRatios.TotalYield, reverse=True)
universe = sortedByYields[:self.selectionSize]
return [f.Symbol for f in universe]

class LongShareHolderYieldAlphaModel(AlphaModel):

def __init__(self):
self.lastMonth = -1
self.signalTimeDelta = 30
self.symbols = []

def _processChanges(self, changes):
# safety check, make sure list elements are unique.
symbols = list(set(self.symbols))
# I feel like this update is problematic and could lead to bugs.
# Need to figure out a better way to just swap the list out whole
# sale.
for security in changes.RemovedSecurities:
symbols.remove(security.Symbol)
for security in changes.AddedSecurities:
symbols.append(security.Symbol)
self.symbols = symbols

def Update(self, algorithm, data):
# Skip if we have already run this month.
if self.lastMonth == algorithm.Time.month:
return []
self.lastMonth = algorithm.Time.month

insights = []
# Create liquidate (flat) signals for stocks in our portfolio that are no longer in our strategy as of this
# update.
for kv in algorithm.Portfolio:
holding = kv.Value
symbol = holding.Symbol
if holding.Invested and symbol not in self.symbols:
insights.append(Insight(symbol, timedelta(self.signalTimeDelta), InsightType.Price, InsightDirection.Flat, None, None))
# Create buy signals for stocks selected in our strategy.
for symbol in self.symbols:
insights.append(Insight(symbol, timedelta(self.signalTimeDelta), InsightType.Price, InsightDirection.Up, None, None))

return insights

def OnSecuritiesChanged(self, algorithm, changes):
self._processChanges(changes)

 

Author