Overall Statistics
Total Trades
17
Average Win
1.89%
Average Loss
-1.15%
Compounding Annual Return
3.878%
Drawdown
23.200%
Expectancy
0.978
Net Profit
4.998%
Sharpe Ratio
0.257
Probabilistic Sharpe Ratio
15.398%
Loss Rate
25%
Win Rate
75%
Profit-Loss Ratio
1.64
Alpha
0.009
Beta
0.267
Annual Standard Deviation
0.147
Annual Variance
0.022
Information Ratio
-0.411
Tracking Error
0.17
Treynor Ratio
0.142
Total Fees
$0.00
Estimated Strategy Capacity
$1600000.00
Lowest Capacity Asset
EOSUSD E3
#region imports
from AlgorithmImports import *
#endregion
class TrailingStopLoss(QCAlgorithm):
    
    def Initialize(self):
        self.SetStartDate(2021, 1, 1)
        self.SetEndDate(2022, 8, 3)
        self.SetCash(100000)
        universe = ['BTCUSD', 'ETHUSD', 'XRPUSD', 'EOSUSD', 'LTCUSD']
        self.pairs = [ Pair(self, ticker) for ticker in universe]
        
        self.entryTicket = None
        self.stopMarketTicket = None
        self.highestPrice = 0

    def OnData(self, data):
        for pair in self.pairs:
        # is rsi ready
         if not pair.sma.IsReady and not pair.rsi.IsReady:
            return
        
        price = data[pair.symbol].Price
        rsi = pair.rsi.Current.Value
        sma = pair.sma.Current.Value
        
        # send entry limit order
        if rsi<25 and sma > price and not self.Portfolio[pair.symbol].Invested:
            self.Debug("rsi is less than 25 and sma is greater than price")
            quantity = self.CalculateOrderQuantity(pair.symbol, 0.2)
            self.entryTicket = self.LimitOrder(pair.symbol, quantity, price, "Entry Order")
            
        
        #trailing stop loss
        if self.stopMarketTicket is not None and self.Portfolio[pair.symbol].Invested:
            # move up trailing stop price
            if price > self.highestPrice:
                self.highestPrice = price
                updateFields = UpdateOrderFields()
                updateFields.StopPrice = price * 0.96
                self.stopMarketTicket.Update(updateFields)
                #self.Debug(updateFields.StopPrice)

    def OnOrderEvent(self, orderEvent):
       for pair in self.pairs:
           
        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(pair.symbol, -self.entryTicket.QuantityFilled, 0.96 * self.entryTicket.AverageFillPrice)
        
        # save fill time of stop loss order (and reset highestPrice)
        if self.stopMarketTicket is not None and self.stopMarketTicket.OrderId == orderEvent.OrderId: 
            self.highestPrice = 0
            
class Pair:
    def __init__(self, algorithm, ticker):
                self.symbol = algorithm.AddCrypto(ticker,Resolution.Daily,Market.Bitfinex).Symbol
                self.rsi = algorithm.RSI(self.symbol,14,MovingAverageType.Simple, Resolution.Daily)
                self.sma = algorithm.SMA(self.symbol,50,Resolution.Daily)
    def OnEndOfDay(self):
        self.Plot("Indicators","RSI", pair.rsi.Current.Value)
        self.Plot("Indicators","SMA", pair.sma.Current.Value)