Pine Script `alert()` vs `alertcondition()` vs Order Fills
Choose the correct TradingView alert primitive for dynamic JSON, named indicator conditions, or strategy order-fill webhooks, with clear timing and snapshot trade-offs.
Which Pine Script alert type should a webhook use?
Use `alertcondition()` for separately named indicator triggers with mostly static messages, `alert()` for dynamic runtime JSON from an indicator or strategy, and strategy order-fill alerts when emission should follow the TradingView broker emulator's simulated execution. Select only one event model for each order intent. None of these events confirms that an external broker accepted or filled the webhook order.
The payload is downstream of the trigger. If the wrong Pine primitive emits at the wrong moment, adding route fields will not restore the intended strategy semantics. An indicator has no strategy order fills, while a strategy can use `alert()` calls or order-fill events. `alertcondition()` calls compile in a strategy but do not create usable alert triggers there. Start by writing the exact event in plain language: condition became true, script requested an order, or broker emulator filled a simulated order.
Then decide how dynamic the message must be. `alertcondition()` requires a constant message but can include supported placeholders. `alert()` accepts a series string built at runtime. An order-generating strategy command can carry a dynamic `alert_message`, which is delivered through an order-fill alert when the alert dialog includes `{{strategy.order.alert_message}}`. These capabilities overlap enough to confuse authors, but their trigger moments and script scopes remain distinct.
| Primitive | Script scope | Message | Trigger moment | Typical use |
|---|---|---|---|---|
| `alertcondition()` | Indicators only for functioning triggers | Constant string with supported placeholders | When its global-scope condition is true and dialog frequency permits | Named long and short conditions users select separately |
| `alert()` | Indicators and strategies | Dynamic series string | When the local call executes and code frequency permits | Calculated JSON or selective programmable events |
| Order-fill event | Strategies | Default fill message or dynamic per-order `alert_message` | When TradingView's broker emulator fills the simulated order | External route intended to follow simulated strategy fills |
When is `alertcondition()` the right choice?
Choose `alertcondition()` when an indicator should expose distinct named conditions in TradingView's Create Alert dialog and a constant template plus placeholders can express the message. Place each call in global scope, let the user choose frequency in the dialog, and create separate running alerts for separately selected conditions. Do not use it as a strategy trigger.
Each `alertcondition()` call appears as its own option under Condition, which is useful when users should select Long, Short, Exit, or another named event independently. The message cannot concatenate runtime Pine strings because it must be known at compile time. It can, however, contain placeholders for ticker, time, OHLCV, and plotted numeric values. For a static HexTrade route, an alert-dialog JSON template can combine those placeholders with literal account and platform fields.
The trade-off is operational count and duplication. Each active condition is a separate alert, and accidentally leaving an older alert enabled can produce repeated webhooks. Maintain a small inventory with names, versions, symbols, timeframes, and expiration. Since the message is editable in the dialog, source review alone does not prove what is running. Capture the final alert configuration and recreate it after any script, input, chart, or message change.
- Strength: distinct named choices in the alert dialog.
- Constraint: indicator scope, global placement, and constant message argument.
- Dynamic path: supported placeholders, not arbitrary runtime string concatenation.
- Operational risk: multiple active conditions or stale alert snapshots can duplicate intent.
//@version=6
indicator("Named webhook conditions", overlay = true)
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
longSignal = ta.crossover(fast, slow) and barstate.isconfirmed
shortSignal = ta.crossunder(fast, slow) and barstate.isconfirmed
alertcondition(longSignal, "Long", '{"ticker":"{{ticker}}","action":"buy","quantity":"1","platformType":"tradovate","accountId":"replace_with_exact_account_id","dryRun":true}')
alertcondition(shortSignal, "Short", '{"ticker":"{{ticker}}","action":"sell","quantity":"1","platformType":"tradovate","accountId":"replace_with_exact_account_id","dryRun":true}')When should Pine use the `alert()` function?
Use `alert()` when code must build a runtime message, select events through local conditional logic, or share one alert across multiple calls. It works in indicators and strategies, accepts a series-string message, and exposes frequency through the call. Keep it inside a strict transition branch and validate every rendered JSON variant before connecting an order route.
`alert()` is the flexible choice for calculated quantities, values converted with `str.tostring()`, and messages whose structure depends on direction. Flexibility moves responsibility into code: Pine authors must escape JSON correctly, handle `na`, control repeated calls, and ensure every branch produces the documented receiver contract. TradingView presents all eligible calls through the single “Any alert() function call” choice, so script inputs or branch logic must provide any desired selectivity.
Frequency is not the whole timing model. Indicators can execute on realtime updates, while strategies recalculate at bar close by default unless every-tick behavior is enabled. A strategy configured for every tick can behave differently from historical bars and repaint after reload. For confirmed-bar automation, guard with `barstate.isconfirmed` and use once-per-bar-close. For intrabar logic, document why unconfirmed values are acceptable and test live behavior rather than extrapolating from backtest markers.
//@version=6
indicator("Dynamic webhook alert", overlay = true)
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
longSignal = ta.crossover(fast, slow) and barstate.isconfirmed
shortSignal = ta.crossunder(fast, slow) and barstate.isconfirmed
if longSignal or shortSignal
side = longSignal ? "buy" : "sell"
message = '{"ticker":"MNQ","action":"' + side +
'","quantity":"1","platformType":"projectx",' +
'"accountId":"replace_with_exact_account_id","dryRun":true}'
alert(message, alert.freq_once_per_bar_close)One dialog option can hide many code paths
Selecting “Any alert() function call” enables every call whose branch and frequency allow it. Test and review all eligible calls, not only the one visible in the current chart scenario.
What exactly does a strategy order-fill alert represent?
It represents a simulated order execution by TradingView's broker emulator, not an execution at the external broker named in your webhook. Order-fill events are available automatically for strategies, and each order-generating command can define a dynamic `alert_message`. Use the alert-dialog placeholder to forward that message, then observe the external receiver and broker as a separate transaction.
Strategy orders can be created on one calculation and filled later under emulator rules. An order-fill alert fires at that emulated fill moment, which can align external routing more closely than an `alert()` emitted when the script merely creates an order. The Pine documentation specifically supports custom messages on `strategy.entry()`, `strategy.order()`, `strategy.exit()`, and `strategy.close()`. Variables in the `alert_message` expression are evaluated when the simulated order executes.
To deliver those custom messages, the running strategy alert must include order-fill events and its Message field must include `{{strategy.order.alert_message}}`. If some order-generating calls omit `alert_message`, that placeholder can resolve to an empty string for those fills. Review every entry, exit, and close path. Also decide whether the alert includes `alert()` calls, order fills, or both; enabling both without distinct intent can send two external instructions for one strategy transition.
- Creation: the script submits a simulated order to TradingView's broker emulator.
- Fill event: the emulator executes that simulated order under strategy rules.
- Webhook: TradingView sends the configured order-fill alert message.
- External outcome: the receiver and live broker independently validate, submit, reject, or fill.
//@version=6
//@strategy_alert_message {{strategy.order.alert_message}}
strategy("Order-fill webhook", overlay = true)
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
if ta.crossover(fast, slow)
entryJson = '{"ticker":"MNQ","action":"buy","quantity":"1","platformType":"rithmic","accountId":"replace_with_exact_account_id","dryRun":true}'
strategy.entry("Long", strategy.long, alert_message = entryJson)How do repainting and alert snapshots affect the choice?
Repainting changes whether a realtime condition still appears after reload, while snapshots determine which script and inputs the running alert continues to execute. Use confirmed-bar triggers when final bar data is required, test every-tick strategies separately, and recreate alerts after reviewed changes. Never assume the current chart code is identical to the server-side alert instance.
Realtime highs, lows, and closes are fluid until the bar confirms. An intrabar `alert()` or `alertcondition()` can legitimately emit on a value that disappears from the historical-looking chart later. Once-per-bar-close reduces this class of discrepancy by waiting for confirmed data, but it also delays the event. Higher-timeframe data and every-tick strategy settings introduce additional repainting considerations. Choose timing according to the strategy's actual requirement, not because one frequency seems universally safer.
At alert creation, TradingView saves the script, inputs, chart symbol, and timeframe as a mirror instance on its servers. Editing any of those later does not update the running alert. This affects all three choices: an old `alertcondition()`, an old `alert()` JSON builder, or an old strategy order-fill message can keep firing. Version labels in documented payload fields help identify stale instances, but the fix is a controlled delete-and-recreate process.
- 1
Define acceptable timing
State whether the event requires confirmed bar data, intrabar responsiveness, or emulator fill timing.
- 2
Select one trigger family
Avoid enabling alert calls and order fills together unless their external actions are deliberately distinct.
- 3
Version the payload
Use a documented strategy or alert label so logs reveal which reviewed configuration emitted.
- 4
Recreate and retest
Replace the server-side alert after every approved code, input, message, symbol, or timeframe change.
What decision process avoids double-firing webhooks?
Write one row per external order intent and assign exactly one Pine trigger source to it. Specify event moment, eligible direction, message construction, frequency, re-arm rule, and expected receiver action. Then test a long, short, exit, repeated condition, open-bar reversal, and stale-alert scenario in dry mode before any smallest-size live test.
A common double-fire occurs when an `alert()` is called as a strategy creates an order and the same running alert also includes the later order-fill event. Another occurs when separate Long and Short `alertcondition()` instances overlap with an old “Any alert() function call” alert. Inventory active alerts rather than reviewing source code alone. Disable or delete legacy instances, and name new instances with strategy version, symbol, timeframe, and trigger family.
The receiver payload should remain the same documented contract whichever Pine primitive creates it: lowercase platform, exact account ID, destination symbol, supported side or action, quantity, and optional controls. Run `dryRun: true` first. A successful validation proves the message and route can be planned, not that the chosen Pine event corresponds to a live broker fill. Observe one end-to-end order and reconcile the broker before scaling.
| Intent | Chosen source | Re-arm rule | Primary failure test |
|---|---|---|---|
| Enter long | One named condition, one guarded call, or one order-fill event | New qualifying transition while flat | Condition remains true for several realtime updates |
| Enter short | A separately reviewed source | New opposite transition while flat | Long and short branches become true around one bar |
| Exit | Explicit exit event | Position-state transition | Entry and exit messages occur close together |
| Diagnostic warning | Non-order `alert()` | Documented reset | Ensure receiver cannot interpret it as trade intent |
Sources and methodology
HexTrade Research uses official product, exchange, regulator, and vendor documentation. Policies and platform behavior can change; follow the linked source and verify current terms before trading.
- 1.Pine Script alerts — TradingView, accessed Aug 30, 2026
- 2.Pine Script alerts FAQ — TradingView, accessed Aug 30, 2026
- 3.How to configure webhook alerts — TradingView, accessed Aug 30, 2026
- 4.Using credentials for webhooks — TradingView, accessed Aug 30, 2026
- 5.Pine Script webhook payloads — HexTrade Docs, accessed Aug 30, 2026
- 6.TradingView webhook automation — HexTrade Docs, accessed Aug 30, 2026
Frequently asked questions
Can `alertcondition()` trigger from a strategy?
No. TradingView documents that `alertcondition()` calls have no trigger effect in strategies even though the code does not produce a compilation error. Strategies can expose `alert()` calls and order-fill events. Use an indicator if named `alertcondition()` choices are required.
Can `alert()` detect a strategy order fill directly?
No. Once the script sends an order to the broker emulator, the emulator controls execution and does not report the fill directly back for an immediate `alert()` call. Configure strategy order-fill events when the simulated fill itself must trigger the alert.
What does `{{strategy.order.alert_message}}` do?
In a strategy order-fill alert, it is replaced by the dynamic `alert_message` associated with the order-generating command whose simulated order filled. Include it in the alert Message or strategy annotation, and ensure every relevant order command supplies a message.
Which alert type supports dynamic JSON?
`alert()` accepts a dynamic series string, and a strategy order command's `alert_message` can also be dynamic for order-fill alerts. `alertcondition()` requires a constant message, though supported placeholders can inject selected runtime values into that template.
Does an order-fill alert prove a live broker fill?
No. It proves a simulated execution in TradingView's broker emulator. The external webhook then begins another route. Verify receiver validation, broker submission, acceptance, and final fill independently before treating the live account as synchronized.
Next step
Put the research into a controlled workflow
Start small, verify the broker and account rules, and keep risk controls between every signal and live order.
Explore webhook automationContinue reading
Educational content only. Futures are leveraged products and can produce losses greater than the amount you expected to risk. This article is not financial, legal, or prop-firm compliance advice.