Overall Statistics
Total Trades
766
Average Win
0.21%
Average Loss
-0.31%
Compounding Annual Return
11.557%
Drawdown
16.100%
Expectancy
0.122
Net Profit
15.432%
Sharpe Ratio
0.681
Probabilistic Sharpe Ratio
33.155%
Loss Rate
33%
Win Rate
67%
Profit-Loss Ratio
0.66
Alpha
-0.001
Beta
0.458
Annual Standard Deviation
0.16
Annual Variance
0.025
Information Ratio
-0.73
Tracking Error
0.178
Treynor Ratio
0.237
Total Fees
$766.00
Estimated Strategy Capacity
$13000000.00
class RetrospectiveBlueWhale(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetCash(100000)  # Set Strategy Cash
        # self.AddEquity("SPY", Resolution.Minute)
        self.AddUniverse(self.SelectCoarse, self.SelectFine)
        self.UniverseSettings.Resolution = Resolution.Minute
        
        self.symbolDataBySymbol = {}
        
        self.coarseNumber = 100
        self.fineNumber = 10
        self.lastMonth = -1

    def OnData(self, data):
        if self.IsWarmingUp:
            return
        
        for symbol, symbolData in self.symbolDataBySymbol.items():
            rsi = symbolData.Rsi.Current.Value
            
            self.Debug(str(symbol) + " " + str(rsi))
            
            if rsi > 70 and self.Portfolio[symbol].Invested:
                self.Liquidate(symbol, "RSI TOO HIGH")
            elif rsi < 30 and not self.Portfolio[symbol].Invested:
                self.SetHoldings(symbol, 1/self.fineNumber)
        
    def OnSecuritiesChanged(self, changes):
        added = [x for x in changes.AddedSecurities]
        removed = [x for x in changes.RemovedSecurities]
        
        for x in added:
            symbol = x.Symbol
            rsi = self.RSI(symbol, 65, MovingAverageType.Simple, Resolution.Minute)
            sma = self.SMA(symbol, 65, Resolution.Minute, Field.Volume)
            obv = self.OBV(symbol, Resolution.Minute)
            history = self.History(symbol, 65, Resolution.Minute)
            
            for tuple in history.loc[symbol].itertuples():
                rsi.Update(tuple.Index, tuple.close)
                sma.Update(tuple.Index, tuple.volume)
                tradebar = TradeBar(tuple.Index, symbol, tuple.open, tuple.high, tuple.low, tuple.close, tuple.volume)
                obv.Update(tradebar)
                
            symbolData = SymbolData(symbol, rsi, sma)
            self.symbolDataBySymbol[symbol] = symbolData
        
    def SelectCoarse(self, coarse):
        if self.lastMonth == self.Time.month:
            return Universe.Unchanged
        self.lastMonth = self.Time.month
        
        filteredCoarse = sorted([x for x in coarse if x.Price > 50 and x.DollarVolume > 1000], key = lambda x: x.DollarVolume, reverse = True)
        return [x.Symbol for x in filteredCoarse][:self.coarseNumber]
    
    def SelectFine(self, fine):
        filteredFine = sorted([x for x in fine], key = lambda x: x.MarketCap, reverse = True)
        return [x.Symbol for x in filteredFine][:self.fineNumber]
        
class SymbolData:
    def __init__(self, symbol, rsi, sma):
        self.Symbol = symbol
        self.Rsi = rsi
        self.Sma = sma