Pine Script Stop Loss: Fixed Prices, Trailing Ticks and Order Timing

A Pine Script stop exit needs a price or distance, a matching entry and a defined time at which the order becomes available. strategy.exit() models that order in a strategy simulation. It does not guarantee the stop price as the fill price, cap every possible loss or place a protective order with a live broker.
Choose the reference before the percentage
A percentage stop can be measured from the signal close, the actual entry fill or an updated average position price. These are different rules. State the reference in the strategy specification and check it against the trade report.
For a hypothetical long entry at 100, a 2% stop based on that fill is 98. A gap through 98 can produce a worse exit. A stop is a trigger, not a promise that the market will offer the requested price. The percentage is also a price distance, not automatically a percentage of account equity.
The stop argument specifies an absolute price. The loss argument uses ticks from the entry price. A matching from_entry identifies which entry the exit applies to. See TradingView's stop-order examples.
Fixed-percentage example and its timing limitation
This retained v5 example calculates a stop from the average entry price. It passed a syntax check during this revision; no market-data backtest result is asserted. It demonstrates the formula but also has a timing limitation that must be understood before reuse.
//@version=5
strategy("MA Crossover with Stop Loss", overlay=true, initial_capital=10000)
// Input parameters
stopLossPercent = input.float(2.0, title="Stop Loss %", minval=0.1, maxval=10.0)
ma_length = input.int(20, title="Moving Average Length")
// Calculate moving average
ma20 = ta.sma(close, ma_length)
// Entry condition: price crosses above MA
longCondition = ta.crossover(close, ma20)
if longCondition
strategy.entry("Long", strategy.long)
// Stop loss management
if strategy.position_size > 0
stopLevel = strategy.position_avg_price * (1 - stopLossPercent / 100)
strategy.exit("Stop Loss", "Long", stop=stopLevel)
// Visualization
plot(ma20, color=color.blue, linewidth=2, title="MA20")
plotshape(longCondition, style=shape.triangleup, location=location.belowbar,
color=color.green, title="Buy Signal")
The strategy.position_size condition is a choice in this script, not a mandatory guard required for every exit call to compile. It keeps this calculation out of the flat-position state, where average entry price is unavailable.
Under default bar-close calculations, a market entry generated at one close normally fills at the next bar's open. This script does not recalculate immediately after that fill. Its first opportunity to see the positive position and submit the stop is normally the next bar's close. The first holding bar therefore lacks this stop order. Merely placing the exit code below the entry code does not make the exit active from the entry fill.
Changing calculation settings can change that sequence, but it also changes the experiment. calc_on_order_fills permits recalculation after fills and requires checking historical fill assumptions. process_orders_on_close changes order-processing timing; it is not a universal fix for missing exits. TradingView documents these settings and their tradeoffs in strategy execution behavior.
This source recalculates the same percentage formula while long. With one unchanged entry price, its level remains fixed. If the position's average entry changes, the formula can move too. It has no profit target or separate time exit, and its default order size is not determined by the selected stop distance.
A complete trailing-stop example in ticks
Pine's built-in trailing exit uses an activation level and a trailing offset. trail_points expresses the activation distance from entry in ticks; trail_price can specify an absolute activation price instead. trail_offset is the following distance in ticks. There is no trail_percent argument.
This standalone v6 example uses a one-unit entry and configurable tick distances. It passed the syntax checker. The settings are illustrative, and there is no protective stop before the trailing order activates. It is a mechanics example, not a complete risk policy.
//@version=6
strategy("Trailing exit mechanics", overlay=true, pyramiding=0)
length = input.int(20, "SMA length", minval=1)
activationTicks = input.int(100, "Activation distance (ticks)", minval=1)
offsetTicks = input.int(50, "Trailing offset (ticks)", minval=1)
average = ta.sma(close, length)
entrySignal = ta.crossover(close, average)
if entrySignal and strategy.position_size == 0
strategy.entry("Long", strategy.long, qty=1)
strategy.exit("Trail", from_entry="Long", trail_points=activationTicks, trail_offset=offsetTicks)
plot(average, "SMA", color.blue)
Suppose the entry fills at 100 and the instrument's minimum tick is 0.01. The default 100-tick activation distance is 1.00, so activation occurs at 101. The 50-tick offset is 0.50. After activation, a new favorable high moves the long trailing level higher; a pullback does not move it lower. On a different tick-size instrument, the same inputs represent different price distances.
A percentage trail requires an explicitly defined conversion or custom price-level rule. Computing a fixed tick distance once at entry is not the same as continuously maintaining a fixed percentage below each new high. Decide which behavior the strategy intends before choosing an implementation.
ATR stops need an update rule
An ATR distance combines a volatility estimate with a chosen multiplier. For a long position, a candidate price can be described as entry price minus the chosen multiple of ATR. That alone leaves a key question unanswered: is ATR captured once at entry, or recalculated during the trade?
Capturing ATR once gives a fixed initial distance. Recalculating it can move the stop away when volatility increases. A ratcheting rule that permits only upward movement for a long position is another design. These alternatives should have different names and separate test results; none is automatically superior.
The same distinction applies to a support-based stop. Specify when the support level was knowable and when the stop may change. Moving a stop after seeing the outcome creates a rule that could not have been followed at the time.
Position size and intended loss
For a simplified cash-share example, assume a 100 monetary-unit loss budget and a stop two units below the intended entry. Dividing 100 by 2 gives 50 shares before fees, slippage and rounding. If the stop is one unit away, the same arithmetic gives 100 shares. These are planning calculations, not maximum-loss guarantees.
For derivatives, incorporate the contract's point value, lot increment and currency conversion. Check that the position is affordable under the account's margin rules. strategy.percent_of_equity alone sets allocation; it does not solve the stop-distance sizing calculation for you.
Validate an exit before comparing performance
Record one trade's signal time, entry fill, stop submission time, stop value and exit fill. Include a gap or rapid move when the dataset provides one. Check that the exit ID matches the intended entry and that the requested quantity was not reserved by another exit. Compare standard OHLC assumptions with more granular data when available.
Keep the entry rule and cost model fixed while studying stop variants. Record every distance tried and preserve a later period for evaluation. A smaller historical drawdown does not by itself show a better strategy: the stop may also change exposure, missed recoveries, turnover and total return. No universal stock, crypto or forex stop percentage follows from the examples above.
Using Pineify for exit rules
Pineify supports visual strategy construction with exit settings. Review the generated Pine code to identify the reference price and update rule, then test it on TradingView. Builder settings are not evidence of a broker-side stop or guaranteed execution.
For the related order sequence, read strategy.entry and fill timing. Short-interval systems also need explicit cost assumptions; see the scalping workflow.
Why might my stop appear one bar after entry?
An exit calculated only while position_size is positive may not be submitted until the next strategy calculation after the entry fill. Inspect the calculation settings and order timeline. Moving the code lower in the file does not create an extra calculation.
Does a stop guarantee the specified exit price?
No. Gaps and execution conditions can produce a worse fill. Backtest fills also depend on the emulator's assumptions and available price data.
Can I use trail_percent in strategy.exit?
No. The built-in trailing parameters use an activation price or tick distance and a trailing offset in ticks. A percentage-based design needs an explicit conversion or custom update rule.
Is a two-percent stop a two-percent account risk?
Only under additional position-value and execution assumptions. Account loss depends on quantity, price movement, contract value, costs and currency. The stop distance alone does not determine it.



