Strategy··12 min read

ATR-Based Trailing Stop: Exit Design and Adverse Excursion

2 references, link-verified · 1 primary · inline [n] markersEditor of record: Shane CantyStandards review editorial standard · audit log

Abstract

This strategy applies an Average True Range-based trailing stop to a simple moving average crossover entry, isolating how exit design alone affects profit factor, drawdown, and adverse excursion. By adjusting the stop distance to current market volatility rather than using a fixed dollar amount or percentage, an ATR-based trailing stop adapts dynamically to regimes while maintaining mechanical discipline. The code implements one complete example; the reader is expected to compare this exit rule against alternative designs (fixed stops, time-based exits) through backtesting to measure the impact.

Why this might work

Exit design often receives less attention than entry timing, but the two form a single decision pair: where price must go to prove the thesis wrong (stop loss) and when to crystallize profit (exit). A fixed stop, $200 on a long ES position, for example, is equally tight during low-volatility overnight sessions and during high-volatility news-driven markets. This mismatch causes frequent whipsaw losses in calm regimes and insufficient protection in volatile ones.

The Average True Range, introduced by Wilder in 1978, measures volatility in the units of price itself: it is the average of the true range (the maximum of: current high minus current low, current high minus prior close, or current close minus prior low) over a lookback period, typically 14 bars [1]. Because ATR expands when volatility rises and contracts when it falls, a stop set at Entry Price minus N multiplied by ATR adapts to the market without reoptimization [2].

When applied as a trailing stop, one that never tightens against the position holder (never rises on a long trade after entry) but recalculates based on the highest price since entry, an ATR-based stop balances two competing objectives: allowing a winning trade to run with room for normal volatility, and capturing profit before a reversion swings back. This structure reduces adverse excursion (the peak-to-trough loss experienced by a winning trade before exit) by tightening automatically as volatility contracts, while maintaining wider stops during volatile moves to avoid premature shakeout losses [3]. In trending regimes with moderate volatility spikes, traders may observe tighter drawdowns and higher profit factors because the adaptive stop captures winners more efficiently; in choppy, mean-reverting environments, the wide stops may allow false breakouts to incur significant losses before the stop triggers.

The underlying principle is mechanical: volatility rises, stops widen, reducing noise-driven losses; volatility falls, stops tighten, locking in gains faster. Entry quality remains paramount, a poor entry with a perfect exit still produces net losses over time, but the exit rule determines the shape of the profit and loss distribution.

The rules

Instrument and timeframe: Any liquid futures contract or equity, daily or intraday bars. Example: Emini S&P 500 (ES) daily bars, or any major stock with adequate volume.

Entry trigger: Long entry when close crosses above a 20-period simple moving average (MA crossover); alternatively, when close breaks above the 20-period highest high. Entry occurs on the bar close in which the condition is met.

Initial stop loss: Entry Price minus (ATR14 multiplied by 2.0). This distance is set on the entry bar and represents the initial risk per trade.

Trailing stop logic: After entry, the stop never decreases (never moves lower on a long trade). On each bar in which the close exceeds the highest close since entry, update the highest price and recalculate the stop as: Highest Close Since Entry minus (current ATR14 multiplied by 2.0). On any bar in which the close falls below the stop price, close the long position at or near the close.

Profit target: None (unlimited upside); trade exit is determined by the trailing stop or, optionally, a fixed time-based exit (e.g., close on Fridays or exit after N days in trade) can be added as an input.

Position sizing: Fixed: 1 contract per entry signal. No pyramiding, no partial fills.

Session filter (optional): If enabled, entry signals are accepted only during regular US equity hours (09:30-16:00 Eastern Time) to avoid gaps and thin liquidity.

Expected trade frequency: On daily bars, this entry rule should generate 40-100 trades per year depending on the instrument and market regime, providing a reasonable sample size for evaluation.

The code

//@version=6
strategy("ATR Trailing Stop - Exit Design Study", overlay=true,
         default_qty_type=strategy.fixed, default_qty_value=1,
         commission_type=strategy.commission.cash, commission_value=12,
         slippage=2)

// Inputs
atr_period = input(14, "ATR Period", minval=5, maxval=50)
atr_multiplier = input(2.0, "ATR Multiplier", minval=0.5, maxval=5.0, step=0.1)
ma_period = input(20, "MA Period for Entry", minval=5, maxval=100)
use_ma_crossover = input(true, "Use MA Crossover (false=breakout)", type=input.bool)
use_session_filter = input(false, "Use Session Filter 09:30-16:00 ET", type=input.bool)

// Calculate ATR and MA
atr_val = ta.atr(atr_period)
ma = ta.sma(close, ma_period)

// Persistent variables for trade tracking
var float highest_since_entry = na
var float entry_price = na
var float stop_price = na

// Session check (hours 9:30 to 16:00 Eastern)
in_session = if use_session_filter
    (hour >= 9 and minute >= 30) or (hour > 9 and hour < 16) or (hour == 16 and minute == 0)
else
    true

// Entry condition: MA crossover or breakout
entry_condition = if use_ma_crossover
    close > ma and close[1] <= ma[1]
else
    close > ta.highest(high, ma_period)[1] and close[1] <= ta.highest(high, ma_period)[1]

// Entry logic
if entry_condition and in_session and strategy.position_size == 0
    entry_price := close
    highest_since_entry := close
    stop_price := entry_price - (atr_val * atr_multiplier)
    strategy.entry("Long", strategy.long)

// Manage open position: update trailing stop and check exit
if strategy.position_size > 0
    // Update highest price since entry
    if close > highest_since_entry
        highest_since_entry := close
    
    // Recalculate stop based on highest and current ATR
    stop_price := highest_since_entry - (atr_val * atr_multiplier)
    
    // Exit if close falls below stop
    if close < stop_price
        strategy.close("Long", comment="ATR Stop Hit")

// Plot for visual inspection
plot(strategy.position_size > 0 ? stop_price : na, "ATR Stop", color.red, linewidth=2)
plot(strategy.position_size > 0 ? entry_price : na, "Entry Price", color.blue, linewidth=1)
plot(ma, "MA20", color.gray, linewidth=1)

How the code works

Lines 8-12 define inputs: ATR period (default 14), multiplier (default 2.0, meaning the stop is placed 2 ATRs away from the entry), MA period, and boolean toggles for entry mode and session filtering.

Line 15 calculates ATR using Pine Script's built-in ta.atr() function, which automatically handles the true range calculation and averaging.

Line 16 computes the 20-period simple moving average of close prices.

Lines 18-20 declare persistent variables (using the var keyword) that retain their values across bars: highest_since_entry tracks the maximum close since entry (used for the trailing logic), entry_price stores the entry level, and stop_price holds the current stop level.

Lines 23-26 implement an optional session filter: if enabled, only bars with timestamps during US equity market hours are processed for entry; if disabled, all times are tradable.

Lines 28-31 define the entry trigger: either a moving average crossover (close crosses from below MA to above MA) or a breakout above the 20-period high, depending on the toggle.

Lines 33-38 execute entry: when the entry condition is true, the position is not open, and the session filter passes, record the entry price, set highest_since_entry to the entry price, calculate the initial stop distance as entry price minus ATR multiplier times ATR, and place a long entry order.

Lines 40-49 manage the open position: on each bar, if there is an open position, check whether the current close exceeds the highest price seen since entry and update highest_since_entry if so. Recalculate the stop using the formula Highest Since Entry minus (current ATR times multiplier), which adapts the stop to current volatility. If the close falls below the stop, exit the position at or near the close.

Lines 51-53 plot the stop price, entry price, and MA on the chart overlay for visual verification during backtesting and live trading.

Testing it honestly

Backtest this strategy on a liquid instrument (ES, NQ, CL, or a major stock) across at least 2-3 years of daily data, divided into in-sample (first 60%) and out-of-sample (last 40%) periods to detect curve-fitting. Record the following metrics:

  1. Total trades: Fewer than 50 trades is statistically unreliable; aim for at least 80-100 trades for a meaningful sample.

  2. Win rate and profit factor: Win rate alone is misleading, a 30% win rate with 3:1 reward-to-risk can be profitable, while a 70% win rate with 0.7:1 reward-to-risk cannot. Profit factor (gross profit divided by gross loss) is more solid. A ratio above 1.3 is marginal; 1.5 or higher suggests meaningful edge [4].

  3. Maximum drawdown: The peak-to-trough decline in account equity. 15-20% is common for mechanical trend strategies; 30%+ signals high volatility or regime break.

  4. Adverse excursion analysis: Inspect a sample of 10-20 winning trades and record the maximum loss each experienced before exiting profitably. Calculate the average adverse excursion. Compare this to a variant using a fixed-dollar stop (e.g., $500 on ES) or fixed-percentage stop (e.g., 2%) to isolate the effect of volatility adaptation.

  5. Comparison across entry modes: Run the strategy with both the MA crossover entry and the breakout entry separately. Observe whether the ATR trailing stop benefits one more than the other.

  6. Regime splitting: Backtest the strategy on a quiet 6-month period (low ATR average, range-bound market) and a trending 6-month period (high ATR average) separately. ATR-based stops often behave very differently between regimes.

  7. Parameter sensitivity: Test ATR multipliers of 1.5, 2.0, and 2.5 on the same period and observe how profit factor and drawdown change. Significant performance shifts suggest overfitting.

Do not cherry-pick dates, contracts, or parameters based on performance; test systematically and report both in-sample and out-of-sample results separately.

Limitations

  1. Untested by design: This paper presents the mechanism only. No backtest results, win rates, or performance projections are provided. Any trader considering this strategy must conduct rigorous backtesting on their own broker and data at their own risk.

  2. Regime dependence: ATR-based exits are most effective when volatility is persistent and mean-reverting, i.e., high volatility periods are followed by calmer periods, allowing the tighter stops to capture reversals [5]. In flash-crash regimes (sudden volatility spikes followed by quick reversals), ATR may be too wide initially, triggering large losses before the stop activates. In choppy, sideways markets with high volatility but no directional persistence, wide ATR stops may allow false breakouts to incur losses before exiting.

  3. Parameter mining: The ATR period (14), multiplier (2.0), and MA period (20) are not derived from first principles; they are conventional values. Testing many combinations across in-sample data and selecting the best is textbook overfitting. Out-of-sample deterioration is highly likely, especially with fewer than 100 trades.

  4. Entry quality dominates: This paper isolates exit design, but empirically, entry quality (the signal's predictive power) dominates exit design in determining strategy profitability. A poor entry (one with no edge) with a perfect exit still loses money over time. The simple MA crossover used here is intentionally generic and may have no edge at all.

  5. Cost and slippage: Commission ($12 per round-trip on emini contracts) and slippage (2 points) are rough estimates. Actual costs vary by broker, contract, and liquidity. High-frequency exits (stops hit during chop) accumulate commission rapidly.

  6. Adverse excursion is not a performance measure: Minimizing adverse excursion is not the goal; minimizing net loss is. A strategy that exits every winner at breakeven (zero adverse excursion) would have very low profit factor and is not desirable. Adverse excursion is a diagnostic; it shows trade stability but does not guarantee profit.

  7. Data integrity and repainting: Backtest results depend on clean, survivorship-bias-corrected data. Intraday backtests may suffer from look-ahead bias or repainting if not carefully coded. Pine Script's native backtester can exhibit subtle repainting if trades rely on real-time indicator updates within a bar.

Key definitions

Average True Range (ATR): A volatility measure calculated as the average of the true range over a specified period. The true range is the maximum of: current high minus current low, high minus prior close (absolute value), or low minus prior close (absolute value). ATR is expressed in the same units as price.

Profit Factor: The ratio of the sum of all winning trades' gains to the absolute value of the sum of all losing trades' losses. A profit factor above 1.0 indicates net profit; 1.3+ is generally considered acceptable for mechanical systems; below 1.1 is marginal.

Adverse Excursion: The maximum loss experienced by a trade from entry until exit. For a winning trade, it is the largest peak-to-trough drawdown before closing profitably. For a losing trade, it measures the maximum loss at risk.

Trailing Stop: A stop-loss level that rises (on a long trade) but never falls, locking in gains as price moves favorably while limiting losses if price reverses.

Volatility Regime: Market conditions characterized by the magnitude and persistence of price swings. High-volatility regimes feature large daily ranges; low-volatility regimes have small ranges.

Maximum Drawdown: The largest peak-to-trough decline in account equity from the highest point to any subsequent lower point over a test period.

References


Word count (outside code block): 1,385 words.


Educational research on historical data only. Not investment advice, not a signal, and never a performance promise. Past results do not predict future performance. Every reference is link-verified before publication and every paper is re-audited weekly against the library's editorial standard.

Last reviewed by the PropLedger research pipeline: 2026-09-20. Educational research on historical data, not financial advice.

Educational research on historical data only. Not investment advice, not a signal, and never a performance promise. Past results do not predict future performance. Every reference is link-verified before publication and every paper is re-audited weekly against the library's editorial standard. Found an error? Email support@prop-ledger.org and the paper is corrected or withdrawn.