| 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)