alertcondition(condition, title, message?)
rsi = ta.rsi(close, 14)
alertcondition(ta.crossover(rsi, 70), "RSI overbought", "{{ticker}} RSI crossed above 70")
alertcondition(ta.crossunder(rsi, 30), "RSI oversold", "{{ticker}} RSI crossed below 30")
titleis what the user sees in the Alerts tab when adding an alert.messageis the default text — the user can override it in the dialog. It accepts placeholders (below).- Called from script scope only. Only
conststrings fortitle/message.
alert(message, freq?)
A dynamic call fires an alert directly from the body:
if volume > ta.sma(volume, 20) * 3
alert("Volume spike on " + syminfo.ticker + " @ " + str.tostring(close),
alert.freq_once_per_bar_close)
freq |
Fires |
|---|---|
alert.freq_all |
Every tick on the forming bar |
alert.freq_once_per_bar |
At most once per bar (on the first evaluation that matches) |
alert.freq_once_per_bar_close |
Once per bar, only on the confirmed (closing) evaluation |
Omitting freq defaults to alert.freq_once_per_bar (the reference default). Use freq_once_per_bar_close when a signal must not fire on a forming bar that later reverses.
Placeholders
alertcondition default messages and the message typed into the alert dialog support these {{…}} placeholders. They are substituted by the alert service at delivery time:
| Placeholder | Replaced with |
|---|---|
{{ticker}} |
Symbol ticker (TCS) |
{{exchange}} |
Exchange (NSE) |
{{interval}} |
Chart interval (5, 1D) |
{{time}} |
Time of the bar that fired (ISO 8601) |
{{timenow}} |
Wall-clock time at delivery (ISO 8601) |
{{plot("Title")}} |
Current value of the plot with that title= (na when the plot has no value) |
Anything else inside {{…}} is left verbatim. Bar values (close, volume, …), strategy.* account values and the reference platform's {{plot_0}} / {{strategy.order.*}} forms are not substituted — build such text in the script with str.tostring() and pass it to alert() or alert_message= instead:
if ta.crossover(close, ta.sma(close, 20))
alert("Long " + syminfo.ticker + " @ " + str.tostring(close, format.mintick), alert.freq_once_per_bar_close)
Example: 3Commas-style strategy alert
BUY_JSON = '{"action":"buy","bot_id":4635591,"token":"***"}'
SELL_JSON = '{"action":"sell","bot_id":4635591,"token":"***"}'
if ta.crossover(close, ta.sma(close, 20))
strategy.entry("Long", strategy.long, alert_message = BUY_JSON)
if ta.crossunder(close, ta.sma(close, 20))
strategy.close("Long", alert_message = SELL_JSON)
The alert panel can arm a durable rule with trigger = order_fill and a webhookUrl; every fill's alert_message is POSTed verbatim to the webhook.
Durable server-side alerts
A rule armed from the Alerts panel registers with the platform's alert service. The script continues executing with no chart open; alertcondition() fires are delivered through the configured channels (push / email / webhook).
Durable alert fields:
scriptId/version— pinned to the version the chart raninputs— the inputs snapshot the chart usedsymbol/intervaltrigger— what fires the rule:alert_condition(default) — analertcondition()/alert()call; optionally pinned to ONEalertconditiontitle (conditionName), otherwise any firesorder_fill— a strategy order filled; the fill'salert_messageis the payloadplot_condition— a plot compared against a value, the price, or another script's plot (crossing / crossing up / crossing down / greater than / less than / entering, exiting, inside, outside channel / moving up, moving down, moving up %, moving down %) — no code needed
freq—only_once(fires then stops),once_per_bar,once_per_bar_close,once_per_minute,allchannels— any combination ofpush,email,webhookwebhookUrl— target for the webhook channel; must be a publichttp(s)host (private, loopback and link-local addresses are rejected, and re-checked on every delivery)message— overrides the script's default message; supports the placeholders above- optional expiry — the rule deactivates itself at the chosen time
Marketplace scripts. A rule on a paid script is tied to your plan: when the subscription expires the alert service deactivates the rule (reason subscription expired — renew it … to re-arm this alert) within ten minutes, or exactly at the plan end when it is known. Renewing does not re-arm it — open the Alerts panel and enable the rule again.
Safety rails: a rule that fires 15 times within 3 minutes is stopped automatically (runaway guard), and a webhook body is posted verbatim — a JSON alert_message arrives byte-for-byte, with Content-Type: application/json when it parses as JSON.
See the alerts tab in the Indicators hub for creating, pausing, deleting rules, and reading the delivery log.
Alerts and strategies
A strategy that uses alert_message= on orders can arm a trigger = order_fill rule — every filled order emits one alert carrying its alert_message. Combine with an alertcondition() or two for pre-fill signals that notify you before a bar closes.
Debugging alerts
log.info(message)from inside the body prints to the Logs panel, mirroring exactly what would go into an alert.- A test alert can be fired with
alert()andfreq=alert.freq_allto validate placeholder interpolation.
See also
- Strategies —
alert_message=on orders - Strings —
str.formatfor building messages - Debugging