Syntax
Literals, operators, and grouping.
Query Structure
A query has a header (KEY = value pragmas, in any order, optionally interleaved with let statements) followed by a core-logic body: a single boolean expression that decides whether an instrument matches.
market = "CRYPTO"
timeframe = h1
columns = [close, rsi(14)]
sort = rsi(14) asc
limit = 20
rsi(14) < 30Supported pragma keys
Only market, timeframe, columns, sort, and limit are recognized. Any
other key (e.g. GROUPBY) is a parse error.
market and timeframe
market is a quoted string, restricted to one of:
"CRYPTO" | "FOREX" | "INDICES" | "COMMODITIES" | "METALS"timeframe is a bare identifier, restricted to one of:
m15 | m30 | h1 | h2 | h4 | d | wBoth are closed enums: an unrecognized value (market = "STOCKS", timeframe = h3) is rejected at parse time.
Series References
Five bare identifiers resolve to a series on the expression's timeframe: close, open, high, low, volume. See OHLCV Series for what each one represents, bar ordering, and how they differ by market.
close > openComparators and Logical Operators
The core-logic body supports the comparators <, >, <=, >=, ==, !=, the logical operators and, or, not, and parentheses for grouping boolean sub-expressions.
(rsi(14) < 30 or not (close > 100)) and close >= 50Arithmetic Operators
+, -, *, / combine any two value expressions: series references, function calls, let references, literals, or other arithmetic expressions. * and / bind tighter than + and -; operators at the same precedence level associate left-to-right.
close - sma(50) > 0volume > avg(volume, 20) * 2Same-precedence chains associate left-to-right, not right-to-left:
sma(50) - sma(20) - sma(10) > 0parses as (sma(50) - sma(20)) - sma(10), not sma(50) - (sma(20) - sma(10)).
Arithmetic is valid anywhere a value expression already is: comparator operands, let right-hand sides, columns entries, and sort.
Unary minus only negates literals
-10 is a negative literal. -ema(50) is a parse error: unary minus does
not negate an arbitrary expression. To negate a computed value, subtract it
from a literal: 0 - ema(50).
Parenthesized Grouping
Any value expression can be wrapped in parentheses to reorder precedence:
(bb_upper(20, 2) - bb_lower(20, 2)) / bb_mid(20, 2) > 0.04A parenthesized group is a compound unit: as a whole, it can carry a <timeframe>:: qualifier or a [-N] offset, which an unparenthesized arithmetic expression cannot (see Timeframes & Offsets):
d::(bb_upper(20, 2) - bb_lower(20, 2)) > 0(close - sma(50))[-1] > 0A single-atom group ((rsi(14))) is legal and semantically a no-op. Grouping nests to arbitrary depth.
Two kinds of parentheses
Value-expression grouping (this section) is distinct from the pre-existing boolean grouping used for (condition and condition). The parser disambiguates the two automatically: a genuine boolean sub-expression like (rsi(14) < 30 and volume > 0) still parses as boolean grouping, while something like (bb_upper(20, 2) - bb_lower(20, 2)) / bb_mid(20, 2) > 0.04 parses as a value-expression group, since its parenthesized content isn't itself a complete boolean expression. You don't need to write anything differently to get the right one.
Offset Indexing
Suffix any expression with [-N] to reach N bars back from the latest bar. An expression with no suffix defaults to offset 0.
rsi(14)[-1] < 30[1] (no leading minus) is a parse error, not "1 bar ago": the minus sign is required.
Cross-Timeframe Qualification
Prefix any expression with timeframe:: to evaluate it against a different timeframe than the query's default:
h4::rsi(14) > 50See Timeframes & Offsets for the full rules, including how offsets and timeframe qualifiers compose with arithmetic and parenthesized groups.
crossover, crossunder, cross
Three boolean primitives detect a value crossing another:
crossover(a, b) // a crossed from at-or-below b to strictly above
crossunder(a, b) // a crossed from at-or-above b to strictly below
cross(a, b) // either directiona and b are each any value expression (a series, a function call, or either qualified with <timeframe>::/[-N]). Cross primitives compose with and/or/not and parentheses, and each requires exactly two arguments.
Cross primitives are not value expressions
crossover/crossunder/cross can only appear where a boolean expression is
valid: never inside columns, sort, or as a comparator operand, and never
offset-indexed directly (crossover(a,b)[-1] is invalid). To check whether a
crossover happened recently, bind it to a let first: see
Cookbook for the full recipe.
columns and sort
columns accepts an array of value expressions, or boolean-typed let references (never a bare comparison or logical expression):
columns = [close, rsi(14), h4::rsi(14)]sort accepts a single value expression (never boolean) followed by a required asc or desc:
sort = rsi(14) ascsort is independent of columns: an expression doesn't need to appear in both.
limit
A single positive integer, capping the number of results kept after running the query:
limit = 20