Overall Statistics
Total Trades
238
Average Win
0.53%
Average Loss
-0.43%
Compounding Annual Return
3.466%
Drawdown
9.600%
Expectancy
0.036
Net Profit
1.732%
Sharpe Ratio
0.279
Probabilistic Sharpe Ratio
28.704%
Loss Rate
54%
Win Rate
46%
Profit-Loss Ratio
1.24
Alpha
0.011
Beta
0.092
Annual Standard Deviation
0.136
Annual Variance
0.019
Information Ratio
-1.473
Tracking Error
0.173
Treynor Ratio
0.414
Total Fees
$261.98
Estimated Strategy Capacity
$680000.00
Lowest Capacity Asset
IHF TIDDZIE7WNZ9
import heapq

class PensiveBlackSalamander(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2021, 1, 28)
        self.SetCash(100000) 
        self.AddUniverse(self.MyCoarseFilterFunction)
        self.selected = []
        self.UniverseSettings.Resolution = Resolution.Daily
        self.dataBySymbol = {}
        self.AddEquity("SPY")
        self.Schedule.On(self.DateRules.MonthStart("SPY"), \
                 self.TimeRules.AfterMarketOpen("SPY"), \
                 self.liquidate)
    def liquidate(self):
        self.Liquidate()
        

    def MyCoarseFilterFunction(self, coarse):
         
         
         sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
         filtered = [ x for x in sortedByDollarVolume 
                      if x.Price > 10 and x.DollarVolume > 10000000 ]
        # probably want some different logic for filtered or none at all
#         filtered = filtered[:20]
         filtered = filtered
         self.selected = []
         self.heap = []
         for x in filtered:
             if x.Symbol not in self.dataBySymbol:
                 self.dataBySymbol[x.Symbol] = SymbolData(self,x.Symbol)
             self.dataBySymbol[x.Symbol].roc.Update(self.Time,x.Price)
             self.dataBySymbol[x.Symbol].rocd.Update(self.Time,x.Price)
             if self.dataBySymbol[x.Symbol].IsReady:
                 #https://docs.python.org/3/library/heapq.html
                heapq.heappush(self.heap, (self.dataBySymbol[x.Symbol].rocd.Current.Value, x.Symbol))

        # choose the 5 largest in the heap
         for h in heapq.nlargest(5,self.heap):
             self.selected.append(h[1])
         
         self.Debug(str(self.selected))
         return self.selected
         
    def OnData(self, data):
        for symbol in self.selected:
            if not self.Portfolio[symbol].Invested:
                self.SetHoldings(symbol,1/len(self.selected))
    
    def OnSecuritiesChanged(self,changes):
        for x in changes.RemovedSecurities:
            self.dataBySymbol.pop(x.Symbol,None)
            self.Liquidate(x.Symbol)
class SymbolData:
    def __init__(self,algo,symbol):
        self.roc = RateOfChange(252)
        self.rocd = IndicatorExtensions.Of(Delay(21), self.roc)
        self.symbol = symbol
        history = algo.History(symbol,252,Resolution.Daily)
        if not  history.empty:
            for time, row in history.loc[symbol].iterrows():
                self.roc.Update(time,row['close'])
                self.rocd.Update(time,row['close'])
    @property
    def IsReady(self):
        return self.roc.IsReady
        return self.rocd.IsReady