Overall Statistics
Total Orders
1262
Average Win
124.45%
Average Loss
-3.74%
Compounding Annual Return
85.423%
Drawdown
47.500%
Expectancy
6.442
Start Equity
100000.00
End Equity
1187694.30
Net Profit
1087.694%
Sharpe Ratio
1.372
Sortino Ratio
1.638
Probabilistic Sharpe Ratio
53.368%
Loss Rate
78%
Win Rate
22%
Profit-Loss Ratio
33.23
Alpha
0.727
Beta
0.352
Annual Standard Deviation
0.561
Annual Variance
0.315
Information Ratio
1.143
Tracking Error
0.569
Treynor Ratio
2.184
Total Fees
$0.00
Estimated Strategy Capacity
$16000000.00
Lowest Capacity Asset
BTCUSD 2XR
Portfolio Turnover
2.99%
from AlgorithmImports import *

class TechnicalIndicatorsAlgorithm(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2018, 1, 1)  # Set Start Date
        self.SetEndDate(2022, 1, 1)    # Set End Date
        self.SetCash(100000)           # Set Strategy Cash

        # Add cryptocurrency pairs
        self.crypto_symbols = [
            self.AddCrypto("BTCUSD", Resolution.DAILY).Symbol,
            self.AddCrypto("ETHUSD", Resolution.DAILY).Symbol,
            self.AddCrypto("LTCUSD", Resolution.DAILY).Symbol,
            self.AddCrypto("BCHUSD", Resolution.DAILY).Symbol,
            self.AddCrypto("XRPUSD", Resolution.DAILY).Symbol,
            self.AddCrypto("ADAUSD", Resolution.DAILY).Symbol,
            self.AddCrypto("DOTUSD", Resolution.DAILY).Symbol,
            self.AddCrypto("LINKUSD", Resolution.DAILY).Symbol,
            self.AddCrypto("SOLUSD", Resolution.DAILY).Symbol
        ]

        self.entry_prices = {}
        self.stop_prices = {}

        # Define indicators
        self.indicators = {}
        for symbol in self.crypto_symbols:
            self.indicators[symbol] = {
                'hammer': self.CandlestickPatterns.Hammer(symbol),
                'hanging_man': self.CandlestickPatterns.HangingMan(symbol),
                'doji': self.CandlestickPatterns.Doji(symbol),
                'spinning_top': self.CandlestickPatterns.SpinningTop(symbol),
                'engulfing': self.CandlestickPatterns.Engulfing(symbol),
                'rsi': self.RSI(symbol, 14, MovingAverageType.Wilders, Resolution.DAILY),
                'sma10': self.SMA(symbol, 10, Resolution.DAILY),
                'sma05': self.SMA(symbol, 5, Resolution.DAILY),
                'ema20': self.EMA(symbol, 20, Resolution.DAILY),
                'sma30': self.SMA(symbol, 30, Resolution.DAILY),
                'sma50': self.SMA(symbol, 50, Resolution.DAILY),
                'sma200': self.SMA(symbol, 200, Resolution.DAILY),
                'sma600': self.SMA(symbol, 600, Resolution.DAILY),
                'sma40': self.SMA(symbol, 40, Resolution.DAILY),
                'sma120': self.SMA(symbol, 120, Resolution.DAILY),
                'ema05': self.EMA(symbol, 5, Resolution.DAILY),
                'ema10': self.EMA(symbol, 10, Resolution.DAILY),
                'ema30': self.EMA(symbol, 30, Resolution.DAILY),
                'ema65': self.EMA(symbol, 65, Resolution.DAILY),
                'ema100': self.EMA(symbol, 100, Resolution.DAILY),
                'ema150': self.EMA(symbol, 150, Resolution.DAILY),
                'ema500': self.EMA(symbol, 500, Resolution.DAILY),
                'ema600': self.EMA(symbol, 600, Resolution.DAILY)
            }

    def OnData(self, data):
        for symbol in self.crypto_symbols:
            if not data.ContainsKey(symbol):
                continue

            price = data[symbol].Close

            indicators = self.indicators[symbol]

            # Buy condition
            if indicators['rsi'].Current.Value > 55 and (indicators['ema10'].Current.Value > indicators['ema20'].Current.Value > indicators['ema65'].Current.Value > indicators['ema150'].Current.Value):
                if not self.Portfolio[symbol].Invested:
                    self.SetHoldings(symbol, 1)
                    self.entry_prices[symbol] = price
                    #self.stop_prices[symbol] = price * 0.95

            # Sell condition
            elif indicators['rsi'].Current.Value < 40 and ((indicators['ema10'].Current.Value < indicators['ema65'].Current.Value) or (indicators['ema20'].Current.Value < indicators['ema65'].Current.Value)):
                if self.Portfolio[symbol].Invested:
                    self.Liquidate(symbol)
                    self.entry_prices[symbol] = None
                    self.stop_prices[symbol] = None

             #Stop-loss condition
            if self.Portfolio[symbol].Invested and self.entry_prices.get(symbol) is not None:
                if price < self.entry_prices[symbol]*0.99:
                    self.Liquidate(symbol)
                    self.entry_prices[symbol] = None

            # Trailing stop-loss
            #if self.Portfolio[symbol].Invested:
            #    self.stop_prices[symbol] = max(self.stop_prices[symbol], price * 0.85)
            #    if price < self.stop_prices[symbol]:
            #        self.Liquidate(symbol)
            #        self.stop_prices[symbol] = None

    def PlotIndicators(self):
        for symbol in self.crypto_symbols:
            indicators = self.indicators[symbol]
            self.Plot(f"RSI_{symbol}", "RSI", indicators['rsi'].Current.Value)
            self.Plot(f"SMA_{symbol}", "SMA10", indicators['sma10'].Current.Value)
            self.Plot(f"SMA_{symbol}", "SMA20", indicators['sma20'].Current.Value)