alertcondition versus alert()
Lesson 13 · about 10 min
An alert turns a script from something you watch into something that watches for you. TradingView runs the script on its servers and sends a notification, email, or webhook when a condition fires. Pine offers two mechanisms, and which one you pick decides what the alert dialog shows, what the message can contain, and how many alerts you have to create.
alertcondition(): a named condition in the dialog
//@version=6
indicator("Alert basics", overlay=true)
ema = ta.ema(close, 21)
crossUp = ta.crossover(close, ema)
crossDn = ta.crossunder(close, ema)
plot(ema, "EMA 21", color=color.orange)
alertcondition(crossUp, title="Cross above EMA 21", message="{{ticker}} crossed above EMA 21 at {{close}}")
alertcondition(crossDn, title="Cross below EMA 21", message="{{ticker}} crossed below EMA 21 at {{close}}")
alertcondition(condition, title, message) registers a condition. It draws nothing and fires nothing by itself. When a user opens the "Create alert" dialog on a chart with this script, the dropdown lists "Cross above EMA 21" and "Cross below EMA 21", and they create one alert per condition they want. The message is a fixed string set at compile time, with {{placeholder}} substitutions filled in by TradingView at fire time.
Properties:
- Indicator scripts only; strategies cannot use it.
- Must be in the global scope, like
plot(). - The message cannot include values computed at runtime except through placeholders.
- One alert per condition per symbol. Ten conditions means ten alerts to set up.
- Changing the script does not change existing alerts; they keep running the version they were created from until recreated.
That last point matters. An alert is a snapshot of the script and its inputs at creation time. Fix a bug, and every alert built on the old code keeps firing the old way.
alert(): fire from inside the code
//@version=6
indicator("Dynamic alerts", overlay=true)
ema = ta.ema(close, 21)
atr = ta.atr(14)
crossUp = ta.crossover(close, ema)
plot(ema, "EMA 21", color=color.orange)
if crossUp
msg = "Long setup on " + syminfo.ticker + " at " + str.tostring(close, format.mintick) +
", stop " + str.tostring(close - 2 * atr, format.mintick)
alert(msg, alert.freq_once_per_bar_close)
alert(message, freq) is a function call inside a condition. The message is built at runtime, so it can contain any value the script knows: a computed stop, a risk multiple, the result of a request.security call. The user creates a single alert with the condition "Any alert() function call", and every alert() in the script goes through it. Add a new signal to the code and it is covered by the existing alert once the alert is recreated.
The frequency argument:
alert.freq_once_per_bar_close: fire once, when the bar closes with the condition true. The safe default.alert.freq_once_per_bar: fire the first time the condition is true during the bar, even if it later becomes false.alert.freq_all: fire on every tick while true. Rarely what you want.
alert() can be called in local scope, from strategies as well as indicators, and multiple times per bar with different messages.
Strategy order alerts
Strategies have a third route. When an order fills in the broker emulator, an alert created with "Order fills only" or "Order fills and alert() function calls" fires with the order details, using placeholders like {{strategy.order.action}}. strategy.entry() and strategy.exit() accept an alert_message argument that becomes {{strategy.order.alert_message}}. That is how automated execution bridges receive a strategy's orders, and module 6 shows it in practice.
Which one to use
| Need | Use |
|---|---|
| Simple indicator, user picks which signals | alertcondition() |
| Message with computed values | alert() |
| Many signal types under one alert | alert() |
| Strategy orders to a webhook | order-fill alerts + alert_message |
| Published script for a wide audience | alertcondition() (familiar to users) |
Many scripts include both: alertcondition() for users who want the standard dialog, alert() for users who want everything through one alert with richer messages.
Key idea:
alertcondition()declares a fixed, named condition that users pick in the dialog;alert()fires from inside the code with a runtime-built message through a single "Any alert() function call" alert.
The alert dialog
Whichever you use, the user still has to create the alert: right-click the chart or press the alert button, choose the script and condition, set expiration and frequency, and choose notification channels. On free plans the number of active alerts is small and they expire after a period; paid plans raise both. Webhook delivery is a paid feature. These details change, so check the plan comparison rather than assuming.
Try it: Add both mechanisms to the EMA cross script. Create one alert on "Cross above EMA 21" and another on "Any alert() function call". Then change the EMA length in the script's settings and notice that neither alert changes until you recreate it.
Recap
alertcondition(cond, title, message)registers a named condition; indicators only, global scope, fixed message with placeholders.alert(message, freq)fires from inside a condition with a runtime message through one "Any alert() function call" alert.alert.freq_once_per_bar_closeis the safe frequency;freq_once_per_barandfreq_allfire on unconfirmed bars.- Strategies use order-fill alerts with
alert_messageinstead ofalertcondition. - Alerts snapshot the script at creation; recreate them after any code or input change.
See it drawn
Original diagrams for the ideas on this page. Illustrative, not real market data.