Values and types
The kinds of value a script works with. Numbers, text, true and false, colours, na, series and history, tuples, arrays, maps, records and enums.
Every expression has a value. This page lists the kinds of value and how to write them. Edition 1 does not make you declare types: the engine works out what a value is. You may write a type after a name when it helps the reader. In edition 1 a written type is documentation: the engine does not check it, so a type that does not match the value is not an error.
Numbers, text, true and false#
indicator "Plain values"
edition = 1
let count = 1_000
let ratio = 0.25
let big = 1.5e3
let name = "Gold"
let other = "single quotes work too"
let flag = close > open
plot(count + ratio + big, name = "Number")
plot(if flag then 1 else 0, name = "Flag")- A number is one kind.
1,1.5,.5,1_000(an underscore groups digits) and1.5e3are all numbers, and7 / 2is3.5. There is no whole-number division; usemath.floor(7 / 2)for 3. - Text is written in double or single quotes. A text can hold the other kind of quote. Triple quotes hold several lines. Text and number formatting has the escapes and the formatted text
f"...". trueandfalseare the two truth values. A comparison gives one.
Colours#
A colour is #rrggbb or #rrggbbaa (the last pair is opacity: ff solid and 00 invisible), a named colour such as color.red, or one made by a function:
indicator "Colours"
edition = 1
display = price
plot(close, name = "Named", color = color.orange)
plot(open, name = "Hex", color = #2962ff)
plot(high, name = "With transparency", color = #ff980080)
plot(low, name = "Made", color = color.fade(color.purple, 40))
plot(hl2, name = "From parts", color = color.rgb(0, 150, 136))color.fade(color, percent) takes a transparency from 0 (solid) to 100 (invisible). color.rgb(r, g, b) takes three numbers from 0 to 255.
Not a number: na#
na means "no value". It is a legal value, not an error: an average has it on its first bars, and close[5] has it on the first five bars. Arithmetic with na gives na. A comparison with na is never true. na, errors and arithmetic is about it.
Series: a value on every bar#
The script runs once for every bar, so every name is really a series: one value per bar. You read the value on the current bar by writing the name, and the value n bars ago by writing name[n]. This is how you compare a bar with the one before it.
indicator "Change from the bar before"
edition = 1
let change = close - close[1]
let two_back = close[2]
let rising = change > 0 and change[1] > 0
plot(change, name = "Change", style = histogram)
plot(if rising then 1 else 0, name = "Two rising bars")bar.index is the number of the bar, counting from 0. x[n] is only for history. n is a count of bars back; it may be an input or any number. On the first n bars there is no such bar and the result is na. The brackets never mean "the n-th element of a list": for a list use .at(n).
indicator "Not a list element"
edition = 1
let levels = [close, open, high]
plot(levels[1])Tuples#
A function can return several values at once as a tuple, and you take them apart with a pattern. _ throws a position away.
indicator "Band"
edition = 1
display = price
fn band(length: int): (float, float)
let middle = tech.sma(close, length)
let spread = tech.stdev(close, length) * 2
return (middle + spread, middle - spread)
let (upper, lower) = band(20)
let (_, floor_only) = band(50)
plot(upper, name = "Upper", color = color.red)
plot(lower, name = "Lower", color = color.green)
plot(floor_only, name = "Lower, 50 bars", color = color.gray)Arrays and maps#
An array is an ordered list, a map holds values by key. Both are created empty or from a literal, and are read and changed with methods.
indicator "Last closes"
edition = 1
state closes: array<float> = []
closes.push(close)
if closes.size() > 5
closes.shift()
let items = [high, low, close]
plot(closes.avg(), name = "Average of the last 5 closes")
plot(items.at(0) - items.at(1), name = "Range")[a, b, c] is an array of the three values; [0.0; 4] is four copies of 0.0. Useful methods are .size(), .at(i), .set(i, v), .push(v), .shift() (drops the oldest), .first(), .last(), .avg(), .sum(), .min() and .max(). Indexes count from 0. Choices and loops shows how to walk an array.
indicator "Streak counter"
edition = 1
state seen: map<int, int> = map<int, int>()
state run: int = 0
if close > close[1]
run += 1
else
if run > 0
seen.set(run, (seen.at(run) ?? 0) + 1)
run = 0
plot(run, name = "Current streak", style = histogram)
plot(seen.size(), name = "Different streak lengths seen")A map's methods are .set(key, value), .at(key) (na when the key is missing; an array's .at(i) outside the array stops the script instead), .contains(key), .keys(), .size() and .remove(key). An array or a map is limited in size; see Limits and budgets.
Records and enums#
A type groups named fields. Build one by naming its fields; a field with = has a default.
indicator "A record"
edition = 1
type Level
price: float
strength: int = 1
let level_ = Level(price = close, strength = 3)
plot(level_.price * level_.strength, name = "Weighted price")An enum is a short list of names. Use it with match to cover every case:
indicator "An enum"
edition = 1
enum Direction
up
down
let direction = if close > open then Direction.up else Direction.down
let sign = match direction
Direction.up => 1
Direction.down => -1
plot(sign, name = "Sign", style = histogram)You may attach a text to a member (fast = "Fast") and use the enum as the type of an input, to give the settings panel a dropdown. See Inputs.
See also: Variables, Functions, types and enums, na, errors and arithmetic.