Skip to content

Syntax

The whole language, in the order you meet it. Each section states what a thing means, gives the grammar for it exactly as the specification writes it, shows a query, and shows the answer the engine gave on the documentation fixture — real venue codes and symbols, invented numbers.

If you want the language by example instead, read the guide. If you want every name it has, read the reference. This page is the map between them.

A query is a condition, and then any number of clauses. The condition decides which instruments come back; the clauses decide what is read, when, in what order and what is returned alongside.

query = condition , { clause } ;
clause = "timeframe" , DURATION
| "freshness" , DURATION
| "as" , "of" , TIMESTAMP
| "order" , "by" , order_item , { "," , order_item } (* C1-06: several keys *)
| "select" , expression , { "," , expression } (* C1-05 *)
| "where" , condition ; (* C4-02: selection *)
order_item = expression , [ "asc" | "desc" ] ;
any(venues where funding > 0) where base = BTC order by max(venues, oi) desc select max(venues, oi)
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {
"max(venues, oi)": {
"value": 60800,
"unit": "base",
"from": [
{
"venue": "BYBIT-PERP",
"value": 60800,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
]
}
},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"funding": {
"value": 0.00002,
"unit": "fraction",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "stale"
},
"oi": {
"value": 60800,
"unit": "base",
"venue": "BYBIT-PERP",
"layer": "oi",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"funding": {
"value": 0.000013,
"unit": "fraction",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"oi": {
"value": 9400,
"unit": "base",
"venue": "HYPERLIQUID",
"layer": "oi",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"funding": {
"value": 0.00001,
"unit": "fraction",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"oi": {
"value": 5800,
"unit": "base",
"venue": "KRAKEN-FUTURES",
"layer": "oi",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"funding": {
"value": 0.000054,
"unit": "fraction",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"oi": {
"value": 41200,
"unit": "base",
"venue": "OKX-PERP",
"layer": "oi",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": null
}
}

Clause order is free when you write it and fixed when the platform prints it back: timeframe, freshness, as of, order by, select, where. Each clause may appear once; twice is DQL_DUPLICATE_CLAUSE. A query may also be a selection alone — where base = BTC with no condition is valid and means “every listing that matches”, which is what the data endpoints send.

Every query exists in two forms: the text you write and a JSON object with the same meaning. An editor that builds queries structurally sends the second and never has to quote anything. Every answer echoes both, canonically.

any(venues where funding > 0)
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"funding": {
"value": 0.00002,
"unit": "fraction",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "stale"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"funding": {
"value": 0.000013,
"unit": "fraction",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"funding": {
"value": 0.00001,
"unit": "fraction",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"funding": {
"value": 0.000054,
"unit": "fraction",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjdlZjMxMGZmYTMyOTI2ZDEifQ"
}
}

The query.string is the canonical text — what the platform understood, which may differ from what you sent in spacing and clause order. The query.json is the same thing as a tree. Send either; POST /v2/dql/parse converts between them without reading any market data.

A name belongs either to the instrument or to one venue’s listing of it. An instrument has several venues, so a venue-scoped name has to say which ones you mean.

quantifier = ( "any" | "all" | "count" ) , "(" , "venues" , "where" , condition , ")" ;
aggregate = ( "max" | "min" | "sum" ) , "(" , "venues" , [ "where" , condition ] ,
"," , expression , ")" ;
count(venues where funding > 0) >= 2
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"funding": {
"value": 0.00002,
"unit": "fraction",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "stale"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"funding": {
"value": 0.000013,
"unit": "fraction",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"funding": {
"value": 0.00001,
"unit": "fraction",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"funding": {
"value": 0.000054,
"unit": "fraction",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjhiMzkyMmIxYmFjMzVhYWMifQ"
}
}

Writing funding > 0 on its own is DQL_SCOPE, not a shortcut for “some venue”: funding is a fact about one venue’s listing, and the language will not pick one for you. Quantifiers do not nest — there is one level of venues, so an inner one would have nothing to range over.

Numbers may carry % or bps; durations are written 30s, 15m, 4h; timestamps are ISO-8601 and always UTC. A bare uppercase word is a code — a venue, an asset, a currency, an instrument — and is checked against the catalogue.

primary = NUMBER
| DURATION
| CODE
| STRING (* C4-02, `symbol` only *)
| status_lit
| method_lit (* C2-03, percentile only *)
| IDENT
| call
| quantifier
| aggregate
| "(" , condition , ")" ;
method_lit = "nearest" | "linear" ;
in_literal = CODE | status_lit ;
status_lit = "present" | "stale" | "missing" | "not_published" | "off" ;
any(venues where funding_8h > 1bps and age(funding) < 2m)
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"funding_8h": {
"value": 2e-05,
"unit": "fraction",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "stale"
},
"age(funding)": {
"value": 485000,
"unit": "ms",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "stale"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"funding_8h": {
"value": 0.000104,
"unit": "fraction",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"age(funding)": {
"value": 1000,
"unit": "ms",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"funding_8h": {
"value": 8e-05,
"unit": "fraction",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"age(funding)": {
"value": 1000,
"unit": "ms",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"funding_8h": {
"value": 5.4e-05,
"unit": "fraction",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"age(funding)": {
"value": 1000,
"unit": "ms",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImQzNTU5ZjgyZmEzNGU5MDUifQ"
}
}

1bps is 0.0001 and 0.5% is 0.005; the platform stores the canonical number and prints it back that way, which is why a query asking for 10bps comes back as 0.001. Keywords are lower case, codes are upper case, and a quoted string is only ever a venue’s own symbol.

Arithmetic, comparison and the three connectives. Precedence is the usual one: unary minus, then * /, then + -, then comparison, then not, then and, then or.

condition = or_expr ;
or_expr = and_expr , { "or" , and_expr } ;
and_expr = not_expr , { "and" , not_expr } ;
not_expr = "not" , not_expr
| comparison ;
comparison = expression , [ compare_op , expression
| "in" , "(" , in_literal , { "," , in_literal } , ")" ] ;
compare_op = "=" | "==" | "!=" | "<>" | "<" | "<=" | ">" | ">=" ;
expression = term , { ( "+" | "-" ) , term } ;
term = factor , { ( "*" | "/" ) , factor } ;
factor = "-" , factor
| primary ;
any(venues where (mark - index) / index > 5bps)
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"mark": {
"value": 86990,
"unit": "quote",
"venue": "BYBIT-PERP",
"layer": "mark",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"index": {
"value": 86950,
"unit": "quote",
"venue": "BYBIT-PERP",
"layer": "mark",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"mark": {
"value": 87010,
"unit": "quote",
"venue": "HYPERLIQUID",
"layer": "mark",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"index": {
"value": 86960,
"unit": "quote",
"venue": "HYPERLIQUID",
"layer": "mark",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"mark": {
"value": 87000,
"unit": "quote",
"venue": "KRAKEN-FUTURES",
"layer": "mark",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"index": {
"value": 86950,
"unit": "quote",
"venue": "KRAKEN-FUTURES",
"layer": "mark",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"mark": {
"value": 86995,
"unit": "quote",
"venue": "OKX-PERP",
"layer": "mark",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"index": {
"value": null,
"unit": "quote",
"venue": "OKX-PERP",
"layer": "mark",
"venue_ts": null,
"received_at": null,
"age_ms": null,
"status": "missing",
"reason": "not_retained"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6Ijk2ZWExZjk5MGMyMjc1OTUifQ"
}
}

Two differences from what you may expect. = is comparison, never assignment. And not binds looser than comparison, so not a > b means not (a > b). Comparison is non-associative: a < b < c is a syntax error rather than a surprise.

any, all and count ask a question about the venues. max, min and sum compute one number from them.

quantifier = ( "any" | "all" | "count" ) , "(" , "venues" , "where" , condition , ")" ;
aggregate = ( "max" | "min" | "sum" ) , "(" , "venues" , [ "where" , condition ] ,
"," , expression , ")" ;
max(venues where quote = USDT, oi) > 1000
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {
"max(venues where quote = USDT, oi)": {
"value": 60800,
"unit": "base",
"from": [
{
"venue": "BYBIT-PERP",
"value": 60800,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
]
}
},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"quote": {
"value": "USDT",
"venue": "BYBIT-PERP",
"layer": "reference",
"venue_ts": null,
"received_at": "2026-09-23T00:00:00Z",
"age_ms": 43205000,
"status": "present"
},
"oi": {
"value": 60800,
"unit": "base",
"venue": "BYBIT-PERP",
"layer": "oi",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"quote": {
"value": "USDC",
"venue": "HYPERLIQUID",
"layer": "reference",
"venue_ts": null,
"received_at": "2026-09-23T00:00:00Z",
"age_ms": 43205000,
"status": "present"
},
"oi": {
"value": 9400,
"unit": "base",
"venue": "HYPERLIQUID",
"layer": "oi",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"quote": {
"value": "USD",
"venue": "KRAKEN-FUTURES",
"layer": "reference",
"venue_ts": null,
"received_at": "2026-09-23T00:00:00Z",
"age_ms": 43205000,
"status": "present"
},
"oi": {
"value": 5800,
"unit": "base",
"venue": "KRAKEN-FUTURES",
"layer": "oi",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"quote": {
"value": "USDT",
"venue": "OKX-PERP",
"layer": "reference",
"venue_ts": null,
"received_at": "2026-09-23T00:00:00Z",
"age_ms": 43205000,
"status": "present"
},
"oi": {
"value": 41200,
"unit": "base",
"venue": "OKX-PERP",
"layer": "oi",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImJiMjc1OWQ1YmY1N2M5YTQifQ"
}
}

sum refuses a field that is not additive: adding prices across venues is a category error, not a small inaccuracy. An aggregate over an empty set of venues is null with no_value; all over an empty set is true and any is false, which is the usual convention and is stated so you need not guess.

Candles and sampled snapshots, read at a period. A series function needs a timeframe — on the query or as its own last argument.

call = IDENT , "(" , [ condition , { "," , condition } ] , ")" ;
any(venues where ema(close, 20) > ema(close, 50)) timeframe 1h
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"timeframe": "1h",
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "unknown",
"values": {},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"ema(close, 20)": {
"value": null,
"unit": "quote",
"venue": "BYBIT-PERP",
"layer": "candles",
"timeframe": "1h",
"bars": 80,
"candle_end": null,
"venue_ts": null,
"received_at": null,
"age_ms": null,
"status": "missing",
"reason": "no_value"
},
"ema(close, 50)": {
"value": null,
"unit": "quote",
"venue": "BYBIT-PERP",
"layer": "candles",
"timeframe": "1h",
"bars": 200,
"candle_end": null,
"venue_ts": null,
"received_at": null,
"age_ms": null,
"status": "missing",
"reason": "no_value"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"ema(close, 20)": {
"value": null,
"unit": "quote",
"venue": "HYPERLIQUID",
"layer": "candles",
"timeframe": "1h",
"bars": 80,
"candle_end": null,
"venue_ts": null,
"received_at": null,
"age_ms": null,
"status": "missing",
"reason": "no_value"
},
"ema(close, 50)": {
"value": null,
"unit": "quote",
"venue": "HYPERLIQUID",
"layer": "candles",
"timeframe": "1h",
"bars": 200,
"candle_end": null,
"venue_ts": null,
"received_at": null,
"age_ms": null,
"status": "missing",
"reason": "no_value"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"ema(close, 20)": {
"value": null,
"unit": "quote",
"venue": "KRAKEN-FUTURES",
"layer": "candles",
"timeframe": "1h",
"bars": 80,
"candle_end": null,
"venue_ts": null,
"received_at": null,
"age_ms": null,
"status": "missing",
"reason": "no_value"
},
"ema(close, 50)": {
"value": null,
"unit": "quote",
"venue": "KRAKEN-FUTURES",
"layer": "candles",
"timeframe": "1h",
"bars": 200,
"candle_end": null,
"venue_ts": null,
"received_at": null,
"age_ms": null,
"status": "missing",
"reason": "no_value"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"ema(close, 20)": {
"value": null,
"unit": "quote",
"venue": "OKX-PERP",
"layer": "candles",
"timeframe": "1h",
"bars": 80,
"candle_end": null,
"venue_ts": null,
"received_at": null,
"age_ms": null,
"status": "missing",
"reason": "no_value"
},
"ema(close, 50)": {
"value": null,
"unit": "quote",
"venue": "OKX-PERP",
"layer": "candles",
"timeframe": "1h",
"bars": 200,
"candle_end": null,
"venue_ts": null,
"received_at": null,
"age_ms": null,
"status": "missing",
"reason": "no_value"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImRkOWI3MzhhMWQzNzY1OTQifQ"
}
}

S[0] is the last completed period, never the forming one: the platform stores closed minutes only, so there is no half-finished candle to read. A window that reaches further back than the data goes is null with insufficient_history, and a hole inside the window is null with gap — neither is silently filled.

age and status are how a query asks about the data rather than about the market.

all(venues where status(funding) = present and age(funding) < 5m)
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "SOL-PERP",
"result": "true",
"values": {},
"venues": [
{
"venue": "HYPERLIQUID",
"symbol": "SOL",
"quote": "USDC",
"values": {
"status(funding)": {
"value": "present",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"age(funding)": {
"value": 1000,
"unit": "ms",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": null
}
}

The five statuses are present, stale, missing, not_published and off. The last two are kept apart on purpose: not_published is a fact about the venue, off is a decision the platform made and can change.

How much rests within a price band of the mid, per side, in quantity or in quote value.

any(venues where depth_bid_value(10bps) > 100000)
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"depth_bid_value(0.001)": {
"value": 68721.705,
"unit": "quote",
"venue": "BYBIT-PERP",
"layer": "book",
"band": "10bps",
"reference": "mid",
"levels": 4,
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"depth_bid_value(0.001)": {
"value": 295830.6,
"unit": "quote",
"venue": "HYPERLIQUID",
"layer": "book",
"band": "10bps",
"reference": "mid",
"levels": 4,
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"depth_bid_value(0.001)": {
"value": 104398.8,
"unit": "quote",
"venue": "KRAKEN-FUTURES",
"layer": "book",
"band": "10bps",
"reference": "mid",
"levels": 4,
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"depth_bid_value(0.001)": {
"value": 208787.76,
"unit": "quote",
"venue": "OKX-PERP",
"layer": "book",
"band": "10bps",
"reference": "mid",
"levels": 4,
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjRhMzA2ZWYwNTYwNzU0NWMifQ"
}
}

The bands are a fixed set — 0.001, 0.0025, 0.005, 0.01 as fractions of the mid. A side the received book did not reach is null with band_truncated, never a partial sum presented as a whole one.

A comparison involving a value that is missing or stale is neither true nor false. It is unknown, and unknown propagates.

all(venues where funding > 0)
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "unknown",
"values": {},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"funding": {
"value": 0.00002,
"unit": "fraction",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "stale"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"funding": {
"value": 0.000013,
"unit": "fraction",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"funding": {
"value": 0.00001,
"unit": "fraction",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"funding": {
"value": 0.000054,
"unit": "fraction",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImI2ZTllZTg0MjMxMDhjNTMifQ"
}
}

This is the part most worth understanding. all(...) over venues where one reading is stale answers unknown, not false — the platform does not know. Ask for include_unknown and those instruments come back with result: unknown instead of being dropped, which is the difference between a screen that reports its coverage and one that quietly narrows it.

as of asks the same question about a past instant. What was visible then is what is used.

count(venues where funding > 0) >= 2 as of 2026-09-23T08:00:00Z
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": "2026-09-23T08:00:00Z",
"settled": true,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [],
"page": {
"limit": 1,
"returned": 0,
"next_cursor": null
}
}

Visibility is by receipt time, not by the venue’s timestamp: a reading that arrived late was not visible at the instant it describes, and a replay that used it would be a backtest of information you did not have. An answer says whether its instant is settled — whether late arrivals can still change it.

Each layer has a bound; a reading older than its bound is stale. A query may set its own.

any(venues where funding > 0) freshness 10m
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "10m",
"mark": "10m",
"oi": "10m",
"book": "10m",
"stats": "10m",
"funding": "10m"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"funding": {
"value": 0.00002,
"unit": "fraction",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "present"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"funding": {
"value": 0.000013,
"unit": "fraction",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"funding": {
"value": 0.00001,
"unit": "fraction",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"funding": {
"value": 0.000054,
"unit": "fraction",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjdlYjNlM2NkYTgxZTdiOTYifQ"
}
}

The defaults are ticker 30s, mark 30s, oi 30s, book 30s, stats 120s, funding 300s. They are defaults, not opinions about your strategy: a market maker and a weekly rebalancer disagree about what fresh means, and the platform states the age rather than settling the argument.

where chooses which listings the query runs over, before the condition is evaluated.

clause = "timeframe" , DURATION
| "freshness" , DURATION
| "as" , "of" , TIMESTAMP
| "order" , "by" , order_item , { "," , order_item } (* C1-06: several keys *)
| "select" , expression , { "," , expression } (* C1-05 *)
| "where" , condition ; (* C4-02: selection *)
venues_listed >= 1 where venue = KRAKEN-FUTURES and base = BTC
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {
"venues_listed": {
"value": 1,
"from": "reference",
"as_of": "2026-09-23T12:00:05Z"
}
},
"venues": [
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": null
}
}

where is evaluated at listing scope — venue, symbol, quote, instrument, base — and never at instrument scope. A listing that maps to no instrument is still selected and comes back with instrument: null; instrument = X never matches one.

Every value is an object: the number, and everything needed to judge it.

any(venues where funding > 0) select funding, status(funding), age(funding)
{
"dql": "1",
"evaluated_at": "2026-09-23T12:00:05Z",
"as_of": null,
"settled": false,
"freshness": {
"ticker": "30s",
"mark": "30s",
"oi": "30s",
"book": "30s",
"stats": "120s",
"funding": "300s"
},
"instruments": [
{
"instrument": "BTC-PERP",
"result": "true",
"values": {},
"venues": [
{
"venue": "BYBIT-PERP",
"symbol": "BTCUSDT",
"quote": "USDT",
"values": {
"funding": {
"value": 0.00002,
"unit": "fraction",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "stale"
},
"status(funding)": {
"value": "stale",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "stale"
},
"age(funding)": {
"value": 485000,
"unit": "ms",
"venue": "BYBIT-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T11:52:00Z",
"age_ms": 485000,
"status": "stale"
}
}
},
{
"venue": "HYPERLIQUID",
"symbol": "BTC",
"quote": "USDC",
"values": {
"funding": {
"value": 0.000013,
"unit": "fraction",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"status(funding)": {
"value": "present",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"age(funding)": {
"value": 1000,
"unit": "ms",
"venue": "HYPERLIQUID",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "KRAKEN-FUTURES",
"symbol": "PF_XBTUSD",
"quote": "USD",
"values": {
"funding": {
"value": 0.00001,
"unit": "fraction",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"status(funding)": {
"value": "present",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"age(funding)": {
"value": 1000,
"unit": "ms",
"venue": "KRAKEN-FUTURES",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
},
{
"venue": "OKX-PERP",
"symbol": "BTC-USDT-SWAP",
"quote": "USDT",
"values": {
"funding": {
"value": 0.000054,
"unit": "fraction",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"status(funding)": {
"value": "present",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
},
"age(funding)": {
"value": 1000,
"unit": "ms",
"venue": "OKX-PERP",
"layer": "funding",
"venue_ts": null,
"received_at": "2026-09-23T12:00:04Z",
"age_ms": 1000,
"status": "present"
}
}
}
]
}
],
"page": {
"limit": 1,
"returned": 1,
"next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImY5MGMxNDk4MWVkMTljMmMifQ"
}
}

A value carries the venue that published it, the venue’s own timestamp, when the platform received it, how old that made it, its unit and its status — and a reason whenever it is null. An aggregate carries the readings it stands on instead of one venue; a derived figure carries the values it was computed from.

Every ceiling is served as data by GET /v2/dql/catalogue and explained in Limits. The ones that shape how a query is written:

limit value
longest query text 8192 bytes
quantifiers and aggregates in one query 16
series calls 32
different periods 3
longest window 500 periods
values in one select 16
keys in one order by 4

POST /v2/dql/parse returns a query’s cost before you run it.

Stated because a language’s edges are as much a part of it as its middle, and because each of these was decided rather than forgotten.

  • Boolean series. crossover returns a truth about the last period, not a series of truths you can feed to another function. Chaining them needs a way to say which period you mean, and no wording for that has survived review.
  • Cross-instrument references. A query about BTC cannot read ETH. The scope rules have two levels, instrument and venue; a third would make every condition ambiguous about which instrument it is talking about.
  • Sub-minute sampling. One minute is the base period the platform stores. A query asking for less is asking about jitter in the collection, not about the market.
  • Mark-price sampled series. Snapshot layers are sampled; the mark layer is not sampled into a series of its own, because mark_close candles already exist and two answers to one question is one too many.
  • Spot. The platform collects perpetual futures. Spot is not a missing feature; it is a different product.

Each of these is a decision with a reason, and each can be revisited. None of them is a bug.