class RSIBasedUniverseSelection(QCAlgorithm):
def Initialize(self):
# Set Start Date, End Date, and Cash
#-------------------------------------------------------
self.SetTimeZone(TimeZones.NewYork) #EDIT: Added Timezon
self.SetStartDate(2011, 4, 1) # Set Start Date
self.SetEndDate(2011, 5, 1) # Set End Date
self.SetCash(100000) # Set Strategy Cash
#-------------------------------------------------------
self.AddUniverse(self.CoarseSelectionFilter, self.FineSelectionFilter)
self.__numberOfSymbols = 100
self.__numberOfSymbolsFine = 50
self.indicators = {}
self.rsi_period = 14
def CoarseSelectionFilter(self, coarse):
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True) # sort descending by daily dollar volume
return [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ] # return the symbol objects of the top entries from our sorted collection
def FineSelectionFilter(self, fine):
sortedByPeRatio = sorted(fine, key=lambda x: x.OperationRatios.OperationMargin.Value, reverse=False) # sort descending by P/E ratio
self.universe = [ x.Symbol for x in sortedByPeRatio[:self.__numberOfSymbolsFine] ] # take the top entries from our sorted collection
return self.universe
def OnSecuritiesChanged(self, changes):
for security in changes.AddedSecurities:
self.indicators[security] = SymbolData(security, self, self.rsi_period)
def OnData(self, data):
for symbol in self.universe:
if not data.ContainsKey(symbol): #Tested and Valid/Necessary
continue
if data[symbol] is None: #Tested and Valid/Necessary
continue
if not symbol in self.indicators: #Tested and Valid/Necessary
continue
# Ensure indicators are ready to update rolling windows
if not self.indicators[symbol].is_rsi_value_ready():
continue
self.indicators[symbol].rsi_window.Add(self.indicators[symbol].get_rsi_value())
if not self.indicators[symbol].is_rsi_window_ready():
continue
if self.indicators[symbol].rsi_value.Current.value > 10 and self.indicators[symbol].rsi_value.Current.value < 30:
self.Debug('symbol' + str(symbol))
self.Debug(self.indicators[symbol].rsi_value.Current.value)
class SymbolData(object):
rolling_window_length = 3
def __init__(self, symbol, context, rsi_period):
self.symbol = symbol
self.rsi_period = rsi_period
self.rsi_value = context.RSI(symbol, 14, MovingAverageType.Exponential)
self.rsi_window = RollingWindow[float](self.rolling_window_length)
# Warm up EMA indicators
history = context.History([symbol], rsi_period + self.rolling_window_length, Resolution.Daily)
for time, row in history.loc[symbol].iterrows():
self.rsi_value.Update(time, row["close"])
# Warm up rolling windows
if self.rsi_value.IsReady:
self.rsi_window.Add(self.rsi_value.Current.Value)
def get_rsi_value(self):
return self.rsi_value.Current.Value
def is_rsi_value_ready(self):
return self.rsi_value.IsReady
def is_rsi_window_ready(self):
return self.rsi_window.IsReady