Overall Statistics
class ModulatedResistanceCoreWave(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 9, 5)  # Set Start Date
        self.SetEndDate(2019, 9 , 10)
        self.SetCash(100000)  # Set Strategy Cash
        self.UniverseSettings.Resolution = Resolution.Hour
        self.AddUniverse(self.SelectCoarse)
        
        # Dictionary to hold symbolData
        self.symbolDict = {}
    
    def SelectCoarse(self, coarse):
        # Get top 1000 liquid stocks
        sortedCoarse = sorted(coarse, key=lambda c:c.DollarVolume, reverse=True)
        return [c.Symbol for c in sortedCoarse][:1000]
    
    def OnSecuritiesChanged(self, changes):
        # Add symbol to symbolDict if added to universe
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            if symbol not in self.symbolDict:
                self.symbolDict[symbol] = SymbolData(self, symbol)
                
        for security in changes.RemovedSecurities:
            symbol = security.Symbol
            if symbol in self.symbolDict:
                # Remove unused consolidators from algorithm and remove symbol from dict
                self.SubscriptionManager.RemoveConsolidator(symbol, self.symbolDict[symbol].consolidator)
                self.symbolDict.pop(symbol, None)
    
    def OnData(self, data):
        
        selected = []
        # Filter stocks in symbolDict by RSI
        for symbol, symbolData in self.symbolDict.items():
            rsi = symbolData.rsi
            if rsi.IsReady and rsi.Current.Value < 30:
                selected.append(symbol.Value)
                
        
        self.Debug(selected)


class SymbolData:
    
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol
        
        # Define and register consolidator
        self.consolidator = TradeBarConsolidator(timedelta(hours = 1))
        self.algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator)
        
        # Define and register RSI indicator
        self.rsi = RelativeStrengthIndex(14)
        algorithm.RegisterIndicator(symbol, self.rsi, self.consolidator)
        
        # Warm-up our RSI indicator with historical data
        history = algorithm.History(symbol, 14, Resolution.Hour)
        
        if not history.empty:
            history = history.close.unstack(0)
            if not history.empty:
                df = history[symbol].dropna()
                for time, close in df.iteritems():
                    self.rsi.Update(time, close)