| Overall Statistics |
|
Total Orders 1444 Average Win 0.79% Average Loss -0.23% Compounding Annual Return 21.654% Drawdown 32.500% Expectancy 0.616 Start Equity 100000.00 End Equity 278121.36 Net Profit 178.121% Sharpe Ratio 0.7 Sortino Ratio 0.816 Probabilistic Sharpe Ratio 24.099% Loss Rate 64% Win Rate 36% Profit-Loss Ratio 3.50 Alpha 0.035 Beta 0.168 Annual Standard Deviation 0.213 Annual Variance 0.045 Information Ratio -1.045 Tracking Error 0.502 Treynor Ratio 0.883 Total Fees $0.00 Estimated Strategy Capacity $3000.00 Lowest Capacity Asset DAIUSD E3 Portfolio Turnover 1.32% |
#region imports
from AlgorithmImports import *
#endregion
class CreativeRedHornet(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 1, 1)
#self.SetEndDate(2024, 6, 12)
self.SetCash(100000)
self.Settings.FreePortfolioValuePercentage = 0.05
self.positionSizeUSD = 3500
self.rsiEntryThreshold = 60 # Lowering entry threshold to encourage more trades
self.rsiExitThreshold = 35 # Raising exit threshold
self.minimumVolume = 50000 # Lowering volume constraint
# 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(30)
self.Debug("Initialization complete")
def OnData(self, data):
if self.IsWarmingUp:
return
for pair in self.pairs:
if not pair.rsi.IsReady:
self.Debug(f"{pair.symbol} RSI not ready")
continue
symbol = pair.symbol
rsi = pair.rsi.Current.Value
investable = pair.Investable()
self.Debug(f"Processing {symbol}: RSI={rsi}, Investable={investable}, Invested={self.Portfolio[symbol].Invested}")
# Selling
if self.Portfolio[symbol].Invested:
if not investable:
self.Debug(f"Liquidating {symbol} due to volume constraint")
self.Liquidate(symbol, "Not enough volume")
elif rsi < self.rsiExitThreshold:
self.Debug(f"Liquidating {symbol} due to RSI below threshold: RSI={rsi}")
self.Liquidate(symbol, "RSI below threshold")
continue
if not investable:
self.Debug(f"{symbol} is not investable due to volume constraint")
continue
# Buying
if rsi > self.rsiEntryThreshold and self.Portfolio.MarginRemaining > self.positionSizeUSD:
self.Debug(f"Buying {symbol}: RSI={rsi}, Price={self.Securities[symbol].Price}")
self.Buy(symbol, self.positionSizeUSD / self.Securities[symbol].Price)
else:
if rsi <= self.rsiEntryThreshold:
self.Debug(f"RSI for {symbol} is not above entry threshold: RSI={rsi}")
if self.Portfolio.MarginRemaining <= self.positionSizeUSD:
self.Debug(f"Not enough margin remaining to buy {symbol}")
class Pair:
def __init__(self, algorithm, ticker, minimumVolume):
self.symbol = algorithm.AddCrypto(ticker, Resolution.Daily, Market.Bitfinex).Symbol
self.rsi = algorithm.RSI(self.symbol, 14, MovingAverageType.Simple, Resolution.Daily)
self.volume = IndicatorExtensions.Times(algorithm.SMA(self.symbol, 30, Resolution.Daily, Field.Volume),
algorithm.SMA(self.symbol, 30, Resolution.Daily, Field.Close))
self.minimumVolume = minimumVolume
def Investable(self):
return (self.volume.Current.Value > self.minimumVolume)