Syntax and layout
How a script is laid out. Blocks by indentation, comments, long lines, names in any language, and the words that have a meaning of their own.
A script is a text file. Each statement is on its own line, and the indentation of a line says which block it belongs to. This page covers the shape of the text; what the statements mean is in the pages that follow.
One statement a line#
A statement ends where its line ends. There are no semicolons and no braces.
// The first line of code is the header; everything after it is the body.
indicator "Layout"
edition = 1
display = price
let average = tech.sma(close, 20)
let above = close > average
mut tint = color.gray
if above
tint = color.green
else
tint = color.red
plot(close, name = "Close", color = tint)A blank line is only for you. In the canonical layout a run of blank lines is cut to one, and none is left at the start of a block or of the file.
A second statement on the same line is refused:
indicator "Two on a line"
edition = 1
let a = 1; let b = 2
plot(a + b)Blocks are indented#
The lines under an if, a for, a while, a match or a function belong to it when they are indented one level deeper. A level is any width of spaces you like, as long as the whole file is consistent; the formatter uses four. A tab in the indentation is an error (E1002), so set your editor to insert spaces.
A line that goes back to a width no open block has is an error:
indicator "Uneven blocks"
edition = 1
if close > open
plot(1)
plot(2)The language has one canonical layout: four spaces for a level, spaces around operators, one statement a line, and a long call broken onto several lines with one argument on each. The examples in this documentation are all in that layout.
Comments#
// starts a comment that runs to the end of the line. A comment is never removed or moved when a script is rewritten in the canonical layout.
/// before an input is the setting's tooltip, the text the settings panel shows when you point at it:
indicator "Documented input"
edition = 1
/// How many bars the average looks at
input length: int = 20, name = "Length", min = 1
plot(tech.sma(close, length))Long lines#
A line carries on to the next one when it cannot be finished yet:
- a bracket
(,[is still open, which is the usual way to lay out a call with many arguments; - the line ends with an operator, a comma,
=, a., or the wordand,orornot; - the next line starts with
and,or,*,/,%, a comparison or??and is indented deeper.
indicator "Long conditions"
edition = 1
display = price
let average = tech.sma(close, 20)
let usual_volume = tech.sma(volume, 20)
let usual_range = tech.atr(14)
let strong = close > open
and close > average
and volume > usual_volume
and high - low > usual_range * 1.5
plot(if strong then close else na, name = "Strong bars")A line that starts with + or - is a new statement, not a continuation. Put the operator at the end of the line before it.
Names#
A name starts with a letter or _ and goes on with letters, digits, _, and the zero-width non-joiner (the invisible character Persian uses inside words). Any letter of any alphabet counts, so a name can be written in your own language:
indicator "Names in Persian"
edition = 1
display = price
input طول: int = 20, name = "Length", min = 1
let میانگین = tech.sma(close, طول)
plot(میانگین, name = "Average")A name is case sensitive. Close and close are different names, and only close is the price.
Persian and Arabic digits, the Arabic comma and curly quotes look like their ASCII twins but are not. They are never read silently: each is an error that names the ASCII character to write instead, and carries that replacement as a fix.
indicator "Persian digit"
edition = 1
input length: int = ۲۰, name = "Length"
plot(tech.sma(close, length))Words with a meaning#
Some words cannot be used as names:
let input fn type enum import export module if else for while break continue match return and or not true false na
Others have a meaning only in one place, and are ordinary names everywhere else: mut state uses session group then to until by as live in show_if check on. You can have a variable called session; but where a session declaration is expected, the word means the declaration.
The name of a built-in series such as close can be used for your own variable. Inside the script close then means yours, and the price is out of reach there, so the checker warns you (W-SHADOW-BUILTIN). A function name such as plot can be reused for a variable without losing the function: plot(close) still draws, but the warning is there because the reader cannot tell them apart.
One line, one thought#
If a line is too long to read, give a part of it a name with let instead of stretching it. Names cost nothing at run time, and they are the only documentation a script is sure to have.
See also: Values and types, Variables, Common mistakes.