Overall Statistics
Total Orders
114
Average Win
3.82%
Average Loss
-2.52%
Compounding Annual Return
11.967%
Drawdown
12.300%
Expectancy
0.411
Start Equity
1000.0
End Equity
1711.28
Net Profit
71.128%
Sharpe Ratio
0.653
Sortino Ratio
0.58
Probabilistic Sharpe Ratio
39.335%
Loss Rate
44%
Win Rate
56%
Profit-Loss Ratio
1.51
Alpha
0.075
Beta
0.088
Annual Standard Deviation
0.139
Annual Variance
0.019
Information Ratio
-0.187
Tracking Error
0.505
Treynor Ratio
1.039
Total Fees
â‚®82.39
Estimated Strategy Capacity
â‚®320000000.00
Lowest Capacity Asset
BTCUSDT 18R
Portfolio Turnover
3.35%
Drawdown Recovery
456
from AlgorithmImports import *
import numpy as np

class OptimizedTrendFollowingStrategy(QCAlgorithm):
    """
    Institutional Grade Crypto Trend Following Strategy.
    Optimized by pro-quant standards.
    """
    def Initialize(self):
        self.SetStartDate(2021, 5, 5)
        self.SetAccountCurrency("USDT")
        self.SetCash("USDT", 1000)
        
        # Grid searchable parameters
        self.sma_period = int(self.GetParameter("SmaPeriod") or 50)
        self.atr_period = int(self.GetParameter("AtrPeriod") or 14)
        self.atr_multiplier = float(self.GetParameter("AtrMultiplier") or 2.5)
        self.tp_multiplier = float(self.GetParameter("TpMultiplier") or 5.0) 
        self.risk_per_trade = float(self.GetParameter("RiskPerTrade") or 0.05) 
        self.adx_threshold = float(self.GetParameter("AdxThreshold") or 25)
        
        self.SetBrokerageModel(BrokerageName.Binance, AccountType.Margin)
        self.crypto = self.AddCryptoFuture("BTCUSDT", Resolution.Daily)
        self.symbol = self.crypto.Symbol
        self.crypto.SetSlippageModel(ConstantSlippageModel(0.001))
        
        self.sma = self.SMA(self.symbol, self.sma_period, Resolution.Daily)
        self.atr = self.ATR(self.symbol, self.atr_period, MovingAverageType.Simple, Resolution.Daily)
        self.adx = self.ADX(self.symbol, 14, Resolution.Daily) 
        
        self.SetWarmUp(max(self.sma_period, self.atr_period, 14))
        self.entry_time = None
        self.stop_price = 0.0
        self.tp_price = 0.0
        self.max_holding_days = 10 

    def OnData(self, data: Slice):
        if self.IsWarmingUp or not all([self.sma.IsReady, self.atr.IsReady, self.adx.IsReady]):
            return
            
        current_price = self.Securities[self.symbol].Price
        if current_price == 0: return
        
        sma_val = self.sma.Current.Value
        atr_val = self.atr.Current.Value
        adx_val = self.adx.Current.Value
        
        if self.Portfolio[self.symbol].Invested:
            # Triple Barrier Check
            if current_price <= self.stop_price:
                self.Liquidate(self.symbol, "Stop Loss")
                return
            if current_price >= self.tp_price:
                self.Liquidate(self.symbol, "Take Profit")
                return
            if (self.Time - self.entry_time).days >= self.max_holding_days:
                self.Liquidate(self.symbol, "Time Barrier")
                return
            if current_price < sma_val:
                self.Liquidate(self.symbol, "SMA Exit")
                return

        if not self.Portfolio[self.symbol].Invested:
            # Regime Filter: Only enter in strong trends (ADX > threshold)
            if current_price > sma_val and adx_val > self.adx_threshold:
                stop_dist = atr_val * self.atr_multiplier
                risk_cash = self.Portfolio.TotalPortfolioValue * self.risk_per_trade
                pos_size = risk_cash / stop_dist
                
                self.MarketOrder(self.symbol, pos_size)
                self.entry_time = self.Time
                self.stop_price = current_price - stop_dist
                self.tp_price = current_price + (atr_val * self.tp_multiplier)