Grammar

This is the whole grammar. Anything outside it is a parse error. History indexing with square brackets is valid only directly on a series name, so write (high + low) into a series first if you need its history.

EBNF
program          = separators, { statement, separators }, EOF ;
separators       = { NEWLINE | ";" } ;

statement        = variable-declaration
                 | assignment
                 | if-statement
                 | for-statement
                 | while-statement
                 | "break" | "continue"
                 | function-declaration
                 | return-statement
                 | call-expression ;

variable-declaration
                 = ("let" | "var"), identifier, [":", type], "=", expression ;
assignment       = identifier, (":=" | "+=" | "-=" | "*=" | "/="), expression ;
if-statement     = "if", expression, block,
                   [separators, "else", (block | if-statement)] ;
for-statement    = "for", identifier, "=", expression, "to", expression,
                   ["by", expression], block ;
while-statement  = "while", expression, block ;
function-declaration
                 = "fn", identifier, "(", [parameters], ")",
                   ["->", type], block ;
parameters       = parameter, {",", parameter} ;
parameter        = identifier, ":", type ;
return-statement = "return", [expression] ;
block            = "{", separators, {statement, separators}, "}" ;

expression       = conditional ;
conditional      = logical-or, ["?", expression, ":", expression] ;
logical-or       = logical-and, {"||", logical-and} ;
logical-and      = equality, {"&&", equality} ;
equality         = comparison, {("==" | "!="), comparison} ;
comparison       = additive, {("<" | "<=" | ">" | ">="), additive} ;
additive         = multiplicative, {("+" | "-"), multiplicative} ;
multiplicative   = unary, {("*" | "/" | "%"), unary} ;
unary            = ["+" | "-" | "!"], unary | postfix ;
postfix          = primary, ["[", expression, "]"] ;
primary          = number | string | "true" | "false"
                 | identifier | constant
                 | call-expression
                 | "(", expression, ")" ;
constant         = "math.pi" | "math.e" | "color.red" | "color.green" | ... ;
call-expression  = dotted-identifier, "(", [arguments], ")" ;
arguments        = expression, {",", expression} ;

type             = "float" | "int" | "bool" | "string" | "color" | "side" | "void" ;

Operator precedence

From tightest to loosest: unary + - !, then * / %, then + -, then < <= > >=, then == !=, then &&, then ||, and last the conditional ? :. All binary operators associate to the left. The conditional associates to the right, so a ? b : c ? d : e reads as a ? b : (c ? d : e).

  • Arithmetic operands must be numbers. The + operator never joins strings; use str.concat.
  • Division or remainder by zero returns nan rather than infinity.
  • && and || require booleans and short circuit. ! requires a boolean. An if condition must be a boolean too.
  • An ordered comparison against nan is false. Both == and != against nan are false, even when both sides are nan. Test with is_nan or replace with nz.
  • Equality is strict. Numbers, booleans and strings are never coerced.
  • condition ? a : b needs a bool condition and evaluates only the branch it takes, exactly like an if. Both branches should have one type; int and float mix freely.
  • x += e, x -= e, x *= e and x /= e are short for x := x + e and so on, on a var or a local.
  • A ta.* call inside one arm of ? : runs only on the bars that take that arm, exactly as inside an if branch. Compute it into a series first and pick between the results.
let tone: color = close >= open ? color.green : color.red
let average_volume: float = ta.sma(volume, 20)
let size_class: string = volume > average_volume * 2 ? "HEAVY" : volume > average_volume ? "ABOVE" : "QUIET"
plot.candle_color(true, tone, 0.6)
plot.label(size_class, "#E5E7EB")

Every layer of the market, Orderflow to optionflow, on one chart.

Institutional grade Orderflow data with backtesting and journaling built in. Join the waitlist for early access.

Get Access