Timeframes & Offsets
Cross-timeframe qualifiers, historical offsets, and the lookback ceiling.
Cross-Timeframe Qualification
Prefix any expression with timeframe:: to evaluate it against a timeframe other than the query's default timeframe pragma:
timeframe = h1
h4::rsi(14) > 50Here, rsi(14) is computed from h4 data even though the query's default timeframe is h1. A qualifier attaches to a single primary expression (a series reference, function call, or let reference) or to a parenthesized group as a whole:
d::(bb_upper(20, 2) - bb_lower(20, 2)) > 0let references can't be re-qualified
A let-bound name's timeframe is fixed at the point of declaration.
h4::myBinding is a parse error: qualify the timeframe inside the let's
own right-hand side instead.
Offset Indexing
Suffix any expression with [-N] to reach N bars back from the latest bar:
rsi(14)[-1] < 30 // one bar backAn expression with no bracket suffix is offset 0 (the latest bar). Like timeframe qualifiers, an offset attaches to a single primary expression or a parenthesized group as a whole, not to a bare, unparenthesized arithmetic expression:
close - sma(50)[-1]Here the [-1] binds only to sma(50), not to the subtraction as a whole. To offset the whole expression, either parenthesize it:
(close - sma(50))[-1] > 0or bind it to a let first and offset the reference:
let diff = close - sma(50)
diff[-1] > 0The 300-Bar Lookback Ceiling
Before a query runs, plan() computes the minimum bars of history (minLookback) every timeframe needs, and rejects the query outright if any timeframe's requirement exceeds 300 bars. This is a hard rejection at plan time, not a soft warning or silent truncation.
Roughly, per function family:
| Functions | Minimum lookback |
|---|---|
sma/wma/stdev/max/min/sum/avg/bb_* | length + offset |
rsi/rma/atr/change/roc/mom | length + 1 + offset |
highest/lowest | length + 1 + offset (the window excludes the current bar) |
Bare series (close, open, …) | 1 + offset |
macd_line(fast, slow, signal) | max(fast, slow) + offset |
macd_signal/macd_hist(fast, slow, signal) | max(fast, slow) + signal - 1 + offset |
A crossover/crossunder/cross call adds one extra bar beyond what each operand already requires, for the "one bar back" comparison the crossing check itself performs.
Mapping Calendar Phrasing to a Timeframe
"200-day moving average" or "52-week high" don't automatically mean "use d:: or w::": they mean "pick whichever timeframe keeps the bar count under 300 while staying natural."
A naive mapping can blow the ceiling
"52-week high" naively maps to d::highest(high, 365) (or ~252 trading days): that exceeds 300 bars and is rejected at plan time. The natural, correct mapping uses weekly bars instead:
close >= w::highest(high, 52)52 weekly bars is comfortably under the ceiling, and arguably a more natural rendering of "52-week" anyway.
"200-day moving average" maps to d::sma(200), regardless of the query's own default timeframe: get this wrong and the result is silently incorrect (computed on the wrong timeframe), not rejected, since sma(200) on an hourly timeframe is syntactically valid, just not "200 days."