Overall Statistics |
Total Orders 1380 Average Win 6.97% Average Loss -3.43% Compounding Annual Return 67.302% Drawdown 86.700% Expectancy 0.344 Start Equity 10000 End Equity 2708028.88 Net Profit 26980.289% Sharpe Ratio 1.141 Sortino Ratio 1.478 Probabilistic Sharpe Ratio 25.338% Loss Rate 56% Win Rate 44% Profit-Loss Ratio 2.03 Alpha 0.804 Beta 0.69 Annual Standard Deviation 0.753 Annual Variance 0.566 Information Ratio 1.043 Tracking Error 0.747 Treynor Ratio 1.245 Total Fees $738563.39 Estimated Strategy Capacity $41000000000000000000.00 Lowest Capacity Asset ADAUSD 2XR Portfolio Turnover 27.48% |
from AlgorithmImports import * import numpy as np class MomentumBasedCryptoSelector(QCAlgorithm): def Initialize(self): self.SetStartDate(2014, 1, 1) # self.SetEndDate(2022, 6, 1) self.SetCash(10000) # Set starting cash in USD # Updated list of crypto pairs to include the new assets self.crypto_symbols = [ "BTCUSD", "ETHUSD", "LTCUSD", "XRPUSD", "BCHUSD", "ADAUSD", "DOGEUSD", "SOLUSD", "DOTUSD", "MATICUSD", "HNTUSD", "STXUSD", "MKRUSD" ] # Add all crypto pairs and apply the Binance fee model self.symbols = [] for symbol in self.crypto_symbols: crypto = self.AddCrypto(symbol, Resolution.Daily) crypto.SetFeeModel(BinanceFeeModel()) # Apply the Binance fee model self.symbols.append(crypto.Symbol) # Warm-up period to ensure data availability (based on lookback period and SMA period) self.lookback_period = 5 # Set the lookback period as a variable self.sma_period = 50 # Set the SMA period as a variable self.SetWarmUp(self.sma_period) # Maximum allocation rule: 80% of the total portfolio value self.max_allocation_percentage = 0.8 def OnData(self, slice): if self.IsWarmingUp: return # Dictionary to store momentum values for each symbol momentum_scores = {} # Calculate momentum and apply the SMA filter for each crypto pair for symbol in self.symbols: history = self.History(symbol, max(self.lookback_period, self.sma_period), Resolution.Daily) if history.empty or len(history["close"]) < self.sma_period: continue close_prices = history["close"].values # Calculate the 50-period SMA sma = np.mean(close_prices[-self.sma_period:]) # Check if the current price is above the SMA if close_prices[-1] < sma: continue # Skip symbols trading below their 50 SMA # Calculate momentum as the change in price over the lookback period momentum = close_prices[-1] - close_prices[-self.lookback_period] momentum_scores[symbol] = momentum # If no momentum scores were calculated, return if not momentum_scores: return # Find the symbol with the highest momentum best_symbol = max(momentum_scores, key=momentum_scores.get) # If already invested in the best symbol, do nothing if self.Portfolio[best_symbol].Invested: return # Liquidate any other holdings for symbol in self.symbols: if symbol != best_symbol and self.Portfolio[symbol].Invested: self.Liquidate(symbol) # Calculate the amount to invest based on the 80% maximum allocation rule available_cash = self.Portfolio.Cash max_investment_value = self.Portfolio.TotalPortfolioValue * self.max_allocation_percentage # Determine the proportion to allocate to the best symbol allocation_percentage = max_investment_value / self.Portfolio.TotalPortfolioValue # Invest in the symbol with the highest momentum, limited to 80% of total portfolio value self.SetHoldings(best_symbol, allocation_percentage) self.Debug(f"Entering Long Position: {best_symbol} with Momentum: {momentum_scores[best_symbol]} and Allocation: {allocation_percentage * 100:.2f}%")