| Overall Statistics |
|
Total Trades 4459 Average Win 0.40% Average Loss -0.41% Compounding Annual Return 89.939% Drawdown 46.500% Expectancy 0.166 Net Profit 206.252% Sharpe Ratio 1.478 Probabilistic Sharpe Ratio 54.403% Loss Rate 41% Win Rate 59% Profit-Loss Ratio 0.98 Alpha 0.853 Beta -0.005 Annual Standard Deviation 0.572 Annual Variance 0.327 Information Ratio -0.706 Tracking Error 0.831 Treynor Ratio -155.833 Total Fees $0.00 Estimated Strategy Capacity $470000.00 Lowest Capacity Asset ZECUSD E3 |
class CreativeRedHornet(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 1, 1)
self.SetEndDate(2021, 9, 28)
self.SetCash(100000)
self.positionSizeUSD = 10000
self.Settings.FreePortfolioValuePercentage = 0.05
self.rsiEntryThreshold = 10 # enter position if rsi rises below this threshold
self.rsiExitThreshold = 60 # exit position if rsi rises above this threshold
self.minimumVolume = 1000000 # filters out symbols with 30 day avg daily dollar volume less than this
# add data for all tickers
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']
self.pairs = [ Pair(self, ticker, self.minimumVolume) for ticker in universe ]
self.SetBenchmark("BTCUSD")
self.SetWarmup(55)
def ProcessLiquidations(self, data):
for pair in self.pairs:
if not pair.rsi.IsReady:
return
symbol = pair.symbol
rsi = pair.rsi.Current.Value
if self.Portfolio[symbol].Invested:
if not pair.Investable():
self.Liquidate(symbol, "Not enough $ volume")
elif rsi > self.rsiExitThreshold:
self.Liquidate(symbol, "RSI above threshold")
continue
def ProcessBuys(self, data):
for pair in self.pairs:
if not pair.rsi.IsReady:
return
symbol = pair.symbol
rsi = pair.rsi.Current.Value
if rsi > self.rsiEntryThreshold and self.Portfolio.MarginRemaining > self.positionSizeUSD:
if pair.Investable():
self.Buy(symbol, self.positionSizeUSD / self.Securities[symbol].Price)
def OnData(self, data):
self.ProcessLiquidations(data)
self.ProcessBuys(data)
class Pair:
def __init__(self, algorithm, ticker, minimumVolume):
self.symbol = algorithm.AddCrypto(ticker, Resolution.Daily, Market.Bitfinex).Symbol
self.rsi = algorithm.RSI(self.symbol, 4, MovingAverageType.Simple, Resolution.Daily)
self.sma10 = algorithm.SMA(self.symbol, 10, Resolution.Daily, Field.Close)
self.sma50 = algorithm.SMA(self.symbol, 50, Resolution.Daily, Field.Close)
self.dollarVolume = IndicatorExtensions.Times(algorithm.SMA(self.symbol, 30, Resolution.Daily, Field.Volume), algorithm.SMA(self.symbol, 30, Resolution.Daily, Field.Close))
self.minimumVolume = minimumVolume
def IsInUpTrend(self):
return (self.sma10.Current.Value > self.sma50.Current.Value)
def Investable(self):
canInvest = True
if self.dollarVolume.Current.Value < self.minimumVolume:
canInvest = False
if not self.IsInUpTrend():
canInvest = False
return canInvest