Alerts
Alert conditions with alert.on, messages with alert.send, script alerts checked on ChartDeck's servers, triggers, placeholders and limits.
A script can describe the moments worth being told about: a cross, a breakout, a level touched. ChartScript has two ways to do that. alert.on declares a named condition, and alert.send sends a message from your code when something happens.
#alert.on: named conditions
const fast = ta.ema(close, 9)
const slow = ta.ema(close, 21)
alert.on(ta.crossover(fast, slow), "Bull cross", "{{ticker}} fast EMA crossed above the slow one")conditionis aboolseries: the alert condition is met on bars where it is true.titleis the name shown in the list of conditions. It must be a constant string.messageis the default text of the alert, also a constant; it may contain placeholders.
alert.on must be at the top level of the script, never inside an if, loop or function: the list of conditions has to be known without running the script. Inside a branch it is error CS3201:
//@chartscript 1
indicator("Alert in a branch")
if (close > open) {
alert.on(close > high[1], "Breakout")
}Compute the condition first and pass it in instead: alert.on(close > open && close > high[1], "Breakout"). A script may declare up to 200 conditions.
#Seeing the conditions on the chart
Every script with alert.on gets an Alert conditions switch on the Style tab of its settings (off by default). Turn it on and a small dot appears under each bar where a condition is true. It is the quickest way to check that a condition fires where you expect, including on history.
#alert.send: messages from code
if (ta.crossover(close, ta.highest(high, 20)[1]) && barstate.isconfirmed) {
alert.send("New 20-bar high at " + str.tostring(close, format.mintick), alert.freq_once_per_bar_close)
}Unlike alert.on, alert.send can be called anywhere (inside if blocks, loops, functions) and its message is a series string, so it can carry values computed on the bar. The second argument is how often it may fire:
| Constant | Fires |
|---|---|
alert.freq_once_per_bar (default) | at most once per bar, as soon as the call runs; on the live bar that may be before the bar closes |
alert.freq_once_per_bar_close | at most once per bar, when the bar closes |
alert.freq_all | on every run that reaches the call, so on every update of the live bar |
alert.freq_once_per_bar_close is the one that never fires for a bar that later turns around; see repainting.
#Creating a script alert
Add the script to a chart, then open Create alert… from the script's legend row (or its row in the object tree). The alert dialog opens on the chart's market and timeframe with the script's conditions:
- every
alert.oncondition, by its title; - Any alert.send() call, when the script calls
alert.send.
You can also open Create alert from the toolbar and pick the script under Or a script on this chart in the market menu.
The dialog shows the inputs the alert will run with: the script's settings on that chart when you create it. Changing the chart's settings later does not change the alert; create a new one, or edit the alert from the chart again. Your own script's alert runs the version you had on the chart; an alert on a Community script follows the version its author publishes.
Then choose the trigger (below), the expiry, the message and where to be notified: in the app, with a sound, by browser push, and on Plus, Pro and Elite also by email, Telegram, Discord, webhook or plain-text email, exactly as for ChartDeck's other alerts.
#It runs on ChartDeck's servers
A script alert does not need your browser. ChartDeck runs the script on its own servers, on exactly the same bars as the script on your chart (its calc_bars_count, else 5,000 bars, within your plan's bars per run), and checks the condition there, also while every tab is closed. The values are the ones your chart shows at each bar close. Alerts on the same script, market, timeframe and inputs share one run, so a popular Community script costs no more for a thousand members than for one.
A protected Community script stays protected: you get its conditions' titles and its messages, never its code.
#Triggers
| Trigger | When it fires |
|---|---|
| Once per bar close (default) | when a bar closes with the condition true; at most once a bar; never for a bar that later turns around |
| Once per bar | on the live bar, as soon as the condition is true; at most once a bar. It can fire on a bar that closes the other way |
| Once | like once per bar close, and then the alert ends |
For Any alert.send() call the call's own frequency applies too: with once per bar close only calls made when the bar closes count; with once per bar the calls of the live bar count as well, except those made with alert.freq_once_per_bar_close. One alert fires at most once a bar, with the first message of that bar.
If a script is too slow to run on every update of the live bar, a once per bar alert is checked at bar close only, and the Alerts panel says so ("too slow on the live bar: checked at bar close only"). It keeps firing on closes.
#A restart never fires twice
If ChartDeck restarts, the alert picks up where it was: a bar it already checked is never checked again, and a bar that closed while the servers were restarting is checked once.
#When a script alert pauses
A script alert pauses, and the bell tells you once, when it can no longer run:
- the author removed your access to an invite-only script, or the script left the Community;
- you deleted the script, or the version the alert runs;
- the script no longer compiles, or no longer has the condition;
- script alerts are not available on your plan.
The Alerts panel shows the reason under the alert. Resume checks again first and tells you if the reason is still there.
#Plan limits
Script alerts have no count of their own: they share your plan's alerts total with price, technical, watchlist and calendar alerts.
| Beginner | Plus | Pro | Elite | |
|---|---|---|---|---|
| Alerts of every kind together (active or paused) | 10 | 250 | 700 | 2,500 |
A script alert can use any timeframe your plan can chart, seconds included, like every other alert. How long an alert runs before it expires follows your plan, as for every alert. When every alert of your total is in use, creating one more says "Your plan allows 10 active alerts in total. Upgrade for more." (on Beginner; your plan's own number on the others); delete or let an alert end to make room.
#Message placeholders
ChartDeck's alert messages replace {{name}} placeholders with the values of the moment the alert fires. These are the ones the alert system understands:
| Placeholder | Becomes |
|---|---|
{{ticker}} | the symbol, e.g. BTCUSDT |
{{exchange}} | the exchange, e.g. Binance Futures |
{{interval}} | the alert's timeframe, e.g. 1h |
{{open}} {{high}} {{low}} {{close}} {{volume}} | the bar's values ({{close}} is the last price) |
{{time}} | when it fired (UTC, ISO 8601) |
{{value}} | the level of the condition |
{{alert_name}} | the alert's name |
{{plan}} | your ChartDeck plan |
A script alert understands three more:
| Placeholder | Becomes |
|---|---|
{{plot_0}}, {{plot_1}}, … {{plot_63}} | the value of the script's first, second, … plotted output on the bar that fired, in the order the script declares them |
{{plot("Title")}} | the value of the plot with that title |
{{message}} | the text of the alert.send call (the default message of an "Any alert.send() call" alert) |
The default message of an alert.on condition is the message the script gives it; you can change it in the dialog. Placeholders that are not in these lists are left exactly as written, and messages are always plain text. Text that alert.send puts into {{message}} is inserted as it is: placeholders inside it are not filled. With alert.send you can also put any value into the message yourself with str.tostring or str.format.
#A whole example
A breakout indicator that declares both directions as named conditions, sends a message with the breakout size, and draws the levels it watches:
//@chartscript 1
indicator("Range breakout", { overlay: true })
const len = input.int(20, "Range length", { minval: 2, maxval: 200 })
const top = ta.highest(high, len)[1]
const bottom = ta.lowest(low, len)[1]
plot(top, "Range top", color.up, { style: plot.style_stepline })
plot(bottom, "Range bottom", color.down, { style: plot.style_stepline })
const breakUp = close > top && barstate.isconfirmed
const breakDown = close < bottom && barstate.isconfirmed
plotshape(breakUp, "Break up", shape.triangleup, location.belowbar, color.up)
plotshape(breakDown, "Break down", shape.triangledown, location.abovebar, color.down)
alert.on(breakUp, "Breakout up", "{{ticker}} {{interval}} closed above the range at {{close}}")
alert.on(breakDown, "Breakout down", "{{ticker}} {{interval}} closed below the range at {{close}}")
if (breakUp || breakDown) {
const size = breakUp ? (close - top) / top * 100 : (bottom - close) / bottom * 100
alert.send(
(breakUp ? "Up" : "Down") + " breakout of " + str.tostring(size, "0.00") + " % beyond the " + str.tostring(len) + "-bar range",
alert.freq_once_per_bar_close
)
}#sound.play: a sound on the chart
An alert reaches you wherever you are. Sometimes you only want the chart to make a short sound while you watch it: sound.play does that.
if (ta.crossover(close, ta.sma(close, 20))) {
sound.play(sound.chime, 0.5)
}- The first argument is one of the built-in sounds:
sound.chime,sound.ping,sound.pop,sound.tick,sound.knock,sound.rise,sound.fall,sound.coin,sound.thudorsound.alarm. They are made in the browser; no file is loaded. sound.custom1tosound.custom3play the viewer's own clips: files each member picks in Settings > Sounds, kept in their browser. A script can not name a web address or a file: anything that is not asound.*id is ignored.- The volume goes from 0 to 1; the viewer's own volume and mute apply on top. The third argument is the same
alert.freq_*as foralert.send(default: once per bar).
When it plays: only while the chart is open and its tab is in front, only for the newest bar as it updates live (never while the history is calculated), at most one sound per run, and the page spaces sounds out so that a burst of signals does not turn into a burst of noise. Browsers allow sound only after you click or press a key on the page once. For a sound while the tab is in the background, create an alert with a sound instead.