
How to Code a Trailing Stop in Pine Script v6 for Traders
Table of Contents
- Introduction
- What Is a Trailing Stop in Pine Script
- Why Trailing Stops Matter for Traders and Investors
- Core Concepts
- Step‑by‑Step Guide
- Practical Tips for Better Results
- Common Mistakes to Avoid
- Frequently Asked Questions
- Conclusion
Introduction
When the EUR/USD pair slipped beneath the 1.0800 mark last week, a wave of retail accounts found themselves on the losing side of a rapidly widening spread. The loss could have been capped with a correctly calibrated trailing stop, yet most publicly available scripts on TradingView still rely on static stop‑loss values that freeze as soon as the trade moves into profit.
If you have ever wondered how to code a trailing stop that reacts to volatility and respects position reversals, you are not alone. New traders often copy‑paste generic snippets, only to watch the stop stay put after a modest gain, exposing the account to unnecessary drawdowns.
This piece walks you through building a fully backtestable, volatility‑adjusted trailing stop loss in Pine Script v6. Real‑world forex and equity examples illustrate the mechanics, while a dedicated section flags the traps that turn a promising idea into a costly mistake.
What Is a Trailing Stop in Pine Script?
A trailing stop is a stop‑loss order that moves in the direction of profit but never retreats. In Pine Script the mechanism is implemented through the strategy.exit function, which accepts either a trailprice (an absolute price level) or a trailoffset (a distance from the entry price).
Take a long position on AAPL entered at $150. A 2 % trailing stop would sit at $147 initially. As the price climbs to $160, the stop moves up to $156.80—still 2 % below the new high. If the price later slides to $156, the order triggers, locking in the gain. The stop never moves back down, preserving the profit that has already been earned.
Why Trailing Stops Matter for Traders and Investors
Professional desks on the CFTC‑regulated futures market and discretionary traders watching the S&P 500 both employ trailing stops to guard against sudden reversals. A trailing stop removes the need to guess an exact exit point, allowing the market to dictate when profit erodes.
Skipping a trailing stop can create “run‑up‑run‑down” scenarios: a position makes a large paper gain, then a rapid unwind wipes out most of the upside, inflating drawdowns and breaching risk limits. Conversely, a well‑tuned trailing stop can improve the risk‑to‑reward ratio without sacrificing upside potential.
Calculating Trailing Distance with ATR or Percentage – mechanism explained
Average True Range (ATR) captures recent volatility, making it a natural scale for stop distance. In a 14‑period ATR calculation on EUR/USD, a value of 0.0012 translates to 12 pips. Multiplying by 1.5 yields an 18‑pip trailing buffer that widens when volatility spikes, preventing premature exits during news releases.
A percentage‑based stop, such as 1.5 % of the closing price, is simpler but can be too tight on high‑volatility days. For a 20‑day SMA crossover on the Nasdaq, a 1.5 % buffer on a 13,200 level equals a $198 stop, which may be appropriate when implied volatility on the VIX is low.
Using strategy.exit() with trailprice and trailoffset – mechanism explained
strategy.exit can accept either trailprice (a fixed price level) or trailoffset (a distance expressed in price units). When trail_offset is set, Pine automatically updates the stop each bar as the high (for longs) or low (for shorts) moves.
Consider a short AAPL trade entered at $155. Setting trail_offset to 2 % of the entry price (≈ $3.10) tells the engine to place a stop at $158.10. If the price drops to $150, the stop trails upward to $152.10, preserving a 2 % buffer from the new low.
Dynamic Stop Adjustment via input() and var Declarations – mechanism explained
User inputs let a trader tweak the ATR multiplier or percentage without editing code. Declaring a var variable preserves the stop level across bars, enabling custom logic such as “lock in half of the profit once a 5 % gain is reached.”
For a multi‑timeframe EUR/USD strategy, a daily ATR value can be stored in a var float dailyATR = request.security(syminfo.tickerid, "D", ta.atr(14)). The trailing distance on a 1‑hour chart then references dailyATR, ensuring the stop reflects broader market volatility rather than intra‑hour noise.
Core Concepts
## Step 1 — Define Entry Conditions and Capture the Initial Price
Begin by coding the entry rule, for example a 20‑period EMA crossing above the 50‑period EMA on the EUR/USD 1‑hour chart. Store the entry price in a var float entryPrice = na and assign it when strategy.position_size changes from zero to positive.Step 2 — Choose a Trailing Metric and Create a User Input
Add an input.float called “ATR multiplier” with a default of 1.5. Compute the trailing distance as float trailDist = atr(14) * inputATR. For a percentage alternative, use float perc = input.float(1.5, "Trailing %") / 100 and calculate trailDist = close * perc.
Step 3 — Apply strategy.exit with Dynamic Parameters
Call strategy.exit inside the same script, passing trailoffset = trailDist for a long position. For shorts, use trailoffset = -trailDist to ensure the stop moves upward as the price falls. Include comment = "Trailing Stop" to label the order in the strategy report.
Step 4 — Reset the Trailing Stop on Position Reversal
When the script flips from long to short, the previous trailing stop must be cleared. Detect a reversal with
pinescript
if strategy.position_size[1] > 0 and strategy.position_size == 0
entryPrice := na
The next bar’s entry logic will re‑initialize the stop.
Step 5 — Backtest the Strategy Across Multiple Timeframes
Use request.security to fetch higher‑timeframe ATR or SMA values, then run the script on a six‑month EUR/USD dataset. Review the “Performance Summary” tab for metrics such as max drawdown, win rate, and average trade duration. Adjust the ATR multiplier until the Sharpe ratio stabilizes across both volatile and calm periods.
Practical Tips for Better Results
- Align the ATR period with the chart timeframe; a 14‑period ATR on a 1‑hour chart reacts faster than the same period on a daily chart.
- Combine a trailing stop with a partial‑profit target; lock in 50 % of the position once a predefined profit level is hit, then let the trailing stop run the remainder.
- Test the script on both the forex market (e.g., EUR/USD) and an equity index (e.g., S&P 500) to verify that the volatility scaling works across asset classes.
- Use the
calc_on_every_tickflag only when the broker’s data feed supports sub‑second updates; otherwise it adds unnecessary CPU load. - Keep an eye on spread widening during high‑impact news; a trailing stop based solely on price can be triggered by a temporary spike in the bid‑ask spread.
- Record the stop‑loss level in a plot for visual verification; mismatched values often indicate a logic error in the
varhandling. - When trading on a margin‑intensive instrument like futures, factor in the required maintenance margin before setting a tight trailing distance.
Common Mistakes to Avoid
- Using a static percentage on a highly volatile pair – the stop may be breached by normal price swings, inflating turnover.
- Forgetting to reset the stop on a position reversal – the old stop can linger and close the new trade prematurely.
- Applying
trailpriceandtrailoffsetsimultaneously – Pine will prioritize one, leading to unexpected behavior. - Relying on a single‑timeframe ATR – intra‑hour noise can cause the stop to chase every minor tick, eroding profits.
- Neglecting broker execution delays – a trailing stop that moves every bar may not be filled at the quoted price during fast markets.
How do I code a trailing stop in Pine Script v6?
Start by defining entry logic, then calculate a trailing distance using either ATR or a fixed percentage. Pass that distance to
strategy.exitvia thetrail_offsetparameter, and ensure you reset the stop when the position flips.
What is the difference between trailprice and trailoffset?
trailprice sets an absolute price level that does not change unless you manually update it. trailoffset specifies a distance from the highest (long) or lowest (short) price since entry, allowing Pine to move the stop automatically each bar.
Why does my trailing stop not move after a profit?
If you used trailprice instead of trailoffset, the stop remains fixed. Switching to trailoffset or updating the trailprice variable each bar resolves the issue.
When should I use ATR versus a fixed percentage for trailing stops?
ATR adapts to market volatility, making it suitable for assets with irregular price swings such as commodities or forex. A fixed percentage works well in low‑volatility environments like major equity indices when implied volatility on the VIX is subdued.
Can I backtest a trailing stop strategy in Pine Script?
Yes. Enable strategy() with overlay=true, run the script on historical data, and review the built‑in performance metrics. Make sure to include realistic commission and slippage settings to mimic broker execution.
Is it possible to apply a trailing stop to both long and short positions simultaneously?
Define separate strategy.exit calls for each direction, using a positive trailoffset for longs and a negative one for shorts. The engine will manage each side independently, provided the script tracks strategy.position_size correctly.
Conclusion
The most important lesson is that a trailing stop only protects you when it moves in lockstep with market volatility and resets on position flips. Build the stop, test it across timeframes, and let the data dictate the multiplier.
Your next step: copy the outline into a fresh Pine Script v6 editor, replace the placeholder variables with your own risk parameters, and run a six‑month backtest on EUR/USD and AAPL. Adjust the ATR multiplier until the strategy’s max drawdown aligns with your risk tolerance.
Remember, no script guarantees profit. Always size positions to withstand the worst‑case drawdown, and treat the trailing stop as one layer of a broader risk‑management framework.
—
This article is for educational purposes only and does not constitute investment advice. Trading and investing carry risk of loss; never invest more than you can afford to lose.
Last reviewed: August 2026