Overall Statistics
Total Trades
245
Average Win
2.52%
Average Loss
-0.96%
Compounding Annual Return
26.690%
Drawdown
25.800%
Expectancy
0.396
Net Profit
60.795%
Sharpe Ratio
0.834
Probabilistic Sharpe Ratio
33.729%
Loss Rate
61%
Win Rate
39%
Profit-Loss Ratio
2.62
Alpha
0.245
Beta
-0.02
Annual Standard Deviation
0.262
Annual Variance
0.069
Information Ratio
-1.802
Tracking Error
0.624
Treynor Ratio
-11.109
Total Fees
$0.00
Estimated Strategy Capacity
$180000.00
Lowest Capacity Asset
XLMUSD E3
class CreativeRedHornet(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 1, 1)
        self.SetEndDate(2021, 1, 1)
        self.SetCash(100000)
        
        universe = ['BTCUSD', 'LTCUSD', 'ETHUSD', 'ETCUSD', 'RRTUSD', 'ZECUSD', 'XMRUSD', 'XRPUSD', 'EOSUSD', 'SANUSD', 'OMGUSD', 'NEOUSD', 'ETPUSD', 'BTGUSD', 'SNTUSD', 'BATUSD', 'FUNUSD', 'ZRXUSD', 'TRXUSD', 'REQUSD', 'LRCUSD', 'WAXUSD', 'DAIUSD', 'BFTUSD', 'ODEUSD', 'ANTUSD', 'XLMUSD', 'XVGUSD', 'MKRUSD', 'KNCUSD', 'LYMUSD', 'UTKUSD', 'VEEUSD', 'ESSUSD', 'IQXUSD', 'ZILUSD', 'BNTUSD', 'XRAUSD', 'VETUSD', 'GOTUSD', 'XTZUSD', 'MLNUSD', 'PNKUSD', 'DGBUSD', 'BSVUSD', 'ENJUSD', 'PAXUSD']
        # add data for all tickers
        self.symbols = [ self.AddCrypto(ticker, Resolution.Daily, Market.Bitfinex).Symbol for ticker in universe ]
        self.SetBenchmark(self.symbols[0])
        
        self.rsis = {}
        # add rsi for all symbols
        for symbol in self.symbols:
            self.rsis[symbol] = self.RSI(symbol, 14,  MovingAverageType.Simple, Resolution.Daily)
        
        self.Settings.FreePortfolioValuePercentage = 0.05
        
        self.maxPos = 5 # max number os positions to open at once
        self.rsiEntryThreshhold = 70 # enter position if rsi rises above this threshhold
        self.rsiExitThreshhold = 65 # exit position if rsi drops below this threshhold
        self.minVolume = 1000000 # filters out symbols with 5 day dollar volume less than this
        
        self.active = []
        self.UniverseSelection()
        self.Schedule.On(self.DateRules.MonthStart(), self.TimeRules.At(12, 0), self.UniverseSelection)


    def UniverseSelection(self):
        # filters out symbols with too low 22 day avg daily dollar volume
        self.active = []
        for symbol in self.symbols:
            hist = self.History(symbol, 22, Resolution.Daily)
            if "volume" in hist.columns and hist.loc[symbol]['volume'].mean() * hist.loc[symbol]['close'].mean() >= self.minVolume:
                self.active.append(symbol)
        self.Log("Universe: " + str([str(symbol) for symbol in self.active]))
    

    def OnData(self, data):
        for symbol in self.symbols:
            if not self.rsis[symbol].IsReady:
                return
            if symbol not in self.active:
                # liquidate symbols outside of active universe
                self.Liquidate(symbol, "Not enough volume")
        
        # number of open positions
        invested = len([x.Key for x in self.Portfolio if x.Value.Invested])
        
        for symbol in self.active:
            rsi = self.rsis[symbol]
            if self.Portfolio[symbol].Invested: 
                if self.rsis[symbol].Current.Value < self.rsiExitThreshhold:
                    self.Liquidate(symbol, "RSI below threshhold")
                    invested -= 1
            elif rsi.Current.Value > self.rsiEntryThreshhold and invested < self.maxPos:
                self.SetHoldings(symbol, 1 / (self.maxPos+1))
                invested += 1