Overall Statistics
Total Trades
43
Average Win
57.74%
Average Loss
-6.08%
Compounding Annual Return
36.073%
Drawdown
50.100%
Expectancy
1.487
Net Profit
195.715%
Sharpe Ratio
0.808
Probabilistic Sharpe Ratio
23.685%
Loss Rate
76%
Win Rate
24%
Profit-Loss Ratio
9.50
Alpha
0.415
Beta
-0.274
Annual Standard Deviation
0.481
Annual Variance
0.232
Information Ratio
0.543
Tracking Error
0.54
Treynor Ratio
-1.42
Total Fees
$0.00
Estimated Strategy Capacity
$2400000.00
Lowest Capacity Asset
BTCUSD XJ
Portfolio Turnover
3.17%
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")

from System import *
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Indicators import *
from QuantConnect.Orders import *

class MovingAverageCrossover(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # set start date
        self.SetCash(10000)  # set strategy cash
        self.btc = self.AddCrypto("BTCUSD", Resolution.Daily)  # Bitcoin data

        self.fast = self.EMA("BTCUSD", 14, Resolution.Daily)
        self.slow = self.EMA("BTCUSD", 28, Resolution.Daily)
        self.long_term = self.EMA("BTCUSD", 50, Resolution.Daily)
        self.volume = self.SMA("BTCUSD", 14, Resolution.Daily, Field.Volume)
        self.atr = self.ATR("BTCUSD", 14, MovingAverageType.Simple, Resolution.Daily)

        self.previous = None
        self.stopMarketTicket = None

        # Initialize the rolling window for the ATR values
        self.atrWindow = RollingWindow[IndicatorDataPoint](14)

    def OnData(self, data):
        if not self.fast.IsReady or not self.slow.IsReady or not self.long_term.IsReady or not self.volume.IsReady or not self.atr.IsReady:
            return

        if self.previous is not None and self.previous.date() == self.Time.date():
            return

        # Add the latest ATR value to the rolling window
        self.atrWindow.Add(IndicatorDataPoint(self.btc.Symbol, self.Time, self.atr.Current.Value))

        # Calculate the average ATR
        if self.atrWindow.IsReady:
            avg_atr = sum([ind.Value for ind in self.atrWindow]) / self.atrWindow.Count
        else:
            avg_atr = self.atr.Current.Value

        holdings = self.Portfolio["BTCUSD"].Quantity

        if self.fast.Current.Value > self.slow.Current.Value and self.Securities["BTCUSD"].Close > self.long_term.Current.Value and self.atr.Current.Value > avg_atr:
            if holdings <= 0 and self.btc.Volume > self.volume.Current.Value:
                self.SetHoldings("BTCUSD", 1.0)
                self.stopMarketTicket = self.StopMarketOrder("BTCUSD", 
                                                            -self.Portfolio["BTCUSD"].Quantity, 
                                                            0.9 * self.Securities["BTCUSD"].Close)

        elif self.fast.Current.Value < self.slow.Current.Value and self.Securities["BTCUSD"].Close < self.long_term.Current.Value and self.atr.Current.Value > avg_atr:
            if holdings >= 0 and self.btc.Volume > self.volume.Current.Value:
                self.SetHoldings("BTCUSD", -1.0)
                self.stopMarketTicket = self.StopMarketOrder("BTCUSD", 
                                                            self.Portfolio["BTCUSD"].Quantity, 
                                                            1.1 * self.Securities["BTCUSD"].Close)

        self.previous = self.Time

    def OnOrderEvent(self, orderEvent):
        order = self.Transactions.GetOrderById(orderEvent.OrderId)
        if order.Type == OrderType.StopMarket and orderEvent.Status == OrderStatus.Filled:
            self.stopMarketTicket = None