tradoor docs Open tradoor

Frost Script

tradoor's own language for indicators: readable lines that work out a value on every bar and draw it — lines, histograms, levels, marks, shapes, labels and a table, on the chart or in a pane of their own — with settings of every kind and the same numbers as the built-in indicators.

A script reads the chart's candles and gives back what to draw. That is all it can do: it has no word for the network, your account, your browser or the page, so a script someone else wrote can draw wrong lines at worst, and nothing more. See Safety.

Every built-in indicator that can be written in Frost Script shows its own source: open its settings and the Source tab — the EMA ribbon, Ichimoku, the swing map and the key levels among them. Each gives exactly the numbers the built-in does, and they are the best place to start.

Your first script

  1. On a chart, open Add an indicator and press New Frost Script. Writing a script needs you signed in with Telegram.
  2. The editor opens on a small script. Change it, or start from one of the examples on the left.
  3. Under the text it says ✓ Checks, or which line and column a mistake is on — click the message to go there.
  4. Save and add to chart. The script is now one of your indicators, in the picker under My scripts, with its own settings, style and source.
// A moving average, and a mark where price crosses above it
input length = 20 min 2 max 500 "Length"
average = ema(close, length)
plot(average, "Average", blue)
mark(crossover(close, average), "Up", below, green)

How a script runs

The script is worked out once for every bar on the chart, from the oldest to the newest, top to bottom. On each bar, close is that bar's close, a variable holds what it was set to on that bar, and plot puts that bar's point on the line.

Writing it down

Bar values

NameOn each bar
open high low closeIts prices.
volumeWhat traded in it.
hl2 hlc3 ohlc4(high + low) / 2, (high + low + close) / 3, (open + high + low + close) / 4
trTrue range: the larger of high − low and how far either reaches from the close before. On the first bar, high − low.
barIts place: 0 for the first bar the chart holds, then 1, 2, … lastbar is the newest's.
isfirst islastTrue on the first bar, and on the newest closed one.
timeWhen it opened, in milliseconds since 1970, UTC. interval is a bar's length, in milliseconds.
day week month yearWhich UTC day, week (from Monday), month and year it is in, as a number that changes when a new one begins: changed(week) is true on a week's first bar. year is also the year itself.
hour minute dayofweek dayofmonth monthofyearIts time, UTC. dayofweek is 1 on a Sunday, 2 on a Monday, as Pine counts; the words sunday to saturday stand for those numbers.
tick decimalsThe market's price step, and how many decimals its prices are written with.
naNo value. See na.
true false1 and 0.

Settings

input length = 14 min 2 max 500 "Length"
input mult = 2 min 0.1 max 10 step 0.1 "Multiplier"
input showLabels = true "Show labels"
input lineColor = #2962ff "Line colour"
input size = "small" from "tiny", "small", "normal", "large" "Label size"
input start = date(2024, 1, 1) "Range start"

Variables and state

range = high - low                 // set on every bar
state count = 0                    // starts at 0 the first time…
count = count + 1                  // …and keeps its value from bar to bar

Looking back: x[n]

gap = open - close[1]              // from the close a bar ago
climbing = close > close[1] and close[1] > close[2]

Arithmetic and logic

WriteMeans
+ - * / %Add, subtract, multiply, divide, remainder. -x turns the sign. + also joins texts.
== != < <= > >=Compare: 1 when true, 0 when not. Texts compare with == and !=.
and or notLogic. Any number other than 0 is true; 0 and na are not.
c ? a : ba where c is true, else b: both numbers, or both texts.
( )First. Then -x; then * / %; then + -; then comparisons; then not, and, or; then ? :.

No value: na

A value can be missing: an average before it has enough bars, close[1] on the first bar, a division by zero. Frost Script calls it na, and a line simply has a gap where its value is na.

Texts

tag = close > open ? "Up" : "Down"
line1 = tag + " " + str(round(change(close), 2))
note = "Since " + duration(time - time[10]) + "\nat " + str(close, decimals)
WriteGives
"text" + "text"The two joined. A number joined to a text is written plainly.
str(x)A number as a text: whole numbers bare, others to up to 8 decimals.
str(x, 2)To 2 decimals. str(x, decimals) writes it as the market writes a price.
duration(ms)A stretch of time: 3h, 2d 4h.

Texts go into titles, labels, the table and settings' choices; a text a script makes is cut at 1,000 characters.

if, for and while

input length = 10 min 1 max 100
if close > open {
  colour = 1
} else if close < open {
  colour = -1
} else {
  colour = 0
}

total = 0
for i = 0 to length - 1 {
  total = total + volume[i]
}
for k = 9 to 0 by -1 {             // down, by any step
  if close[k] > open[k] {
    break
  }
}

Lists

state swings = list()              // kept from bar to bar
ph = pivothigh(5, 5)
if not isna(ph) {
  swings.push(ph)
}
average = swings.avg()
plot(swings.size() > 0 ? swings.last() : na, "Last swing")

Functions of your own

fn middle(length) {
  return (highest(high, length) + lowest(low, length)) / 2
}
fn band(x, width) {
  return x + width, x - width
}
base = middle(26)
upper, lower = band(base, atr(14))

Functions over bars

These remember the bars before: an average needs the last length values. So each one is worked out on every bar, which is why they go outside if, for and while — and why both sides of c ? a : b are always worked out. A length is from 1 to 5,000: a number, a setting, or maths on them such as length * 2 or round(length / 2), rounded to a whole number. It cannot be a variable.

FunctionGives
sma ema rma wma vwma hma
(x, length)
Simple, exponential (seeded with the simple average), Wilder's (as RSI and ATR use), weighted, volume-weighted and Hull averages.
stdev dev median (x, length)Standard deviation of the whole set (÷ length), mean absolute deviation, median.
highest lowest sum (x, length)The highest, the lowest, and the sum of the last length. highest(n) reads the highs, lowest(n) the lows.
highestbars lowestbars (x, length)How many bars back the highest or lowest is: 0 or less, as Pine gives it.
rsi(x, length), atr(length)Relative Strength Index, 0 to 100; average true range, rma(tr, length).
change(x), change(x, n), roc(x, n)x − x[1], x − x[n], and that as a percentage of x[n].
linreg cci mfi percentrank (x, length)Linear regression at the newest bar; commodity channel index; money flow index (with volume); percent of the values before that are at or below this one.
stoch(x, high, low, length), correlation(a, b, length)Stochastic, 0 to 100; correlation, −1 to 1.
rising falling (x, n)True where x is above (below) each of its n values before.
pivothigh pivotlow (left, right)The high (low) right bars back, where it is higher (lower) than the left bars before it and the right bars after; na elsewhere. Known right bars late, as in Pine. A value may come first: pivothigh(close, 5, 5).
crossover crossunder cross (a, b)True on the bar a goes from at or below b to above it, the other way, or either.
barssince(c), valuewhen(c, x)Bars since c was last true (0 on that bar), and x as it was then.
changed(x), cum(x)True on a bar where x is not what it was a bar ago; the sum of every x so far.

An average that meets na starts over after it, as the built-in indicators do.

Maths

These work out a value from what they are given, and go anywhere.

FunctionGives
abs sqrt log log10 exp sign (x)Without its sign; square root (na below zero); logarithms (na at zero and below); e to the x; −1, 0 or 1.
pow(x, y)x to the power y.
round(x), round(x, digits), floor ceilTo the nearest whole number or to 0–10 decimals; down; up.
min max avg (a, b, …)The least, the greatest, and the average of 2 to 12 values; na if any is.
clamp(x, low, high)x kept between the two.
nz(x), nz(x, y), isna(x)x, or 0 — or y — where it is na; whether it is.
sin cos tan atan (x), atan2(y, x), piIn radians.
date(year, month, day, hour, minute)A moment in milliseconds, UTC; the hour and minute may be left out.
barat(time)The place of the bar holding a moment; na before the first.

Colours

green lime red orange yellow blue aqua
teal purple pink white gray black silver
maroon navy olive fuchsia

Plots, marks and shading

These draw along the bars, at the top level, on every bar. Each line needs a title of its own (up to 40 characters): it is what the legend and the Style tab show.

WriteDraws
plot(value, "Title", color, width, style, offset)A line through each bar's value, with gaps where it is na. style: line steps dots dashed dotted. Width 0.5 to 10. offset moves it by bars: 26 draws it 26 bars ahead, past the newest. A colour that changes from bar to bar colours the line bar by bar.
histogram(value, "Title", color, offset)A bar from zero for each value, in a colour of its own bar by bar if it is given one; with none, above zero and below take the chart's up and down colours.
hline(value, "Title", color, width, style)A level, dashed unless another style is named; gray unless another colour is.
fill("Upper", "Lower", color)Shades between two lines drawn above it, named by their titles.
mark(condition, "Text", above or below, color)A mark at the bar where the condition is true: below its low (green unless named) or above its high (red unless named). Text up to 12 characters, or none.
background(color)Shades the bar's whole height, in its pane; na leaves it.
barcolor(color)Colours the bar's candle; na leaves it as it is.
pane ownDraws the script in a pane of its own below the chart, with its own scale. pane price, the default, draws on the price chart.
A colour as solid as can be is shaded lightly in fill and background, so the candles show through; give one an opacity of its own with alpha(). plot(x, "X", color = na) keeps a line's values, for a fill, without drawing it. Up to 32 lines, 16 fills, 16 marks and 4 backgrounds.

Lines, labels and boxes

state last = na
ph = pivothigh(5, 5)
if not isna(ph) {
  delete(last)
  last = line(bar - 5, ph, bar + 20, ph, color = red, style = dashed)
  tag = label(bar - 5, ph, "High\n" + str(ph, decimals), color = red, place = above)
}

Shapes are drawn anywhere — in if, loops and functions — and stay until they are deleted. A shape's x is a bar's place (bar, bar - 5, bar + 10 ahead of the newest), its y a price. Each is given back as a number to keep, move or delete it by.

WriteDraws
line(x1, y1, x2, y2, color, width, style, extend)A straight line. style: solid dashed dotted. extend: none left right both, on past its points.
label(x, y, text, color, textcolor, place, size, box)A text at a point, in a box pointing at it. place: above below left right center; size: tiny small normal large; box = false draws the text alone. Its text may run over several lines.
box(x1, y1, x2, y2, color, border, width)A rectangle, filled and outlined.
delete(id)Lets one go. na, or one already gone, is left alone.
set_x1 set_y1 set_x2 set_y2 (id, v), set_xy1 set_xy2 (id, x, y)Moves one end. For a label, set_x set_y set_xy.
set_text set_color set_textcolor set_widthChanges it.
get_x1 get_y1 get_x2 get_y2 (id), get_text(id)Reads it back.

Up to 500 lines, 500 labels and 200 boxes: past these, the oldest goes as a new one is drawn.

The table

table("top right")
averageRange = sma(high - low, 20)
if islast {
  cell(0, 0, "Average range", gray)
  cell(1, 0, str(averageRange, decimals), white, alpha(blue, 0.4))
}

Examples

The editor's examples are tradoor's built-in indicators written in Frost Script, each giving exactly the built-in's numbers: SMA, EMA, the EMA 12/25 ribbon and EMA 200, Bollinger Bands, Keltner Channels, Ichimoku, RSI, Stochastic RSI, MACD, ATR, VWAP, anchored VWAP, the historical key levels, the swing structure map, trading sessions, moon phases and volume, and a SuperTrend. Open any of them, or any built-in's Source tab, to read it.

SuperTrend, with a mark at each turn

input length = 10 min 1 max 1000 "ATR length"
input mult = 3 min 0.1 max 10 step 0.1 "Multiplier"
band = mult * atr(length)
state trend = 1
state stop = na
if trend == 1 {
  stop = isna(stop) ? hl2 - band : max(hl2 - band, stop)
  if close < stop {
    trend = -1
    stop = hl2 + band
  }
} else {
  stop = isna(stop) ? hl2 + band : min(hl2 + band, stop)
  if close > stop {
    trend = 1
    stop = hl2 - band
  }
}
turned = changed(trend)
plot(stop, "Stop", trend == 1 ? green : red)
mark(turned and trend == 1, "Buy", below, green)
mark(turned and trend == -1, "Sell", above, red)

The day's range so far, labelled at its high

state dayHigh = na
state dayLow = na
state tag = na
if changed(day) or isna(dayHigh) {
  dayHigh = high
  dayLow = low
} else {
  dayHigh = max(dayHigh, high)
  dayLow = min(dayLow, low)
}
plot(dayHigh, "Day high", green, 1, steps)
plot(dayLow, "Day low", red, 1, steps)
if islast {
  tag = label(bar, dayHigh, "Range " + str(dayHigh - dayLow, decimals), color = alpha(gray, 0.6), place = above, size = small)
}

From Pine Script, with an AI

An indicator written in TradingView's Pine Script v6 can be turned into Frost Script by an AI chat — Claude, ChatGPT, Gemini or another. The instructions below teach it the whole language and how each part of Pine Script maps onto it: its arrays, functions, lines, labels, boxes and tables included.

  1. Copy the instructions: the button below, or Pine Script → Frost: copy AI instructions in the Frost Script editor.
  2. Paste them into the AI chat, and then the Pine Script v6 source of the indicator.
  3. Paste the script it answers with into the editor. It is checked at once: if a line is wrong, give the AI the message and the line, and ask it to put it right.
  4. Before you rely on it, put it on a chart beside the original and compare the numbers on a few bars.
An AI that reads links can be given this one: tradoorterminal.com/frost-script-ai.txt
Read the instructions
Loading…
What Frost Script has no word for stays behind: other timeframes and symbols (request.security), strategies, alerts, the clock (timenow), polylines, matrices and maps. The AI is told to say what it left out, and to turn a strategy's entries into marks.

Mistakes and messages

A script is checked as it is typed. A mistake says its line and column and what is wrong, and the line's number turns red. Some you will meet:

MessageWhat to do
foo is not known hereA name not set anywhere, or spelt differently (capitals count).
ema(value, length)The function takes other arguments: here a value and a length.
a length is a number or a settingA length cannot change from bar to bar: use a number, a setting, or maths on them.
… call it outside if, for and whileA function over bars, or a plot, inside a block. Work the value out above the block, and use it inside.
close is built inA variable named as a bar value, a colour or a word of the language: pick another. A function's name is free: sum = 0 is fine.
… keeps it nowhere: name itA line that works out a value and keeps it nowhere.
two lines are called "A"Give each line its own title.
x holds a number: it cannot be set to a textA variable keeps to the kind it was first set to: give the text another name.
… is not a place in this list of 3A list read or set past its end: check its size() first.
f(…) calls itselfA function cannot call itself: write it as a loop.
this script takes too long to work outLoops that together ask too much: fewer, or shorter. See Limits.

A script that runs into a problem on the chart says so in the chart's legend, beside its name.

Limits

Every script ends, and quickly. One that asks for more than these stops with a message saying where.

LimitAt most
Length of a script40,000 characters, 12,000 words and signs
Brackets and blocks inside each other40 deep
Settings · a choice's options32 · 16
Variables, counting each function call's own1,000
Functions · lists · a list's values64 · 32 · 5,000
Lines, histograms and levels · fills · marks · backgrounds32 · 16 · 16 · 4
Shapes kept: lines · labels · boxes500 · 500 · 200
Table4 columns, 16 rows
A length (sma, ema, highest…)5,000
Looking back with x[n]5,000 bars
One loop10,000 rounds
All the work of one run over the chart40 million steps
Titles and names · mark text · a text in quotes · a text made40 · 12 · 200 · 1,000 characters

Safety

Frost Script is safe by what it is, not by what it forbids. A script is read and worked out by tradoor's own engine for it, written in Rust. It is never turned into JavaScript or any other code a browser runs.

A script can still be wrong. It cannot harm you, but a script can draw a line that misleads. Read a script before you trade on it, and remember that no indicator knows where price goes next.

Your scripts and your account

Public scripts and the Community

The indicator picker has three tabs: Built-in, tradoor's own; Community, the scripts their authors made public; and My scripts. One search runs through all three, and each tab says how many it matches.

Read a script before you trade on it. A Community script is someone else's work. It cannot reach your account or your browser, but it can draw a line that misleads.