Pine Script Error Reference: strategy.exit & trail_offset

If the Pine Editor just threw red text at you, you’re not alone. In my experience debugging strategies for traders moving toward automation, two errors show up more than any other: strategy.exit parameter conflicts and trail_offset misuse. Both stem from Pine Script’s strict pairing rules, not from bad trading logic. This Pine Script error reference exists for exactly that: the exact error text, why Pine throws it, and the fix, organized so you can jump straight to your error and get back to coding.

Key Takeaways

  • trail_offset cannot be used alone. It must be paired with trail_price or trail_points, or Pine throws strategy.exit must have at least one of the following parameters.
  • Pine Script v6 changed how strategy.exit() evaluates stop/loss and limit/profit together. It now picks whichever level the market hits first, instead of always favoring the absolute price.
  • Most “mismatched input” and “no viable alternative” compile errors trace back to indentation, a missing comma, or a stray character, not logic bugs.
  • The when parameter was removed from all order functions in v6. Wrap the call in an if statement instead.

What Does strategy.exit() Actually Require?

strategy.exit() needs at least one of profit, limit, loss, or stop, or a valid trailing-stop pair, or Pine won’t compile the call at all. Skip all of them and you’ll see strategy.exit must have at least one of the following parameters: profit, limit, loss, stop, trail_price, trail_points, which is Pine’s way of saying the exit has nothing to actually trigger on.

The function closes an open position created by strategy.entry(), and it separates absolute price levels from relative distances:

ParameterTypeWhat it means
limitabsolute priceTake-profit price level
stopabsolute priceStop-loss price level
profitticksTake-profit distance from entry
lossticksStop-loss distance from entry
trail_priceabsolute pricePrice at which the trailing stop activates
trail_pointsticksDistance from entry at which the trailing stop activates
trail_offsetticksHow far behind price the trailing stop follows once active

In practice, most beginner errors come from mixing an absolute-price parameter with a relative-distance one and assuming Pine will “figure it out.” It won’t. Each pair has its own rule, covered below.

Programming code displayed on a dark computer screen, representing a Pine Script strategy being edited in the Pine Editor

Why Does trail_offset Throw “Must Have At Least One Parameter”?

trail_offset on its own does nothing, because Pine needs a second value telling it when the trailing stop should activate. Set trail_offset without trail_price or trail_points and Pine can’t build a valid trailing-stop order. It falls back to the generic “must have at least one of the following parameters” error, even though you clearly passed an argument.

The rule is simple once you see it stated plainly. trail_price defines the activation price. trail_points defines the activation distance in ticks. trail_offset defines how far the stop trails behind price once triggered. You need one activation parameter plus trail_offset. Never use trail_offset by itself, and never use trail_price or trail_points without it.

//@version=6
strategy("Trail Offset Example", overlay=true)

longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
if longCondition
    strategy.entry("Long", strategy.long)

// Wrong: trail_offset with nothing to activate it
// strategy.exit("Exit Long", "Long", trail_offset=10)

// Correct: trail_points sets activation distance, trail_offset sets trail distance
strategy.exit("Exit Long", "Long", trail_points=50, trail_offset=10)

What just happened: the trailing stop arms once price moves 50 ticks in your favor (trail_points), then follows price at a fixed 10-tick distance (trail_offset). Swap trail_points for trail_price=high*1.01 if you’d rather arm the trail at a specific price instead of a tick distance.

Trailing Stop Parameter Pairing trail_price or trail_points sets the activation point. Either one must be paired with trail_offset to define the trail distance, producing a valid trailing stop. trail_offset used alone produces the “must have at least one parameter” error. trail_price activation price trail_points activation distance + trail_offset trail distance (required) Valid trailing stop compiles trail_offset used alone Error: must have at least one parameter
How trail_offset pairs with trail_price or trail_points to compile a valid trailing stop

Watch out: trail_price and trail_points are mutually exclusive activation methods. Pick one, not both, and always pair whichever you choose with trail_offset.

How Do trail_price and trail_points Actually Differ?

trail_points measures the activation distance in ticks from your entry price. trail_price sets an exact price level at which trailing begins instead. Pick trail_points for distance-based logic that scales across instruments, and trail_price when your strategy reasons in specific price levels, like a prior swing high.

trail_pointstrail_price
UnitTicks from entryAbsolute price
Best forPercentage/ATR-based systemsLevel-based systems (swing highs/lows)
Exampletrail_points=100trail_price=high[1]
Still needstrail_offsettrail_offset

Why Did My strategy.exit() Behave Differently After Upgrading to Pine v6?

Pine Script v6 changed how strategy.exit() resolves combined absolute and relative parameters. It now evaluates both specified levels and closes the position at whichever one the market is expected to reach first. That’s different from v5, which always gave priority to the absolute price (stop or limit) over the relative one (loss or profit). If your v5 strategy relied on stop silently overriding loss, backtest results on v6 can shift.

//@version=6
strategy("v6 Exit Priority Example", overlay=true)

if ta.crossover(close, ta.sma(close, 50))
    strategy.entry("Long", strategy.long)

// v6 evaluates both stop and loss, exits at whichever triggers first
strategy.exit("Exit Long", "Long", stop=close * 0.97, loss=200)

This same first-to-trigger logic applies to limit vs. profit. If you maintain strategies written for v5 and haven’t re-tested them on v6, this is the first place to look when live results diverge from your backtest.

strategy.exit() Priority: Pine v5 vs v6 In Pine v5, the absolute stop parameter always wins over the relative loss parameter when both are set. In Pine v6, both stop and loss are evaluated together and whichever level the market reaches first triggers the exit. Pine v5 stop (absolute) always wins if both set loss (relative) ignored if stop is set Pine v6 stop (absolute) evaluated together loss (relative) evaluated together whichever level triggers first wins
Pine v5 always favored the absolute stop/limit level; Pine v6 evaluates both and exits at whichever triggers first

Here’s a pattern worth flagging. Strategies that pass a loose stop (a wide absolute price meant as a catastrophic backstop) alongside a tight loss (the real risk parameter) behaved identically in v5 and v6, because the tighter level always triggers first no matter which evaluation rule is active. Behavior actually diverges when the two levels sit close together and volatility decides which one gets hit first. That’s the scenario worth backtesting on both versions before you trust the numbers.

What Does “Undeclared Identifier” Mean and How Do I Fix It?

“Undeclared identifier” means Pine Script doesn’t recognize a name you’ve used, almost always because it’s missing its namespace prefix or because the standalone function it replaced was removed in v6. If the identifier is a built-in you’re sure exists, add the correct prefix (ta. for indicators like ta.sma, request. for request.security, color. for named colors like color.green).

The most common v6-specific trigger is the old input() function with a type= argument. v6 splits it into dedicated functions per type (input.int(), input.float(), input.bool(), input.string(), and so on), each with its own parameter names.

// v5 style: throws "undeclared identifier" style errors when ported carelessly
// length = input(14, title="Length", type=input.integer)

// v6: dedicated typed input function
length = input.int(14, title="Length")

How Do I Fix “Mismatched Input” and “No Viable Alternative” Errors?

“Mismatched input ‘[token]’ expecting ‘[expected]'” almost always points to an indentation or line-placement problem. “No viable alternative at character ‘[char]'” points to an invalid character that doesn’t belong at that spot in the syntax. Both are structural problems, not logical ones, so the fix lives in formatting, not strategy logic.

ErrorTypical CauseFix
mismatched input 'plot' expecting 'end of line'Statement indented when it should start a new lineRemove the leading whitespace before the statement
no viable alternative at character '$'Invalid character inside a string/argument, often from copy-pastingReplace with a plain string literal, e.g. "title"
syntax error at input 'end of line without line continuation'A trailing // comment placed after a wrapped lineMove the comment above the line instead of at the end
syntax error at input '<eof>'Missing closing parenthesis or bracketCount your ( against your ) for that statement

Across the strategies I’ve debugged for other traders migrating to PickMyTrade automation, the single most repeated fix has been the same one. A plot(), strategy.exit(), or alert() call gets left indented under an if block it was never meant to belong to. Pine treats indentation as structural, so one accidental extra space turns a top-level statement into a conditional one. The compiler reports it as a mismatched-input error rather than “wrong indentation,” which is why it trips up experienced coders too.

A computer screen showing a pink and green candlestick chart, representing a Pine Script strategy plotting entries and exits

Why Doesn’t My when Parameter Work Anymore?

The when parameter was removed from every order function, including strategy.entry(), strategy.exit(), and strategy.order(), in Pine Script v6. Any v5 script still passing when= will fail to compile. Replace it with an if statement wrapping the order call instead.

// v5: no longer valid in v6
// strategy.exit("Exit Long", "Long", stop=close * 0.97, when=barstate.isconfirmed)

//@version=6
if barstate.isconfirmed
    strategy.exit("Exit Long", "Long", stop=close * 0.97)

This is one of the most common breaks when you pull in an older strategy written for v5, since when= was a common pattern for gating orders to confirmed bars.

How Do I Combine a Stop-Loss and Trailing Stop in One strategy.exit() Call?

Yes, a single strategy.exit() call can carry a hard stop, a take-profit, and a trailing stop simultaneously. Pine evaluates all specified exit conditions on the same order and executes whichever triggers first. This is the standard “bracket + trail” pattern for prop-firm strategies that need a hard daily-loss backstop alongside adaptive profit protection.

//@version=6
strategy("Combined Exit Example", overlay=true, margin_long=100, margin_short=100)

if ta.crossover(ta.ema(close, 9), ta.ema(close, 21))
    strategy.entry("Long", strategy.long)

strategy.exit(
     "Bracket + Trail",
     "Long",
     stop=strategy.position_avg_price * 0.98,
     limit=strategy.position_avg_price * 1.04,
     trail_points=60,
     trail_offset=15,
     comment_trailing="Trailing",
     alert_message="exit_long")

What just happened: the hard stop/limit bracket protects against a runaway move while trail_points/trail_offset locks in gains once price runs 60 ticks in your favor. The alert_message argument is what lets a webhook, including the one PickMyTrade listens on, fire the moment this exact exit condition executes. That’s what keeps your broker or prop-firm account closing the position in sync with the chart instead of a few seconds behind it.

What Are oca_name and oca_type For?

oca_name and oca_type group multiple exit orders so that filling one automatically cancels or reduces the others, which matters when a single strategy.exit() call isn’t enough to express a partial take-profit plus stop-loss structure. Set oca_type=strategy.oca.reduce when you want each fill to reduce the remaining group’s quantity instead of canceling it outright. That’s the correct setting for scaled exits.

strategy.exit("TP1", "Long", qty_percent=50, limit=strategy.position_avg_price * 1.02,
     oca_name="ExitGroup", oca_type=strategy.oca.reduce)
strategy.exit("TP2", "Long", qty_percent=50, limit=strategy.position_avg_price * 1.05,
     oca_name="ExitGroup", oca_type=strategy.oca.reduce)

Do Built-In Trailing Stops Repaint on Historical Bars?

Yes. Pine’s built-in trail_points/trail_offset trailing stop can repaint on historical bars because it models trailing behavior against assumed intrabar price movement rather than actual tick data. A backtest’s trailing exits may not fill at the exact same point a live chart would. This is a known limitation, not a bug in your code.

If exact bar-by-bar consistency between backtest and live matters more than convenience, code the trailing logic manually instead. That usually matters most for strategies you plan to run live through TradingView-to-broker automation, where a repainted backtest can overstate how well the exit actually performs. Recalculate strategy.exit()‘s stop and limit parameters on each barstate.isconfirmed bar. You trade a small amount of responsiveness for a stop level that can’t repaint.

Frequently Asked Questions

Why does Pine Script say "strategy.exit must have at least one of the following parameters"?

This fires when a strategy.exit() call has no valid exit condition: either none of profit/limit/loss/stop are set, or trail_offset is set without a matching trail_price or trail_points. Add at least one activation parameter alongside trail_offset, or one of the four basic exit parameters.

Can I use trail_price and trail_points together?

No. trail_price and trail_points are two different ways of defining the same thing: the trailing stop’s activation point. Pine only needs one. Pick whichever matches your logic: trail_points for tick-distance-based systems, trail_price for level-based systems, and pair either with trail_offset.

What changed in strategy.exit() between Pine Script v5 and v6?

The biggest behavioral change is that v6 evaluates combined absolute/relative parameter pairs (stop+loss, limit+profit) together and exits at whichever level the market reaches first, where v5 always gave priority to the absolute price. The when parameter was also removed entirely. Replace it with an if statement around the order call.

How do I fix "no viable alternative at character" in Pine Script?

This error means Pine hit a character it can’t parse at that position in the syntax, usually a stray symbol from copy-pasting code or a typo like $ where a string was expected. Check the exact character named in the error message and the line it points to. The fix is almost always replacing or removing that one character.

Why did my Pine v5 script stop compiling after switching to v6?

The most common causes are the removed when parameter, the retired generic input() function (now split into input.int(), input.float(), etc.), and stricter boolean typing that no longer implicitly casts int/float to bool. Compare each compile error against the specific v6 breaking change it maps to, rather than guessing.

Still Have Questions?

I update this reference whenever a Pine Script version bump changes strategy.exit() behavior or introduces a new class of compile error. If you hit an error not listed here, drop the exact error text in the comments. That’s usually enough to trace it back to the parameter or syntax rule causing it.


Disclaimer:
This content is for informational purposes only and does not constitute financial, investment, or trading advice. Trading and investing in financial markets involve risk, and it is possible to lose some or all of your capital. Always perform your own research and consult with a licensed financial advisor before making any trading decisions. The mention of any proprietary trading firms, brokers, does not constitute an endorsement or partnership. Ensure you understand all terms, conditions, and compliance requirements of the firms and platforms you use.


Also Checkout: Automate TradingView Indicators with Tradovate Using PickMyTrade

Leave a Comment

Your email address will not be published. Required fields are marked *

error

Follow us for more insights and updates

Scroll to Top
Verified by MonsterInsights