Hi!

I've been working on a strategy lately but no matter what I try, the symbols I have in the universe are not the ones I'm expecting. I tried using self.ActiveSecurities.Keys, self.changes.AddedSecurities…but no matter what I try the securities are more than the ones I would expect. I tried reducing the output from the CoarseSelectionFunction, too. But no matter what I do…it seems that the filtering is broken.

class MeanReversionAlgo(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date

        self.initialcash = 100000
        self.SetCash(self.initialcash)  # Set Strategy Cash
        # Add SPY to set scheduled events
        self.AddEquity("SPY", Resolution.Daily)
        # Setting Universe
        self.UniverseSettings.Resolution = Resolution.Daily
        self.SetUniverseSelection(QC500UniverseSelectionModel())
        
        # 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.UniverseSettings.Resolution = Resolution.Daily
        
        self.AddUniverse(self.CoarseSelectionFunction)

        self.__numberOfSymbolsFine = 2
        self._changes = None
        
        self.AutomaticIndicatorWarmUp=True
        
        self.SetWarmup(200, Resolution.Daily)
        
        self.dataDict = {}
        self.verboseLogging = False
        
        # schedule an event to fire every trading day for a security the
        # time rule here tells it to fire 10 minutes after SPY's market open
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 10), self.EveryDayAfterMarketOpen)
        
    def EveryDayAfterMarketOpen(self):
        '''
        self.Debug(f"EveryDay.SPY 10 min after open: Fired at: {self.Time}")
        
         # if we have no changes, do nothing
        if self._changes is None: return

        # liquidate removed securities
        for security in self._changes.RemovedSecurities:
            if security.Invested:
                self.Liquidate(security.Symbol)

        # we want 20% allocation in each security in our universe
        for security in self._changes.AddedSecurities:
            self.SetHoldings(security.Symbol, 0.01)

        self._changes = None
        '''
        
        for i in self.ActiveSecurities.Keys:
            self.Debug(i)
    
    # sort the data by daily dollar volume and take the top 'NumberOfSymbols'
    def CoarseSelectionFunction(self, coarse):
        
        CoarseWithFundamental = [x for x in coarse if x.HasFundamentalData and x.Price > 5]
        
        for i in CoarseWithFundamental:
            if i.Symbol not in self.dataDict:
                self.dataDict[i.Symbol] = SymbolData(i.Symbol)
            
            self.dataDict[i.Symbol].update(i.EndTime, i.AdjustedPrice)  
        

        values = [x for x in self.dataDict.values()]
        
        values_sharpe_ready = [x for x in values if x.SharpeOK] 
        
        values_sharpe_ready.sort(key=lambda x: x.sharpe , reverse=True)
        
        top_100_sharpe = values_sharpe_ready[:100]
        
        if self.verboseLogging:
            self.Debug("First filter --------> top 100 by Sharpe")
            for i in top_100_sharpe:
                self.Debug(str(i.symbol)+" Current Sharpe "+str(i.sharpe))

        
        sma_filtered = [x for x in top_100_sharpe if x.SMA_OK]
        
        if self.verboseLogging:
            self.Debug("Second filter --------> SMA filter")
            for i in sma_filtered:
                self.Debug(str(i.symbol)+" Current SMA Value "+str(i.SMA)+" Current Price "+str(i.currentPrice))

        
        rsi_filtered = [x for x in sma_filtered if x.RSI_OK]
        
        if self.verboseLogging:
            self.Debug("Third filter --------> RSI filter")
            for i in rsi_filtered:
                self.Debug(str(i.symbol)+" Current 2 period RSI "+str(i.RSI))

        
        rsi_filtered.sort(key=lambda x: x.STD, reverse=True)
       
        finally_filtered = rsi_filtered[:10]
        
        if self.verboseLogging:
            self.Debug("Fourth filter --------> Top 10 by Standard Deviation")
            for i in finally_filtered:
                self.Debug(str(i.symbol)+" Current Standard Deviation "+str(i.STD))


        # return the symbol objects of the top entries from our sorted collection
        return [ x.symbol for x in finally_filtered[:10] ]
    
   

    '''
    def FineSelectionFunction(self, fine):


        filteredByMktCap = [x for x in fine if x.MarketCap>500000000]
        
        isPrimaryShare = [x for x in filteredByMktCap if x.SecurityReference.IsPrimaryShare]

        # take the top entries from our sorted collection
        return [ x.Symbol for x in isPrimaryShare]        
    '''        

        
    
    def OnData(self, slice):
        
        '''
        self.Debug("###### Instruments we are going to buy")
        for i in self.ActiveSecurities.Keys:
                self.Debug(i.Value)
                self.SetHoldings(i.Value,0.1)
   
        
        #Take profit logic
        if self.Portfolio.Invested: 
            if self.Portfolio.TotalPortfolioValue >  self.initialcash* 1.05:# means a 5% take profit target, if the initial portfolio value is 100000 with 1.05 you will take profit when the value of portfolio is greater than 105 000 $.
                self.Liquidate()
        '''
        
        #Stop loss logic
        if self.Portfolio.Invested: 
            if self.Portfolio.TotalPortfolioValue < self.initialcash*0.90:  # means a 10% stop loss. In this case 0.9 means that the portfolio is valued a 90% of the original value, so if the initial value is 100 000 $ it means 90 000$, a 10% stop loss. if you set self.initialcash*0.5 means a 50% stop loss and so on.
                self.Liquidate()        
        
        
        # this event fires whenever we have changes to our universe
    def OnSecuritiesChanged(self, changes):
        self._changes = changes
        
        '''
    # this event fires whenever we have changes to our universe
    def OnSecuritiesChanged(self, changes):
        # liquidate removed securities
        for security in changes.RemovedSecurities:
            if security.Invested:
                self.Liquidate(security.Symbol)

        
        # we want 20% allocation in each security in our universe
        for security in changes.AddedSecurities:
            self.Debug(security)
            self.SetHoldings(security.Symbol, 0.1)
        
          
        self._changes = changes
        self.Log(f"OnSecuritiesChanged({self.UtcTime}):: {changes}")
        '''
        

        
class SymbolData(object):
    
    def __init__(self, symbol):
        self.symbol = symbol
        self.History = RollingWindow[float](126)# you can't change this
        self.STD = StandardDeviation(126)
        self.SMA = SimpleMovingAverage(200)
        self.SMA_OK = False
        self.riskFreeRate=0.1
        self.RSI = RelativeStrengthIndex(2)
        self.RSI_OK = False
        self.sharpe = 0
        self.SharpeOK = False
        self.currentPrice = 0
        

    def update(self, time, value):
        self.SMA.Update(time,value)
        self.History.Add(float(value))
        self.STD.Update(time,value)
        self.RSI.Update(time, value)
        self.currentPrice=value
        
        if self.History.IsReady and self.STD.IsReady and self.STD.Current.Value != 0:
            totalReturn = (self.History[10]-self.History[125])/self.History[10] 
            sharpeRatio = (totalReturn-self.riskFreeRate)/self.STD.Current.Value
            self.sharpe = sharpeRatio
            self.SharpeOK = sharpeRatio != 0
        
        self.SMA_OK = self.SMA.IsReady and value > self.SMA.Current.Value 
        
        self.RSI_OK = self.RSI.IsReady and self.RSI.Current.Value < 10