Overall Statistics
Total Trades
37
Average Win
0.27%
Average Loss
-1.07%
Compounding Annual Return
4.860%
Drawdown
28.800%
Expectancy
-0.896
Net Profit
6.271%
Sharpe Ratio
0.267
Probabilistic Sharpe Ratio
15.793%
Loss Rate
92%
Win Rate
8%
Profit-Loss Ratio
0.25
Alpha
-0.003
Beta
0.664
Annual Standard Deviation
0.267
Annual Variance
0.071
Information Ratio
-0.157
Tracking Error
0.257
Treynor Ratio
0.107
Total Fees
$0.00
Estimated Strategy Capacity
$10000000.00
Lowest Capacity Asset
EOSUSD XJ
#region imports
from AlgorithmImports import *
#endregion

# Cryptos RSI and SMA with Stop Loss

# ------------------------------------------------------------------------------------------
CRYPTOS = ['BTCUSD', 'ETHUSD', 'EOSUSD', 'LTCUSD','XRPUSD']; MA = 50; RSI = 14;  SL = 0.04;
# ------------------------------------------------------------------------------------------

class CryptosRSIandSMA(QCAlgorithm):
    
    def Initialize(self):
        self.SetStartDate(2021, 1, 1)
        self.SetCash(100000)
        
        self.stopMarketTicket = None
        self.entryTicket = None

        self.cryptos = [self.AddCrypto(ticker, Resolution.Daily).Symbol for ticker in CRYPTOS]
        self.sma = {}; self.rsi = {}; self.enter_price={}; self.highestPrice={};
        for sec in self.cryptos:
            self.sma[sec] = self.SMA(sec, MA, Resolution.Daily)
            self.rsi[sec] = self.RSI(sec, RSI, MovingAverageType.Simple, Resolution.Daily)
            self.enter_price[sec] = 0            
            self.highestPrice[sec] = 0
        self.SetWarmUp(max(MA, RSI), Resolution.Daily)


    def OnData(self, data):
        if self.IsWarmingUp: return
        for sec in self.cryptos:
            if not self.sma[sec].IsReady or not self.rsi[sec].IsReady: continue
            rsi = self.rsi[sec].Current.Value
            price =  self.Securities[sec].Price
            sma = self.sma[sec].Current.Value
            quantity = self.CalculateOrderQuantity(sec, 0.19)
            pnl = self.Securities[sec].Holdings.UnrealizedProfitPercent
            

            if not self.Portfolio[sec].Invested:
                if rsi <25 and sma > price:
                    self.entryTicket = self.LimitOrder(sec, quantity, price, "entry order")
                    self.enter_price[sec] = price

            elif self.Portfolio[sec].Invested and self.stopMarketTicket is not None:
                if self.enter_price[sec] > self.highestPrice[sec]:
                     self.highestPrice[sec] = price
                     updateFields = UpdateOrderFields()
                     updateFields.StopPrice = price * 0.96
                     self.stopMarketTicket.Update(updateFields)
                     self.Debug(updateFields.StopPrice)

                   
    def OnOrderEvent(self, orderEvent):
       for sec in self.cryptos:
           
        if orderEvent.Status != OrderStatus.Filled:
            return
        
        # send stop loss order if entry limit order is filled
        if self.entryTicket is not None and self.entryTicket.OrderId == orderEvent.OrderId:
            self.stopMarketTicket = self.StopMarketOrder(sec, -self.entryTicket.QuantityFilled, 0.96 * self.enter_price[sec])
            
        
        # save fill time of stop loss order (and reset highestPrice)
        if self.stopMarketTicket is not None and self.stopMarketTicket.OrderId == orderEvent.OrderId: 
            self.highestPrice[sec] = 0
            self.enter_price[sec]=0
            
                    
                    
    def OnEndOfDay(self, symbol):   
        if self.IsWarmingUp: return
        for sec in self.cryptos:
            if not self.sma[sec].IsReady or not self.rsi[sec].IsReady: continue
            self.Plot("RSI", sec, self.rsi[sec].Current.Value)
            self.Plot("RSI", 'threshold', 25)
            self.Plot("SMA", sec, self.sma[sec].Current.Value)