Skip to content
AlertaChart
← Guides

AlertaScript

Pine Script alternative: run Pine-style scripts in AlertaScript

No converter needed: paste Pine-style code into the AlertaScript editor. What runs unchanged, what returns na, and three tested examples.

Updated Reviewed: Oct 5, 2026 · AlertaChart editorial teamProduct facts checked: Oct 5, 20268 min read

If you have written indicators or strategies in Pine Script®, you do not need a converter or a new language to run them on AlertaChart. AlertaScript accepts a broad Pine-compatible syntax — namespaced calls such as ta.ema, arrays, maps, user-defined types and strategies — and you start by pasting your code into its editor as it is.

This guide is for traders deciding whether to move their scripts: what to expect in the first five minutes, what runs unchanged, what quietly returns no data, and three complete examples that we tested on both of AlertaChart's script engines. The reference version of the same material, with an "Open in editor" button on every example, is the documentation page Pine compatibility and migration.

Why no converter is needed

Converters exist because most platforms speak another language. AlertaScript reads the same syntax, so the editor runs exactly the code you paste — it does not rewrite it. The documentation writes functions with an alerta. prefix to tell them apart (alerta.ta.ema), but the original names work too and resolve to the same calculation, without a naming warning. The //@version line of an existing script can stay. No converter does not mean nothing ever changes: now and then a call needs a small edit, and the editor names the line where that is the case.

indicator("EMA spellings", overlay=true)
original = ta.ema(close, 20)
prefixed = alerta.ta.ema(close, 20)
plot(original, "TradingView-compatible")
plot(prefixed, "AlertaScript", color=color.blue)

Both lines are the same EMA and lie on top of each other.

Your first five minutes

  1. Open a chart and, from the Indicators menu, open the AlertaScript editor. It is a window you can move while the chart stays visible.
  2. Paste your script without changing anything and press Run.
  3. Read the messages. Errors come with their line. A warning means the script ran but could not supply a value — note it and look it up below.
  4. A Run that ends without an error also saves the script to your library under My scripts; warnings do not block it.
  5. Change the inputs from the gear of the script's row on the chart, the same way as any indicator.

Open the chart with the AlertaScript editor →Trader

AlertaScript is included from the Trader plan; alerts on a script's conditions come with Pro and Elite. Pricing compares the plans. The Help Center's AlertaScript article covers the editor, the script library and sharing.

What runs unchanged, what does not

Syntax is rarely the problem. Data is. These limits come from the documentation's limits page and the engine itself:

Your script usesWhat happens
ta.*, math.*, str.*, arrays, maps, matrices, types, strategy.*Runs. Search the reference by the name you know if a call fails.
request.security for another timeframe or symbolRuns when the symbol exists on AlertaChart and has history for the period.
request.financial, request.earnings, request.dividends, request.splitsReturns na: there is no fundamentals feed. You see a warning unless the call passes ignore_invalid_symbol = true.
request.seed, request.quandlNot supported; returns na with a warning.
syminfo.current_contractNot supported; gives no contract code.
Footprint or open-interest data (request.footprint, tickers such as BINANCE:BTCUSDT.P_OI)Pro and Elite plans, on supported markets and timeframes; on other plans na with a warning. See order flow data.

A script that relies on any of these still runs — it just draws an empty line. That is why a migration is checked by looking at the output, not only by the absence of errors.

Example 1: an EMA crossover strategy

Long when the 9-period EMA crosses above the 21-period EMA, flat on the opposite cross, with a protective stop 2 % under the average entry price. The defaults in strategy(...) — 10,000 starting capital, 10 % of equity per order and 0.1 % commission — are what the Strategy tester starts from.

//@version=5
strategy("EMA crossover strategy", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, commission_type=strategy.commission.percent, commission_value=0.1)
fastLength = input.int(9, "Fast EMA length", minval=1)
slowLength = input.int(21, "Slow EMA length", minval=2)
stopPercent = input.float(2.0, "Stop loss (%)", minval=0.1, step=0.1)

fast = ta.ema(close, fastLength)
slow = ta.ema(close, slowLength)
crossUp = ta.crossover(fast, slow)
crossDown = ta.crossunder(fast, slow)

if crossUp
    strategy.entry("Long", strategy.long)
if crossDown
    strategy.close("Long", comment="EMA cross down")
// A protective stop: an absolute price, recalculated from the average entry price.
if strategy.position_size > 0
    strategy.exit("Stop", "Long", stop=strategy.position_avg_price * (1 - stopPercent / 100))

plot(fast, "Fast EMA", color=color.teal)
plot(slow, "Slow EMA", color=color.orange)
plotshape(crossUp, title="Cross up", style=shape.triangleup, location=location.belowbar, color=color.teal, size=size.tiny)
  • Results appear in the Strategy tester under the chart: key stats first (total P&L, maximum drawdown, profitable trades, profit factor), then the list of trades. Its settings change capital, order size, commission and slippage without editing the code.
  • In the simulation, an order placed on the signal bar fills at the open of the next bar, so the marker and the fill price differ.
  • stop= is an absolute price, which is why the input is converted. profit= and loss= would be distances in ticks.
  • A strategy never sends orders to an exchange. A test on past data says nothing certain about the future.

Example 2: RSI divergence with alert conditions

An indicator in its own pane that compares RSI pivots with price: a lower price low on a higher RSI low is marked bullish, a higher price high on a lower RSI high bearish. Each case is a named alertcondition.

//@version=5
indicator("RSI divergence finder", overlay=false)
rsiLength = input.int(14, "RSI length", minval=2)
pivotBars = input.int(5, "Bars on each side of a pivot", minval=1)

rsi = ta.rsi(close, rsiLength)
// A pivot is only known pivotBars bars after it formed.
rsiLow = ta.pivotlow(rsi, pivotBars, pivotBars)
rsiHigh = ta.pivothigh(rsi, pivotBars, pivotBars)
newLow = not na(rsiLow)
newHigh = not na(rsiHigh)

// RSI and price at the previous pivot of the same kind.
lastRsiLow = ta.valuewhen(newLow, rsi[pivotBars], 1)
lastPriceLow = ta.valuewhen(newLow, low[pivotBars], 1)
lastRsiHigh = ta.valuewhen(newHigh, rsi[pivotBars], 1)
lastPriceHigh = ta.valuewhen(newHigh, high[pivotBars], 1)

// Price makes a lower low while RSI makes a higher low (bullish), or the reverse at highs (bearish).
bullish = newLow and low[pivotBars] < lastPriceLow and rsi[pivotBars] > lastRsiLow
bearish = newHigh and high[pivotBars] > lastPriceHigh and rsi[pivotBars] < lastRsiHigh

plot(rsi, "RSI", color=color.purple)
hline(70, "Upper level")
hline(30, "Lower level")
plot(bullish ? rsi[pivotBars] : na, "Bullish divergence", color=color.green, style=plot.style_circles, linewidth=4, offset=-pivotBars)
plot(bearish ? rsi[pivotBars] : na, "Bearish divergence", color=color.red, style=plot.style_circles, linewidth=4, offset=-pivotBars)
alertcondition(bullish, "Bullish RSI divergence", "{{ticker}}: bullish RSI divergence confirmed")
alertcondition(bearish, "Bearish RSI divergence", "{{ticker}}: bearish RSI divergence confirmed")
  • A pivot is confirmed only after five more bars (the default input), so on a live chart a mark appears five bars late; offset places it back on the pivot bar.
  • To be notified (script alerts come with the Pro and Elite plans), open Create Alert, choose Script as the source and then this script, and pick the condition by its title from the Script alerts list. {{ticker}} becomes the symbol.
  • The alert window states it plainly: script alerts are evaluated while AlertaChart is open; they do not run around the clock on the server yet. Price alerts are covered in the alerts article.

Example 3: a higher-timeframe trend filter

request.security calculates the whole expression on the requested timeframe — here a 50-period EMA of 4-hour candles — and lines the result up with your chart. One call returns two values as a tuple.

//@version=5
indicator("Higher-timeframe trend filter", overlay=true)
higherTf = input.timeframe("240", "Higher timeframe")
emaLength = input.int(50, "EMA length on the higher timeframe", minval=1)

// One request returns both values, each calculated on the higher timeframe's own bars.
[htfEma, htfClose] = request.security(syminfo.tickerid, higherTf, [ta.ema(close, emaLength), close], lookahead=barmerge.lookahead_off)
uptrend = htfClose > htfEma

plot(htfEma, "Higher-timeframe EMA", color=uptrend ? color.teal : color.red, linewidth=2)
bgcolor(uptrend ? color.new(color.teal, 92) : color.new(color.red, 92), title="Trend background")
  • An EMA computed on 4-hour candles is not the same as averaging 4-hour closes on a 1-hour chart.
  • lookahead_off uses no future bars. While the current 4-hour candle is still open, its value can change.
  • Pick another timeframe from the gear: input.timeframe makes it a setting.

Honest differences

  • Live versus closed candles. Scripts recalculate while a candle forms; a cross can appear and vanish before the close. Use barstate.isconfirmed when a rule must wait for it.
  • Data. Compare the same exchange, symbol and timeframe. BTC/USDT on two exchanges is two different price series, so indicator values differ even with identical code.
  • History. How far back a chart goes depends on the market and its data source, so long lookbacks may start later than elsewhere.
  • Resources. Loops and drawing objects are bounded. The limits page publishes no fixed numbers, so delete objects you no longer need instead of creating new ones on every bar.

Common problems

  • "Unknown function": search the reference by the original name and by its alerta. spelling. A call into a library that is not loaded is different: it returns na with a warning.
  • An empty line: early bars without enough history, an na request, or an oscillator that opened in its own pane.
  • Different trades than elsewhere: match quantity, commission, slippage and the test range first, then the fill rule above.

For a reproducible error, the documentation's troubleshooting page shows how to reduce it to a small example.

Next steps

Sources

  1. Pine compatibility and migration — AlertaScript documentation (accessed Oct 5, 2026)
  2. Limits and availability — AlertaScript documentation (accessed Oct 5, 2026)
  3. Strategies and backtesting — AlertaScript documentation (accessed Oct 5, 2026)
  4. Multiple symbols and timeframes — AlertaScript documentation (accessed Oct 5, 2026)
  5. AlertaScript: your own indicators and strategies — AlertaChart Help Center (accessed Oct 5, 2026)

How this guide was made Drafted with AI from AlertaChart's Help Center and source code; product facts checked against the code and the Help Center; external facts from the cited primary sources.

Changes · Version 1.0
  • · 1.0 — First version.