Skip to content
GetProfitable
Search

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_close is the safe frequency; freq_once_per_bar and freq_all fire on unconfirmed bars.
  • Strategies use order-fill alerts with alert_message instead of alertcondition.
  • 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.

Payoff of a long call at expiryA flat loss equal to the premium below the strike, turning upward at 45 degrees above it.Profit / loss per share08595115125Strike 105Max loss 3 — the premium paidBreakeven 108Profit keeps growingUnderlying price at expiry
Buying a call: payoff at expiry. A 105-strike call bought for 3 loses that whole 3 if the price finishes at or below 105, breaks even at 108, then gains a dollar for every dollar higher. The loss is capped at the premium; the upside is not capped.
A fast and a slow moving average crossingA jagged price line with two smoother average lines through it; the fast average dips below the slow one on the left and cuts back above it in the middle, where a circle marks the crossing.pricefast averageslow averagefast crosses belowfast crosses abovethe slow averageAverages of recent closes; the fast one reacts sooner than the slow one.
Fast and slow moving averages crossing. A moving average is the average of the last few closing prices, redrawn each period. An average over fewer periods turns sooner than one over many, so the two lines cross whenever the recent pace of the market changes.