
The EMA Crossover Smart DCA with Dual Trailing Stop System is a quantitative trading strategy based on technical analysis and sophisticated capital management. This strategy utilizes Exponential Moving Average (EMA) crossover signals to identify potential uptrends, combines Dollar-Cost Averaging (DCA) for intelligent position building, and implements a dual trailing stop mechanism to protect profits. The core of the strategy relies on using fast and slow EMA crossovers to determine entry points, automatically deploying up to two Safety Orders when price declines, calculating additional position entries using Average True Range (ATR) or fixed percentages, and employing a dual-layer trailing stop system (standard trailing stop and profit lock-in trailing stop) to protect capital. The strategy also integrates date filtering and trade cooldown periods, providing quantitative traders with a complete risk management and capital allocation system.
The strategy operates based on several key components:
Trend Identification Mechanism: Uses a fast EMA (default 9-period) and slow EMA (default 21-period) crossover to identify potential uptrends. When the fast EMA crosses above the slow EMA, the system generates a buy signal.
Base Orders and Safety Orders: The strategy employs a tiered capital management approach, starting with a base order (default \(1000) and adding two additional safety orders (SO1 default \)1250, SO2 default $1750) as price declines.
Dynamic Spacing Calculation: Safety order trigger prices can be calculated in two ways:
Dual Trailing Stop System:
Exit Conditions: The strategy closes positions when:
Cooldown Period and Date Filter: The strategy includes a cooldown period after base orders (default 4 hours) and an optional date filter to limit backtesting or execution to specific time periods.
Analyzing the strategy code in depth, we can summarize the following key advantages:
Adaptive Capital Management: The strategy combines DCA with dynamic safety orders, automatically adjusting positions according to market conditions. This approach is particularly effective in volatile markets, reducing average entry price and increasing potential profits.
Volatility-Based Position Adjustment: By calculating safety order positions using ATR, the strategy can automatically adjust entry spacing based on current market volatility, providing more flexibility than fixed percentage methods.
Dual Profit Protection: The dual trailing stop system provides innovative risk management, with the standard trailing stop protecting the majority of capital while the profit lock-in mechanism activates after reaching a specific profit target, protecting gained profits with a tighter percentage.
Fully Customizable: All key parameters (EMA lengths, order sizes, trailing stop percentages, safety order spacing) can be adjusted according to trader risk preferences and market conditions.
Integrated Alert System: The strategy includes formatted alert conditions that can integrate with third-party automation platforms (like 3Commas) for fully automated trading.
Transparent Debugging Information: Includes a detailed debug table displaying key trading metrics and states, facilitating real-time monitoring and strategy optimization.
Despite its numerous advantages, the strategy still has the following potential risks:
Solution: Adjust trailing stop percentages and safety order spacing according to specific instruments and timeframes; consider adding a global stop loss as an additional protection layer.
Solution: Conduct extensive backtesting and optimization for specific trading instruments and market conditions; implement adaptive parameter adjustment mechanisms.
Solution: Consider implementing more flexible safety order trigger mechanisms, such as time-based forced execution or adjusting spacing under specific market conditions.
Solution: Add trading filters such as volatility thresholds or trend strength confirmation; extend cooldown periods to reduce trading frequency.
Solution: Consider integrating fundamental filters or risk sentiment indicators; add cross-market correlation checks as confirmation signals.
Based on in-depth analysis of the strategy code, here are several possible optimization directions:
Adaptive Parameter Adjustment: Implement a mechanism to automatically adjust EMA lengths and ATR multipliers based on market volatility or trading volume. For example, use longer EMAs and larger ATR multipliers in high-volatility environments, and shorter EMAs and smaller ATR multipliers in low-volatility environments. This will improve strategy adaptability across different market conditions.
Multiple Confirmation Signals: Add additional confirmation indicators such as Relative Strength Index (RSI), volume, or Bollinger Bands to reduce false signals. Filters can be implemented requiring multiple technical indicators to simultaneously confirm entry signals, thereby improving signal quality.
Dynamic Capital Allocation: Adjust order sizes based on market conditions and historical volatility. For example, increase base order size during periods of lower volatility or historically more likely upward markets, while reducing it in high-risk environments.
Intelligent Exit Strategy: Implement partial profit-taking mechanisms, allowing for gradual exits at different profit levels rather than all-at-once position closing. This can be achieved by setting multiple profit targets with corresponding exit percentages, optimizing the risk-reward ratio.
Sentiment Indicator Integration: Add market sentiment analysis, such as Fear and Greed Index or volume analysis, as additional filters for entries and exits. This will help the strategy avoid unnecessary trades during periods of extreme market sentiment.
Risk Exposure Management: Implement functionality to dynamically calculate maximum risk exposure (sum of all possible safety orders) and set acceptable maximum risk limits. This will ensure the strategy never overexposes capital to a single trade at any time.
The EMA Crossover Smart DCA with Dual Trailing Stop System is a well-designed quantitative trading strategy that combines trend detection, tiered position building, and advanced stop management. Its core strengths lie in its ability to adapt to market volatility, intelligent capital management, and dual-layer profit protection system. The strategy is particularly suitable for moderately volatile market environments where trends have sufficient persistence and directionality.
With appropriate parameter optimization and suggested enhancements, the strategy can further improve its performance and robustness. In particular, adaptive parameter adjustment and multiple confirmation signals could significantly improve entry quality, while dynamic capital allocation and intelligent exit strategies could optimize risk-reward characteristics.
Ultimately, this strategy represents a balanced quantitative trading approach with a focus on capital preservation and consistency rather than maximizing profit on each trade. It provides traders with a robust framework that can be customized according to individual risk preferences and market conditions, potentially achieving long-term sustainable trading results.
/*backtest
start: 2025-04-15 00:00:00
end: 2025-07-13 19:30:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT","balance":200000}]
*/
//@version=5
strategy(
title="DCA + Dual Trailing Strategy",
overlay=true
)
// --- Trend ---
fastMALen = input.int(9, title="Fast EMA Length")
slowMALen = input.int(21, title="Slow EMA Length")
// --- Trailing Stops ---
trailStopPerc = input.float(8.0, title="Standard Trailing Stop (%)", minval=0.1) / 100
lockInThreshold = input.float(2.5, title="Profit Lock-In Trigger (%)", minval=0.1) / 100
lockInTrailPct = input.float(1.5, title="Lock-In Trail (%) after Trigger", minval=0.1) / 100
// --- Safety Orders (SO) ---
useATRSpacing = input.bool(true, title="Use ATR-Based Spacing?")
atrLength = input.int(14, title="ATR Length", minval=1)
atrSo1Multiplier = input.float(1.2, title="ATR SO1 Multiplier", minval=0.1)
atrSo2Multiplier = input.float(2.5, title="ATR SO2 Multiplier", minval=0.1)
// --- Fallback SO Spacing (if not using ATR) ---
fallbackSo1Perc = input.float(4.0, title="Fallback SO1 Drop (%) ", minval=0.1) / 100
fallbackSo2Perc = input.float(8.0, title="Fallback SO2 Drop (%) ", minval=0.1) / 100
// --- Entry Cooldown ---
cooldownBars = input.int(4, "Cooldown Bars After Base Entry", minval=0)
// --- Order Sizes in USD ---
baseUsd = input.float(10000.0, title="Base Order Size (USD)", minval=1.0)
so1Usd = input.float(12500.0, title="Safety Order 1 Size (USD)", minval=1.0)
so2Usd = input.float(17500.0, title="Safety Order 2 Size (USD)", minval=1.0)
// 2) CALCULATIONS
// --- Trend & Reversal Detection ---
fastMA = ta.ema(close, fastMALen)
slowMA = ta.ema(close, slowMALen)
trendUp = ta.crossover(fastMA, slowMA)
trendDown = ta.crossunder(fastMA, slowMA)
// --- ATR Value ---
atrValue = ta.atr(atrLength)
// 3) BASE ENTRY LOGIC
// Base Buy Signal: EMA crossover
baseBuySignal = trendUp
var int lastBuyBar = na // Tracks the bar index of the last base entry
inCooldown = not na(lastBuyBar) and (bar_index - lastBuyBar < cooldownBars)
var float baseEntryPrice = na // Stores the price of the initial base entry for SO calculations
// --- Execute Base Entry ---
if baseBuySignal and strategy.position_size == 0 and not inCooldown
baseQty = baseUsd / close // Calculate quantity based on USD
strategy.order("Base Order", strategy.long, qty=baseQty, comment="Base Entry")
baseEntryPrice := close
lastBuyBar := bar_index
// 4) SAFETY ORDERS LOGIC
// --- Calculate SO Trigger Prices ---
float so1TriggerPrice = na
float so2TriggerPrice = na
if strategy.position_size > 0 // Only calculate if a base order has been placed
so1TriggerPrice := useATRSpacing ?
(baseEntryPrice - atrValue * atrSo1Multiplier) :
(baseEntryPrice * (1 - fallbackSo1Perc))
so2TriggerPrice := useATRSpacing ?
(baseEntryPrice - atrValue * atrSo2Multiplier) :
(baseEntryPrice * (1 - fallbackSo2Perc))
// --- Conditions for SO Execution ---
// Added 'inDateRange' check
// Ensure base order exists, price trigger hit, and the specific SO hasn't filled yet
bool so1Condition = strategy.position_size > 0 and close <= so1TriggerPrice and strategy.opentrades == 1
bool so2Condition = strategy.position_size > 0 and close <= so2TriggerPrice and strategy.opentrades == 2
// --- Execute SO1 ---
if so1Condition
so1Qty = so1Usd / close // Calculate quantity based on USD
strategy.order("Safety Order 1", strategy.long, qty=so1Qty, comment="SO1")
// --- Execute SO2 ---
if so2Condition
so2Qty = so2Usd / close // Calculate quantity based on USD
strategy.order("Safety Order 2", strategy.long, qty=so2Qty, comment="SO2")
// 5) AVERAGE ENTRY PRICE
// Use the built-in variable for the average price of the open position
avgEntryPrice = strategy.position_avg_price
// 6) DUAL TRAILING STOP LOGIC
// Variables to track trailing stop levels and states
var float highestSinceEntry = na
var float trailStopPrice = na
var bool stopHitNormal = false
var bool lockInTriggered = false
var float lockInPeak = na
var float lockInStopPrice = na
var bool stopHitLockIn = false
// --- Update Trailing Logic when in a Position ---
if strategy.position_size > 0
// --- Standard Trail ---
highestSinceEntry := na(highestSinceEntry) ? close : math.max(highestSinceEntry, close)
trailStopPrice := highestSinceEntry * (1 - trailStopPerc)
stopHitNormal := close < trailStopPrice
// --- Lock-In Trail ---
if not lockInTriggered and close >= avgEntryPrice * (1 + lockInThreshold)
lockInTriggered := true
lockInPeak := close
if lockInTriggered
lockInPeak := math.max(lockInPeak, close)
lockInStopPrice := lockInPeak * (1 - lockInTrailPct)
stopHitLockIn := close < lockInStopPrice
else
stopHitLockIn := false
lockInStopPrice := na
// --- Reset Variables when Flat ---
else
highestSinceEntry := na
trailStopPrice := na
stopHitNormal := false
lockInTriggered := false
lockInPeak := na
lockInStopPrice := na
stopHitLockIn := false
// lastBuyBar is intentionally NOT reset here, cooldown depends on it
// 7) EXIT CONDITIONS
// Added 'inDateRange' check
// Exit if either trailing stop is hit OR if the trend reverses downward
exitCondition = (stopHitNormal or stopHitLockIn or trendDown) and strategy.position_size > 0
if exitCondition
strategy.close_all(comment="Exit: SL / LockIn / TrendDown")
// 9) PLOTS & DEBUG TABLE
// --- Plot MAs ---
plot(fastMA, color=color.new(color.green, 0), title="Fast EMA", linewidth=2)
plot(slowMA, color=color.new(color.red, 0), title="Slow EMA", linewidth=2)
// --- Plot Trailing Stops ---
plot(strategy.position_size > 0 ? trailStopPrice : na, color=color.new(color.orange, 0), title="Standard Trailing Stop", style=plot.style_linebr, linewidth=2)
plot(lockInTriggered ? lockInStopPrice : na, color=color.new(color.fuchsia, 0), title="Lock-In Trailing Stop", style=plot.style_linebr, linewidth=2)