{
  "openapi": "3.1.1",
  "info": {
    "title": "DEBYKO API",
    "description": "Crypto derivatives data from every venue that quotes an instrument, with the evidence attached: each\nvalue carries the venue that published it, the time DEBYKO received it and its age.\n\n## What this API will not do to your data\n\n- **A missing value is never a zero.** A venue that does not publish a field is absent from the\n  answer, and the answer says which of the five it is: the value is there and fresh, there and stale,\n  the layer is collected but nothing has arrived, the venue publishes no such field, or nobody is\n  collecting it for that listing. Nothing is filled in.\n- **Venues are never averaged.** There is no “the price of BTC” here. There is what Bybit published,\n  what Kraken published, and the age of each.\n- **Values come back as the venue published them.** Prices are not rounded, rescaled or re-serialised\n  on the way through; a derived figure (a spread, a rate) says so and carries its own definition.\n- **A gap stays a gap.** History is stored with its holes intact, and an answer about a period nobody\n  quoted is empty rather than interpolated.\n\n## What this reference covers\n\n`/v2`, which is the platform: selection in DQL, point-in-time replay, per-second history, candles in\nany of the stored periods, books, screening and a live stream.\n\nMost of it needs a key. The endpoints that describe the platform rather than measure a market —\ncoverage, the catalogue and the parser — do not, because you should be able to see what exists and\nwhat a query may ask before you decide to pay for the answers.\n\nThere is also a `/v1` surface, which is what debyko.com and Studio are drawn with. It still answers\nand nothing about it is changing, but it is not documented here: it is a display surface, not a thing\nto build on, and meeting eleven of its endpoints before reaching DQL would send you into the wrong\nhalf of the platform.\n\n## Getting started\n\n```bash\n# what is collected, no key needed\ncurl \"https://api.debyko.com/v2/venues\"\ncurl \"https://api.debyko.com/v2/dql/catalogue\"\n\n# a measurement, with a key\ncurl -H \"Authorization: Bearer $DEBYKO_KEY\" \\\n  -H \"content-type: application/json\" \\\n  -d '{\"where\":\"base = BTC\",\"layers\":[\"mark\",\"funding\",\"book\"]}' \\\n  \"https://api.debyko.com/v2/snapshots\"\n```\n\nA key is issued at [studio.debyko.com/account](https://studio.debyko.com/account); the Free plan needs\nno card. Send it as `Authorization: Bearer <key>` — never in a URL, where it would be written into\nlogs and browser history. A key sent as a query parameter is refused with `KEY_IN_URL`.\n\n\n# Keys and plans\n\nEvery `/v2` endpoint that returns a measurement needs a key:\n\n```\nAuthorization: Bearer dbk_…\n```\n\nA key is issued at [studio.debyko.com/account](https://studio.debyko.com/account). The Free plan is\nissued without a card; paid plans start with a seven-day trial. One key covers Studio, the API and\nAgent — whatever a plan includes in Studio, it includes here.\n\n**Never in a URL.** A key in a query string is written into server logs, proxy logs and browser\nhistory. A request that carries one is refused with `KEY_IN_URL` and the key should be replaced from\nyour account.\n\n## What a plan changes\n\nA plan narrows what a key sees, and the answer says so rather than quietly shrinking:\n\n- **venues and instruments**: a plan that includes two venues sees two venues in the registry it is\n  answered from, and a `where` that names another matches nothing;\n- **history**: asking further back than a plan reaches is refused with `PLAN_LIMIT`, naming the date\n  the plan reaches and what it would take to go further — never a shortened answer that looks whole;\n- **rate**: requests per second and per day, and the number of live streams, are counted per key.\n  Exceeding one is a `429` with `Retry-After` and the name of the limit that stopped you.\n\nUsage is counted per key, per hour and per endpoint class, and is visible in your account. No\nper-request log of what you asked is kept.\n\n\n# Selecting with DQL\n\nDQL is how a request says **what it is about** — one language for selection across every endpoint,\ninstead of a different set of query parameters per resource.\n\n```\nwhere: base = BTC and venue in (BYBIT-PERP, KRAKEN-FUTURES)\n```\n\nThe same `where` selects for a snapshot, for history, for candles, for books and for the stream. What\nyou may name in it — the fields, the operators, the layers, the timeframes and the limits — is not\nwritten into this page: it is published live at `GET /v2/dql/catalogue`, so it can never disagree with\nwhat the platform actually holds.\n\nBefore sending a query, `POST /v2/dql/parse` will check it and answer with the position of the first\nproblem and what was expected there. It is free and needs no key, because a parser is a tool, not a\nmeasurement.\n\nAn instrument is named by its market code (`BTC-PERP`), a venue by its published code\n(`BYBIT-PERP`) — codes are permanent once published, so a saved query keeps working.\n\n\n# The language\n\nThe whole language, in the order you meet it. Each section states what a thing means, gives the grammar\nfor it exactly as the specification writes it, shows a query, and shows **the answer the engine gave** on\nthe documentation fixture — real venue codes and symbols, invented numbers.\n\nIf you want the language by example instead, read [the guide](#the-guide). If you want every name it has,\nread [the reference](#fields). This page is the map between them.\n\n## 1. The shape of a query\n\nA 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.\n\n```ebnf\nquery        = condition , { clause } ;\n\nclause       = \"timeframe\" , DURATION\n             | \"freshness\" , DURATION\n             | \"as\" , \"of\" , TIMESTAMP\n             | \"order\" , \"by\" , order_item , { \",\" , order_item }        (* C1-06: several keys *)\n             | \"select\" , expression , { \",\" , expression }              (* C1-05 *)\n             | \"where\" , condition ;                                     (* C4-02: selection *)\n\norder_item   = expression , [ \"asc\" | \"desc\" ] ;\n\n```\n\n```dql\nany(venues where funding > 0) where base = BTC order by max(venues, oi) desc select max(venues, oi)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {\n        \"max(venues, oi)\": {\n          \"value\": 60800,\n          \"unit\": \"base\",\n          \"from\": [\n            {\n              \"venue\": \"BYBIT-PERP\",\n              \"value\": 60800,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00002,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            },\n            \"oi\": {\n              \"value\": 60800,\n              \"unit\": \"base\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000013,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"oi\": {\n              \"value\": 9400,\n              \"unit\": \"base\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00001,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"oi\": {\n              \"value\": 5800,\n              \"unit\": \"base\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000054,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"oi\": {\n              \"value\": 41200,\n              \"unit\": \"base\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\nClause 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.\n\n## 2. Text and machine form\n\nEvery 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.\n\n```dql\nany(venues where funding > 0)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00002,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000013,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00001,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000054,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjdlZjMxMGZmYTMyOTI2ZDEifQ\"\n  }\n}\n```\n\nThe `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.\n\n## 3. Scopes\n\nA 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.\n\n```ebnf\nquantifier   = ( \"any\" | \"all\" | \"count\" ) , \"(\" , \"venues\" , \"where\" , condition , \")\" ;\naggregate    = ( \"max\" | \"min\" | \"sum\" ) , \"(\" , \"venues\" , [ \"where\" , condition ] ,\n               \",\" , expression , \")\" ;\n\n```\n\n```dql\ncount(venues where funding > 0) >= 2\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00002,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000013,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00001,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000054,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjhiMzkyMmIxYmFjMzVhYWMifQ\"\n  }\n}\n```\n\nWriting `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.\n\n## 4. Literals and units\n\nNumbers 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.\n\n```ebnf\nprimary      = NUMBER\n             | DURATION\n             | CODE\n             | STRING                                                    (* C4-02, `symbol` only *)\n             | status_lit\n             | method_lit                                                (* C2-03, percentile only *)\n             | IDENT\n             | call\n             | quantifier\n             | aggregate\n             | \"(\" , condition , \")\" ;\n\nmethod_lit   = \"nearest\" | \"linear\" ;\n\nin_literal   = CODE | status_lit ;\nstatus_lit   = \"present\" | \"stale\" | \"missing\" | \"not_published\" | \"off\" ;\n```\n\n```dql\nany(venues where funding_8h > 1bps and age(funding) < 2m)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 2e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            },\n            \"age(funding)\": {\n              \"value\": 485000,\n              \"unit\": \"ms\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 0.000104,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"age(funding)\": {\n              \"value\": 1000,\n              \"unit\": \"ms\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 8e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"age(funding)\": {\n              \"value\": 1000,\n              \"unit\": \"ms\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 5.4e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"age(funding)\": {\n              \"value\": 1000,\n              \"unit\": \"ms\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImQzNTU5ZjgyZmEzNGU5MDUifQ\"\n  }\n}\n```\n\n`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.\n\n## 5. Operators\n\nArithmetic, comparison and the three connectives. Precedence is the usual one: unary minus, then `* /`, then `+ -`, then comparison, then `not`, then `and`, then `or`.\n\n```ebnf\ncondition    = or_expr ;\nor_expr      = and_expr , { \"or\" , and_expr } ;\nand_expr     = not_expr , { \"and\" , not_expr } ;\nnot_expr     = \"not\" , not_expr\n             | comparison ;\ncomparison   = expression , [ compare_op , expression\n                            | \"in\" , \"(\" , in_literal , { \",\" , in_literal } , \")\" ] ;\ncompare_op   = \"=\" | \"==\" | \"!=\" | \"<>\" | \"<\" | \"<=\" | \">\" | \">=\" ;\n\nexpression   = term , { ( \"+\" | \"-\" ) , term } ;\nterm         = factor , { ( \"*\" | \"/\" ) , factor } ;\nfactor       = \"-\" , factor\n             | primary ;\n```\n\n```dql\nany(venues where (mark - index) / index > 5bps)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 86990,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"index\": {\n              \"value\": 86950,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 87010,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"index\": {\n              \"value\": 86960,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 87000,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"index\": {\n              \"value\": 86950,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 86995,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"index\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"not_retained\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6Ijk2ZWExZjk5MGMyMjc1OTUifQ\"\n  }\n}\n```\n\nTwo 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.\n\n## 6. Quantifiers and aggregates\n\n`any`, `all` and `count` ask a question about the venues. `max`, `min` and `sum` compute one number from them.\n\n```ebnf\nquantifier   = ( \"any\" | \"all\" | \"count\" ) , \"(\" , \"venues\" , \"where\" , condition , \")\" ;\naggregate    = ( \"max\" | \"min\" | \"sum\" ) , \"(\" , \"venues\" , [ \"where\" , condition ] ,\n               \",\" , expression , \")\" ;\n\n```\n\n```dql\nmax(venues where quote = USDT, oi) > 1000\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {\n        \"max(venues where quote = USDT, oi)\": {\n          \"value\": 60800,\n          \"unit\": \"base\",\n          \"from\": [\n            {\n              \"venue\": \"BYBIT-PERP\",\n              \"value\": 60800,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"quote\": {\n              \"value\": \"USDT\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"reference\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T00:00:00Z\",\n              \"age_ms\": 43205000,\n              \"status\": \"present\"\n            },\n            \"oi\": {\n              \"value\": 60800,\n              \"unit\": \"base\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"quote\": {\n              \"value\": \"USDC\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"reference\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T00:00:00Z\",\n              \"age_ms\": 43205000,\n              \"status\": \"present\"\n            },\n            \"oi\": {\n              \"value\": 9400,\n              \"unit\": \"base\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"quote\": {\n              \"value\": \"USD\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"reference\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T00:00:00Z\",\n              \"age_ms\": 43205000,\n              \"status\": \"present\"\n            },\n            \"oi\": {\n              \"value\": 5800,\n              \"unit\": \"base\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"quote\": {\n              \"value\": \"USDT\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"reference\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T00:00:00Z\",\n              \"age_ms\": 43205000,\n              \"status\": \"present\"\n            },\n            \"oi\": {\n              \"value\": 41200,\n              \"unit\": \"base\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImJiMjc1OWQ1YmY1N2M5YTQifQ\"\n  }\n}\n```\n\n`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.\n\n## 7. Series\n\nCandles and sampled snapshots, read at a period. A series function needs a timeframe — on the query or as its own last argument.\n\n```ebnf\ncall         = IDENT , \"(\" , [ condition , { \",\" , condition } ] , \")\" ;\n```\n\n```dql\nany(venues where ema(close, 20) > ema(close, 50)) timeframe 1h\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"timeframe\": \"1h\",\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImRkOWI3MzhhMWQzNzY1OTQifQ\"\n  }\n}\n```\n\n`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.\n\n## 8. Data quality\n\n`age` and `status` are how a query asks about the data rather than about the market.\n\n```dql\nall(venues where status(funding) = present and age(funding) < 5m)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"SOL-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"SOL\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"age(funding)\": {\n              \"value\": 1000,\n              \"unit\": \"ms\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\nThe 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.\n\n## 9. Book depth in bands\n\nHow much rests within a price band of the mid, per side, in quantity or in quote value.\n\n```dql\nany(venues where depth_bid_value(10bps) > 100000)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"depth_bid_value(0.001)\": {\n              \"value\": 68721.705,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"book\",\n              \"band\": \"10bps\",\n              \"reference\": \"mid\",\n              \"levels\": 4,\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"depth_bid_value(0.001)\": {\n              \"value\": 295830.6,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"book\",\n              \"band\": \"10bps\",\n              \"reference\": \"mid\",\n              \"levels\": 4,\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"depth_bid_value(0.001)\": {\n              \"value\": 104398.8,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"book\",\n              \"band\": \"10bps\",\n              \"reference\": \"mid\",\n              \"levels\": 4,\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"depth_bid_value(0.001)\": {\n              \"value\": 208787.76,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"book\",\n              \"band\": \"10bps\",\n              \"reference\": \"mid\",\n              \"levels\": 4,\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjRhMzA2ZWYwNTYwNzU0NWMifQ\"\n  }\n}\n```\n\nThe 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.\n\n## 10. Three-valued logic\n\nA comparison involving a value that is missing or stale is neither true nor false. It is unknown, and unknown propagates.\n\n```dql\nall(venues where funding > 0)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00002,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000013,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00001,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000054,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImI2ZTllZTg0MjMxMDhjNTMifQ\"\n  }\n}\n```\n\nThis 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.\n\n## 11. Point in time\n\n`as of` asks the same question about a past instant. What was visible then is what is used.\n\n```dql\ncount(venues where funding > 0) >= 2 as of 2026-09-23T08:00:00Z\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": \"2026-09-23T08:00:00Z\",\n  \"settled\": true,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 0,\n    \"next_cursor\": null\n  }\n}\n```\n\nVisibility 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.\n\n## 12. Freshness\n\nEach layer has a bound; a reading older than its bound is stale. A query may set its own.\n\n```dql\nany(venues where funding > 0) freshness 10m\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"10m\",\n    \"mark\": \"10m\",\n    \"oi\": \"10m\",\n    \"book\": \"10m\",\n    \"stats\": \"10m\",\n    \"funding\": \"10m\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00002,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000013,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00001,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000054,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjdlYjNlM2NkYTgxZTdiOTYifQ\"\n  }\n}\n```\n\nThe 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.\n\n## 13. Selecting listings\n\n`where` chooses which listings the query runs over, before the condition is evaluated.\n\n```ebnf\nclause       = \"timeframe\" , DURATION\n             | \"freshness\" , DURATION\n             | \"as\" , \"of\" , TIMESTAMP\n             | \"order\" , \"by\" , order_item , { \",\" , order_item }        (* C1-06: several keys *)\n             | \"select\" , expression , { \",\" , expression }              (* C1-05 *)\n             | \"where\" , condition ;                                     (* C4-02: selection *)\n\n```\n\n```dql\nvenues_listed >= 1 where venue = KRAKEN-FUTURES and base = BTC\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {\n        \"venues_listed\": {\n          \"value\": 1,\n          \"from\": \"reference\",\n          \"as_of\": \"2026-09-23T12:00:05Z\"\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {}\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\n`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.\n\n## 14. What comes back\n\nEvery value is an object: the number, and everything needed to judge it.\n\n```dql\nany(venues where funding > 0) select funding, status(funding), age(funding)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00002,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            },\n            \"status(funding)\": {\n              \"value\": \"stale\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            },\n            \"age(funding)\": {\n              \"value\": 485000,\n              \"unit\": \"ms\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000013,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"age(funding)\": {\n              \"value\": 1000,\n              \"unit\": \"ms\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00001,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"age(funding)\": {\n              \"value\": 1000,\n              \"unit\": \"ms\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000054,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"age(funding)\": {\n              \"value\": 1000,\n              \"unit\": \"ms\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImY5MGMxNDk4MWVkMTljMmMifQ\"\n  }\n}\n```\n\nA 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.\n\n## 15. Limits\n\nEvery ceiling is served as data by `GET /v2/dql/catalogue` and explained in [Limits](#limits). The ones that shape how a query is written:\n\n| limit | value |\n| --- | --- |\n| longest query text | 8192 bytes |\n| quantifiers and aggregates in one query | 16 |\n| series calls | 32 |\n| different periods | 3 |\n| longest window | 500 periods |\n| values in one `select` | 16 |\n| keys in one `order by` | 4 |\n\n`POST /v2/dql/parse` returns a query's cost before you run it.\n\n## 16. What the language does not do\n\nStated because a language's edges are as much a part of it as its middle, and because each of these was\ndecided rather than forgotten.\n\n- **Boolean series.** `crossover` returns a truth about the last period, not a series of truths you can\n  feed to another function. Chaining them needs a way to say which period you mean, and no wording for\n  that has survived review.\n- **Cross-instrument references.** A query about BTC cannot read ETH. The scope rules have two levels,\n  instrument and venue; a third would make every condition ambiguous about which instrument it is\n  talking about.\n- **Sub-minute sampling.** One minute is the base period the platform stores. A query asking for less is\n  asking about jitter in the collection, not about the market.\n- **Mark-price sampled series.** Snapshot layers are sampled; the mark layer is not sampled into a series\n  of its own, because `mark_close` candles already exist and two answers to one question is one too many.\n- **Spot.** The platform collects perpetual futures. Spot is not a missing feature; it is a different\n  product.\n\nEach of these is a decision with a reason, and each can be revisited. None of them is a bug.\n\n\n# Fields, sources and functions\n\nEvery name a query may use. Generated from the catalogue the engine runs on — `GET /v2/dql/catalogue`\nserves the same thing as data, and a client should read it from there rather than carry a copy.\n\nEach entry shows a query that reads it and **the value the engine gave back**, on the documentation\nfixture. The shape is the shape you will get; the numbers are invented.\n\nTwo columns are worth understanding before the tables:\n\n- **scope** — `instrument` names belong to the instrument, `venue` names to one venue's listing of it. A\n  venue-scoped name has to sit inside `any(…)`, `all(…)`, `count(…)` or an aggregate, because an\n  instrument has several venues and the language will not silently pick one.\n- **additive** — whether summing it across venues means anything. `sum` refuses a field that is not\n  additive: adding prices is a category error, not a small inaccuracy.\n\n## Fields\n\n| field | scope | layer | type | unit | sampleable | additive |\n| --- | --- | --- | --- | --- | --- | --- |\n| [`instrument`](#instrument) | instrument | reference | code | code | — | — |\n| [`base`](#base) | instrument | reference | code | code | — | — |\n| [`venues_listed`](#venues-listed) | instrument | reference | number | count | — | — |\n| [`venues_answered`](#venues-answered) | instrument | reference | number | count | — | — |\n| [`venue`](#venue) | venue | reference | code | code | — | — |\n| [`quote`](#quote) | venue | reference | code | code | — | — |\n| [`tick_size`](#tick-size) | venue | reference | number | quote | — | — |\n| [`lot_size`](#lot-size) | venue | reference | number | quantity | — | — |\n| [`min_qty`](#min-qty) | venue | reference | number | quantity | — | — |\n| [`last`](#last) | venue | ticker | number | quote | yes | — |\n| [`mark`](#mark) | venue | mark | number | quote | yes | — |\n| [`index`](#index) | venue | mark | number | quote | yes | — |\n| [`basis`](#basis) | venue | mark | number | fraction | yes | — |\n| [`funding`](#funding) | venue | funding | number | fraction | yes | — |\n| [`funding_interval`](#funding-interval) | venue | funding | duration | ms | — | — |\n| [`funding_8h`](#funding-8h) | venue | funding | number | fraction | yes | — |\n| [`time_to_funding`](#time-to-funding) | venue | funding | duration | ms | — | — |\n| [`oi`](#oi) | venue | oi | number | quantity | yes | yes |\n| [`bid`](#bid) | venue | book | number | quote | yes | — |\n| [`ask`](#ask) | venue | book | number | quote | yes | — |\n| [`mid`](#mid) | venue | book | number | quote | yes | — |\n| [`spread`](#spread) | venue | book | number | fraction | yes | — |\n| [`bid_size`](#bid-size) | venue | book | number | quantity | yes | yes |\n| [`ask_size`](#ask-size) | venue | book | number | quantity | yes | yes |\n| [`volume_24h`](#volume-24h) | venue | stats | number | quantity | yes | yes |\n| [`turnover_24h`](#turnover-24h) | venue | stats | number | quote | yes | yes |\n| [`change_24h`](#change-24h) | venue | stats | number | fraction | yes | — |\n\n### instrument\n\nthe market code, e.g. BTC-PERP\n\n*Instrument-scoped, layer `reference`, type code, unit code.*\n\n```dql\nvenues_listed >= 1 select instrument\n```\n\n```json\n{\n  \"value\": \"BTC-PERP\",\n  \"from\": \"reference\",\n  \"as_of\": \"2026-09-23T12:00:05Z\"\n}\n```\n\n### base\n\nthe base asset's registry code, e.g. BTC\n\n*Instrument-scoped, layer `reference`, type code, unit code.*\n\n```dql\nvenues_listed >= 1 select base\n```\n\n```json\n{\n  \"value\": \"BTC\",\n  \"from\": \"reference\",\n  \"as_of\": \"2026-09-23T12:00:05Z\"\n}\n```\n\n### venues_listed\n\nnumber of (selected) listings at T\n\n*Instrument-scoped, layer `reference`, type number, unit count.*\n\n```dql\nvenues_listed >= 1 select venues_listed\n```\n\n```json\n{\n  \"value\": 4,\n  \"from\": \"reference\",\n  \"as_of\": \"2026-09-23T12:00:05Z\"\n}\n```\n\n### venues_answered\n\nnumber of (selected) listings whose mark is present at T\n\n*Instrument-scoped, layer `reference`, type number, unit count.*\n\n```dql\nvenues_listed >= 1 select venues_answered\n```\n\n```json\n{\n  \"value\": 4,\n  \"from\": \"reference\",\n  \"as_of\": \"2026-09-23T12:00:05Z\"\n}\n```\n\n### venue\n\nthe venue's public code\n\n*Venue-scoped, layer `reference`, type code, unit code.*\n\n```dql\nvenues_listed >= 1 select venue\n```\n\n```json\n{\n  \"value\": \"BYBIT-PERP\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"reference\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T00:00:00Z\",\n  \"age_ms\": 43205000,\n  \"status\": \"present\"\n}\n```\n\n### quote\n\nthe listing's quote currency\n\n*Venue-scoped, layer `reference`, type code, unit code.*\n\n```dql\nvenues_listed >= 1 select quote\n```\n\n```json\n{\n  \"value\": \"USDT\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"reference\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T00:00:00Z\",\n  \"age_ms\": 43205000,\n  \"status\": \"present\"\n}\n```\n\n### tick_size\n\nminimum price increment of the listing\n\n*Venue-scoped, layer `reference`, type number, unit quote.*\n\n```dql\nvenues_listed >= 1 select tick_size\n```\n\n```json\n{\n  \"value\": 0.1,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"reference\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T00:00:00Z\",\n  \"age_ms\": 43205000,\n  \"status\": \"present\"\n}\n```\n\n### lot_size\n\nminimum quantity increment\n\n*Venue-scoped, layer `reference`, type number, unit quantity.*\n\n```dql\nvenues_listed >= 1 select lot_size\n```\n\n```json\n{\n  \"value\": 0.001,\n  \"unit\": \"base\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"reference\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T00:00:00Z\",\n  \"age_ms\": 43205000,\n  \"status\": \"present\"\n}\n```\n\n### min_qty\n\nminimum order quantity\n\n*Venue-scoped, layer `reference`, type number, unit quantity.*\n\n```dql\nvenues_listed >= 1 select min_qty\n```\n\n```json\n{\n  \"value\": 0.001,\n  \"unit\": \"base\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"reference\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T00:00:00Z\",\n  \"age_ms\": 43205000,\n  \"status\": \"present\"\n}\n```\n\n### last\n\nlast trade price\n\n*Venue-scoped, layer `ticker`, type number, unit quote, readable as a series.*\n\n```dql\nvenues_listed >= 1 select last\n```\n\n```json\n{\n  \"value\": 86988,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"ticker\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### mark\n\nvenue mark price\n\n*Venue-scoped, layer `mark`, type number, unit quote, readable as a series.*\n\n```dql\nvenues_listed >= 1 select mark\n```\n\n```json\n{\n  \"value\": 86990,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"mark\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### index\n\nvenue index price\n\n*Venue-scoped, layer `mark`, type number, unit quote, readable as a series.*\n\n```dql\nvenues_listed >= 1 select index\n```\n\n```json\n{\n  \"value\": 86950,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"mark\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### basis\n\n(mark − index) / index\n\n*Venue-scoped, layer `mark`, type number, unit fraction, readable as a series.*\n\n```dql\nvenues_listed >= 1 select basis\n```\n\n```json\n{\n  \"value\": 0.00046003450258769407,\n  \"unit\": \"fraction\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"mark\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### funding\n\npublished rate for the next settlement, per interval\n\n*Venue-scoped, layer `funding`, type number, unit fraction, readable as a series.*\n\n```dql\nvenues_listed >= 1 select funding\n```\n\n```json\n{\n  \"value\": 0.00002,\n  \"unit\": \"fraction\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"funding\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T11:52:00Z\",\n  \"age_ms\": 485000,\n  \"status\": \"stale\"\n}\n```\n\n### funding_interval\n\nsettlement interval as published\n\n*Venue-scoped, layer `funding`, type duration, unit ms.*\n\n```dql\nvenues_listed >= 1 select funding_interval\n```\n\n```json\n{\n  \"value\": 28800000,\n  \"unit\": \"ms\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"funding\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T11:52:00Z\",\n  \"age_ms\": 485000,\n  \"status\": \"stale\"\n}\n```\n\n### funding_8h\n\nfunding × 8h / funding_interval\n\n*Venue-scoped, layer `funding`, type number, unit fraction, readable as a series.*\n\n```dql\nvenues_listed >= 1 select funding_8h\n```\n\n```json\n{\n  \"value\": 2e-05,\n  \"unit\": \"fraction\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"funding\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T11:52:00Z\",\n  \"age_ms\": 485000,\n  \"status\": \"stale\"\n}\n```\n\n### time_to_funding\n\nnext_funding_at − T\n\n*Venue-scoped, layer `funding`, type duration, unit ms.*\n\n```dql\nvenues_listed >= 1 select time_to_funding\n```\n\n```json\n{\n  \"value\": 14400000,\n  \"unit\": \"ms\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"funding\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T11:52:00Z\",\n  \"age_ms\": 485000,\n  \"status\": \"stale\"\n}\n```\n\n### oi\n\nopen interest\n\n*Venue-scoped, layer `oi`, type number, unit quantity, readable as a series, additive across venues.*\n\n```dql\nvenues_listed >= 1 select oi\n```\n\n```json\n{\n  \"value\": 60800,\n  \"unit\": \"base\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"oi\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### bid\n\nbest bid price\n\n*Venue-scoped, layer `book`, type number, unit quote, readable as a series.*\n\n```dql\nvenues_listed >= 1 select bid\n```\n\n```json\n{\n  \"value\": 86989.5,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### ask\n\nbest ask price\n\n*Venue-scoped, layer `book`, type number, unit quote, readable as a series.*\n\n```dql\nvenues_listed >= 1 select ask\n```\n\n```json\n{\n  \"value\": 86990.5,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### mid\n\n(bid + ask) / 2\n\n*Venue-scoped, layer `book`, type number, unit quote, readable as a series.*\n\n```dql\nvenues_listed >= 1 select mid\n```\n\n```json\n{\n  \"value\": 86990,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### spread\n\n(ask − bid) / mid\n\n*Venue-scoped, layer `book`, type number, unit fraction, readable as a series.*\n\n```dql\nvenues_listed >= 1 select spread\n```\n\n```json\n{\n  \"value\": 1.1495574203931486e-05,\n  \"unit\": \"fraction\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### bid_size\n\nresting quantity at the best bid\n\n*Venue-scoped, layer `book`, type number, unit quantity, readable as a series, additive across venues.*\n\n```dql\nvenues_listed >= 1 select bid_size\n```\n\n```json\n{\n  \"value\": 0.79,\n  \"unit\": \"base\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### ask_size\n\nresting quantity at the best ask\n\n*Venue-scoped, layer `book`, type number, unit quantity, readable as a series, additive across venues.*\n\n```dql\nvenues_listed >= 1 select ask_size\n```\n\n```json\n{\n  \"value\": 3.19,\n  \"unit\": \"base\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### volume_24h\n\nrolling 24h traded volume as published\n\n*Venue-scoped, layer `stats`, type number, unit quantity, readable as a series, additive across venues.*\n\n```dql\nvenues_listed >= 1 select volume_24h\n```\n\n```json\n{\n  \"value\": 72800,\n  \"unit\": \"base\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"stats\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### turnover_24h\n\nrolling 24h traded value as published\n\n*Venue-scoped, layer `stats`, type number, unit quote, readable as a series, additive across venues.*\n\n```dql\nvenues_listed >= 1 select turnover_24h\n```\n\n```json\n{\n  \"value\": 6332000000,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"stats\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### change_24h\n\n24h price change as published\n\n*Venue-scoped, layer `stats`, type number, unit fraction, readable as a series.*\n\n```dql\nvenues_listed >= 1 select change_24h\n```\n\n```json\n{\n  \"value\": 0.011,\n  \"unit\": \"fraction\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"stats\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n## Candle sources\n\nA source is one column of the candles of one price type. `close` is the trade price; `mark_close` is the\nvenue's mark price; `index_close` is its index. They are different measurements and the language keeps\nthem apart — a funding calculation done on trade prices is a different number from the one the venue\nsettled.\n\nA source is only readable at a timeframe: `timeframe 15m` on the query, or as a trailing argument on the\nfunction that reads it.\n\n| source | price type | column | unit | additive |\n| --- | --- | --- | --- | --- |\n| `open` | trade | open | quote | — |\n| `high` | trade | high | quote | — |\n| `low` | trade | low | quote | — |\n| `close` | trade | close | quote | — |\n| `volume` | trade | volume | quantity | yes |\n| `mark_open` | mark | open | quote | — |\n| `mark_high` | mark | high | quote | — |\n| `mark_low` | mark | low | quote | — |\n| `mark_close` | mark | close | quote | — |\n| `mark_volume` | mark | volume | quantity | yes |\n| `index_open` | index | open | quote | — |\n| `index_high` | index | high | quote | — |\n| `index_low` | index | low | quote | — |\n| `index_close` | index | close | quote | — |\n| `index_volume` | index | volume | quantity | yes |\n\nRead one, at a period:\n\n```dql\nvenues_listed >= 1 select close timeframe 15m\n```\n\n```json\n{\n  \"value\": 86980,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 1,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n\n## Functions\n\nThe `bars` column says how much history the function needs, as a rule over the window it is given. It is\nwhat the platform charges against `bars_per_atom` and `cost`, and `POST /v2/dql/parse` will tell you a\nquery's cost before you run it.\n\n| function | kind | returns | bars | unit |\n| --- | --- | --- | --- | --- |\n| [`prev(S, k)`](#prev) | series | series | bars(S) + n | — |\n| [`sma(S, n)`](#sma) | series | series | bars(S) + n − 1 | — |\n| [`ema(S, n)`](#ema) | series | series | bars(S) + 4n − 1 | — |\n| [`rsi(S, n)`](#rsi) | series | series | bars(S) + 4n | — |\n| [`atr(n)`](#atr) | series | series | 4n + 1 | — |\n| [`stdev(S, n)`](#stdev) | series | series | bars(S) + n − 1 | — |\n| [`highest(S, n)`](#highest) | series | series | bars(S) + n − 1 | — |\n| [`lowest(S, n)`](#lowest) | series | series | bars(S) + n − 1 | — |\n| [`change(S, n)`](#change) | series | series | bars(S) + n | — |\n| [`roc(S, n)`](#roc) | series | series | bars(S) + n | — |\n| [`crossover(A, B)`](#crossover) | series | boolean | max(bars(A), bars(B)) + 1 | — |\n| [`crossunder(A, B)`](#crossunder) | series | boolean | max(bars(A), bars(B)) + 1 | — |\n| [`gaps(n)`](#gaps) | series | number | n | — |\n| [`abs(x)`](#abs) | scalar | number | bars(x) | — |\n| [`rolling_sum(S, n)`](#rolling-sum) | series | series | bars(S) + n − 1 | — |\n| [`percentile(S, n, p, [method])`](#percentile) | series | series | bars(S) + n − 1 | — |\n| [`percentile_rank(S, n)`](#percentile-rank) | series | series | bars(S) + n − 1 | — |\n| [`age(F)`](#age) | data quality | duration | — | — |\n| [`status(F)`](#status) | data quality | status | — | — |\n| [`depth_bid(band)`](#depth-bid) | book depth | number | — | quantity |\n| [`depth_ask(band)`](#depth-ask) | book depth | number | — | quantity |\n| [`depth_bid_value(band)`](#depth-bid-value) | book depth | number | — | quote |\n| [`depth_ask_value(band)`](#depth-ask-value) | book depth | number | — | quote |\n\n### prev\n\nS[k]\n\n`prev(S, k)` — series, returns series, reads bars(S) + n bars.\n\n```dql\nvenues_listed >= 1 select prev(close, 1) timeframe 15m\n```\n\n```json\n{\n  \"value\": 85476.66666666667,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 2,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### sma\n\nsimple moving average\n\n`sma(S, n)` — series, returns series, reads bars(S) + n − 1 bars.\n\n```dql\nvenues_listed >= 1 select sma(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 85517.16666666666,\n  \"unit\": \"quote\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 20,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### ema\n\nexponential moving average over a fixed 4n window\n\n`ema(S, n)` — series, returns series, reads bars(S) + 4n − 1 bars.\n\n```dql\nvenues_listed >= 1 select ema(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 85564.184136414,\n  \"unit\": \"quote\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 80,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### rsi\n\nrelative strength index, Wilder smoothing over 4n\n\n`rsi(S, n)` — series, returns series, reads bars(S) + 4n bars.\n\n```dql\nvenues_listed >= 1 select rsi(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 85.16667851522334,\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 81,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### atr\n\naverage true range of the trade candles\n\n`atr(n)` — series, returns series, reads 4n + 1 bars.\n\n```dql\nvenues_listed >= 1 select atr(14) timeframe 15m\n```\n\n```json\n{\n  \"value\": 231.59289811088146,\n  \"unit\": \"quote\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 57,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### stdev\n\npopulation standard deviation\n\n`stdev(S, n)` — series, returns series, reads bars(S) + n − 1 bars.\n\n```dql\nvenues_listed >= 1 select stdev(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 342.66970653645143,\n  \"unit\": \"quote\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 20,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### highest\n\nmax(S[0] … S[n−1])\n\n`highest(S, n)` — series, returns series, reads bars(S) + n − 1 bars.\n\n```dql\nvenues_listed >= 1 select highest(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 87000,\n  \"unit\": \"quote\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 20,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### lowest\n\nmin(S[0] … S[n−1])\n\n`lowest(S, n)` — series, returns series, reads bars(S) + n − 1 bars.\n\n```dql\nvenues_listed >= 1 select lowest(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 85373.33333333333,\n  \"unit\": \"quote\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 20,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### change\n\nS[0] − S[n]\n\n`change(S, n)` — series, returns series, reads bars(S) + n bars.\n\n```dql\nvenues_listed >= 1 select change(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 1606.6666666666715,\n  \"unit\": \"quote\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 21,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### roc\n\n(S[0] − S[n]) / S[n]\n\n`roc(S, n)` — series, returns series, reads bars(S) + n bars.\n\n```dql\nvenues_listed >= 1 select roc(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 0.01881489577640727,\n  \"unit\": \"fraction\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 21,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### crossover\n\nA[0] > B[0] and A[1] ≤ B[1]\n\n`crossover(A, B)` — series, returns boolean, reads max(bars(A), bars(B)) + 1 bars.\n\n```dql\nvenues_listed >= 1 select crossover(ema(close, 5), ema(close, 20)) timeframe 15m\n```\n\n```json\n{\n  \"value\": false,\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 81,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### crossunder\n\nA[0] < B[0] and A[1] ≥ B[1]\n\n`crossunder(A, B)` — series, returns boolean, reads max(bars(A), bars(B)) + 1 bars.\n\n```dql\nvenues_listed >= 1 select crossunder(ema(close, 5), ema(close, 20)) timeframe 15m\n```\n\n```json\n{\n  \"value\": false,\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 81,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### gaps\n\nmissing periods among the last n\n\n`gaps(n)` — series, returns number, reads n bars.\n\n```dql\nvenues_listed >= 1 select gaps(20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 1,\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 20,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### abs\n\n|x|, element-wise for series\n\n`abs(x)` — scalar, returns number, reads bars(x) bars.\n\n```dql\nvenues_listed >= 1 select abs(change_24h)\n```\n\n```json\n{\n  \"value\": 0.011,\n  \"unit\": \"fraction\",\n  \"derived\": true,\n  \"atoms\": {\n    \"change_24h\": {\n      \"value\": 0.011,\n      \"unit\": \"fraction\",\n      \"venue\": \"BYBIT-PERP\",\n      \"layer\": \"stats\",\n      \"venue_ts\": null,\n      \"received_at\": \"2026-09-23T12:00:04Z\",\n      \"age_ms\": 1000,\n      \"status\": \"present\"\n    }\n  }\n}\n```\n\n### rolling_sum\n\nS[n−1] + … + S[0]\n\n`rolling_sum(S, n)` — series, returns series, reads bars(S) + n − 1 bars.\n\n```dql\nvenues_listed >= 1 select rolling_sum(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 1710343.3333333333,\n  \"unit\": \"quote\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 20,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### percentile\n\nnearest-rank (default) or linear percentile of S[0] … S[n−1]\n\n`percentile(S, n, p, [method])` — series, returns series, reads bars(S) + n − 1 bars.\n\n```dql\nvenues_listed >= 1 select percentile(close, 20, 0.9) timeframe 15m\n```\n\n```json\n{\n  \"value\": 85496.66666666667,\n  \"unit\": \"quote\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 20,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### percentile_rank\n\nshare of S[0] … S[n−1] that are ≤ S[0]\n\n`percentile_rank(S, n)` — series, returns series, reads bars(S) + n − 1 bars.\n\n```dql\nvenues_listed >= 1 select percentile_rank(close, 20) timeframe 15m\n```\n\n```json\n{\n  \"value\": 1,\n  \"unit\": \"fraction\",\n  \"venue\": \"HYPERLIQUID\",\n  \"layer\": \"candles\",\n  \"timeframe\": \"15m\",\n  \"bars\": 20,\n  \"candle_end\": \"2026-09-23T12:00:00Z\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:00.300Z\",\n  \"age_ms\": 4700,\n  \"status\": \"present\"\n}\n```\n\n### age\n\nT − received_at of the value used for F\n\n`age(F)` — data quality, returns duration.\n\n```dql\nvenues_listed >= 1 select age(funding)\n```\n\n```json\n{\n  \"value\": 485000,\n  \"unit\": \"ms\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"funding\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T11:52:00Z\",\n  \"age_ms\": 485000,\n  \"status\": \"stale\"\n}\n```\n\n### status\n\nstate of F's layer at T\n\n`status(F)` — data quality, returns status.\n\n```dql\nvenues_listed >= 1 select status(funding)\n```\n\n```json\n{\n  \"value\": \"stale\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"funding\",\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T11:52:00Z\",\n  \"age_ms\": 485000,\n  \"status\": \"stale\"\n}\n```\n\n### depth_bid\n\nbid quantity within band of mid\n\n`depth_bid(band)` — book depth, returns number.\n\n```dql\nvenues_listed >= 1 select depth_bid(10bps)\n```\n\n```json\n{\n  \"value\": 0.79,\n  \"unit\": \"base\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"band\": \"10bps\",\n  \"reference\": \"mid\",\n  \"levels\": 4,\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### depth_ask\n\nask quantity within band of mid\n\n`depth_ask(band)` — book depth, returns number.\n\n```dql\nvenues_listed >= 1 select depth_ask(10bps)\n```\n\n```json\n{\n  \"value\": 3.19,\n  \"unit\": \"base\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"band\": \"10bps\",\n  \"reference\": \"mid\",\n  \"levels\": 4,\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### depth_bid_value\n\nbid value (price × size) within band of mid\n\n`depth_bid_value(band)` — book depth, returns number.\n\n```dql\nvenues_listed >= 1 select depth_bid_value(10bps)\n```\n\n```json\n{\n  \"value\": 68721.705,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"band\": \"10bps\",\n  \"reference\": \"mid\",\n  \"levels\": 4,\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n### depth_ask_value\n\nask value (price × size) within band of mid\n\n`depth_ask_value(band)` — book depth, returns number.\n\n```dql\nvenues_listed >= 1 select depth_ask_value(10bps)\n```\n\n```json\n{\n  \"value\": 277499.695,\n  \"unit\": \"quote\",\n  \"venue\": \"BYBIT-PERP\",\n  \"layer\": \"book\",\n  \"band\": \"10bps\",\n  \"reference\": \"mid\",\n  \"levels\": 4,\n  \"venue_ts\": null,\n  \"received_at\": \"2026-09-23T12:00:04Z\",\n  \"age_ms\": 1000,\n  \"status\": \"present\"\n}\n```\n\n\n## What is not here\n\nNames the specification mentions that are not functions of the language: `rma` and `sqrt` are notation\ninside the formulas of §7.3, not things a query may call. `depth_bid` and `depth_ask` were fields in an\nearly draft and are functions of a price band now — `depth_bid_qty(10bps)`, not `depth_bid`.\n\n\n# Cookbook\n\nQueries that answer a question somebody actually has, with the answer the engine gives.\n\nEvery recipe is taken from [the guide](#the-guide), where it is explained in full; this page is the\nindex you scan when you know what you want and not how to write it. The answers are rendered on the\ndocumentation fixture — real venue codes and symbols, invented numbers.\n\n## Positive funding on any venue\n\nIntent: instruments with a positive funding rate on at least one venue.\n\n```dql\nany(venues where funding > 0)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00002,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000013,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00001,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000054,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjdlZjMxMGZmYTMyOTI2ZDEifQ\"\n  }\n}\n```\n\n## Fresh positive funding on at least three venues\n\nIntent: the funding rate, normalised to eight hours, is above one basis point on three or more venues, and each of those readings is less than two minutes old.\n\n```dql\ncount(venues where funding_8h > 1bps and age(funding) < 2m) >= 3\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 0,\n    \"next_cursor\": null\n  }\n}\n```\n\n## Cross-venue mark dispersion\n\nIntent: the highest and lowest mark price across venues differ by more than five basis points of the lowest, and at least three venues are answering.\n\n```dql\n(max(venues, mark) - min(venues, mark)) / min(venues, mark) > 5bps and venues_answered >= 3\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"ETH-PERP\",\n      \"result\": \"true\",\n      \"values\": {\n        \"max(venues, mark)\": {\n          \"value\": 2751,\n          \"unit\": \"quote\",\n          \"from\": [\n            {\n              \"venue\": \"BYBIT-PERP\",\n              \"value\": 2751,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        },\n        \"min(venues, mark)\": {\n          \"value\": 2749,\n          \"unit\": \"quote\",\n          \"from\": [\n            {\n              \"venue\": \"OKX-PERP\",\n              \"value\": 2749,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        },\n        \"venues_answered\": {\n          \"value\": 3,\n          \"from\": \"reference\",\n          \"as_of\": \"2026-09-23T12:00:05Z\"\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"ETHUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 2751,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_ETHUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 2750,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"ETH-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 2749,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\n## Two named venues\n\nIntent: the mark price on KRAKEN-FUTURES and BYBIT-PERP differs by more than 10 (quote units).\n\n```dql\nmax(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark) - min(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark) > 10\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"SOL-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {\n        \"max(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark)\": {\n          \"value\": null,\n          \"unit\": \"quote\",\n          \"from\": [],\n          \"reason\": \"no_value\"\n        },\n        \"min(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark)\": {\n          \"value\": null,\n          \"unit\": \"quote\",\n          \"from\": [],\n          \"reason\": \"no_value\"\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"SOL\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"venue\": {\n              \"value\": \"HYPERLIQUID\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"reference\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T00:00:00Z\",\n              \"age_ms\": 43205000,\n              \"status\": \"present\"\n            },\n            \"mark\": {\n              \"value\": 118,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\n## Tight books wherever there is a book\n\nIntent: every venue that publishes an order book has a spread below five basis points. Venues that publish no book (oracle-priced venues) must not make the condition fail.\n\n```dql\nall(venues where status(bid) = not_published or spread < 5bps)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"status(bid)\": {\n              \"value\": \"present\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 1.1495574203931486e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"status(bid)\": {\n              \"value\": \"present\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 2.2985863693828294e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"status(bid)\": {\n              \"value\": \"present\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 2.2988505747126437e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"status(bid)\": {\n              \"value\": \"present\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 2.298982700289e-06,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImI5ZTY0YzFjZWJmOTkzZmQifQ\"\n  }\n}\n```\n\n## Trend on hourly candles, any venue\n\nIntent: on at least one venue, the 20-candle EMA of hourly closes is above the 50-candle EMA.\n\n```dql\nany(venues where ema(close, 20) > ema(close, 50)) timeframe 1h\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"timeframe\": \"1h\",\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImRkOWI3MzhhMWQzNzY1OTQifQ\"\n  }\n}\n```\n\n## A cross on the latest closed 15-minute candle, one venue, clean history\n\nIntent: on KRAKEN-FUTURES, the 20-EMA crossed above the 50-EMA on the most recent completed 15-minute candle, and the last 200 candles have no gaps.\n\n```dql\nany(venues where venue = KRAKEN-FUTURES and crossover(ema(close, 20), ema(close, 50)) and gaps(200) = 0) timeframe 15m\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"timeframe\": \"15m\",\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"ETH-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"ETHUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"venue\": {\n              \"value\": \"BYBIT-PERP\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"reference\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T00:00:00Z\",\n              \"age_ms\": 43205000,\n              \"status\": \"present\"\n            },\n            \"crossover(ema(close, 20), ema(close, 50))\": {\n              \"value\": null,\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 201,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"gaps(200)\": {\n              \"value\": null,\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_ETHUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"venue\": {\n              \"value\": \"KRAKEN-FUTURES\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"reference\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T00:00:00Z\",\n              \"age_ms\": 43205000,\n              \"status\": \"present\"\n            },\n            \"crossover(ema(close, 20), ema(close, 50))\": {\n              \"value\": null,\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 201,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"gaps(200)\": {\n              \"value\": null,\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"ETH-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"venue\": {\n              \"value\": \"OKX-PERP\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"reference\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T00:00:00Z\",\n              \"age_ms\": 43205000,\n              \"status\": \"present\"\n            },\n            \"crossover(ema(close, 20), ema(close, 50))\": {\n              \"value\": null,\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 201,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"gaps(200)\": {\n              \"value\": null,\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\n## Two timeframes in one condition\n\nIntent: hourly trend up (EMA 20 above EMA 50 on 1h candles) while the 15-minute RSI is low.\n\n```dql\nany(venues where ema(close, 20, 1h) > ema(close, 50, 1h) and rsi(close, 14, 15m) < 35)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"rsi(close, 14, 15m)\": {\n              \"value\": null,\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 57,\n              \"candle_end\": \"2026-09-23T12:00:00Z\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:00.300Z\",\n              \"age_ms\": 4700,\n              \"status\": \"present\",\n              \"reason\": \"gap\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"ema(close, 20, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"rsi(close, 14, 15m)\": {\n              \"value\": 88.19612724877551,\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 57,\n              \"candle_end\": \"2026-09-23T12:00:00Z\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:00.300Z\",\n              \"age_ms\": 4700,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"ema(close, 20, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"rsi(close, 14, 15m)\": {\n              \"value\": 88.19612724877551,\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 57,\n              \"candle_end\": \"2026-09-23T12:00:00Z\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:00.300Z\",\n              \"age_ms\": 4700,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"rsi(close, 14, 15m)\": {\n              \"value\": null,\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 57,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjMxOTVhZGUxMDU2YTFhOWMifQ\"\n  }\n}\n```\n\n## Which instruments have a venue that has gone quiet\n\nIntent: instruments where at least one listed venue is not answering (no fresh mark price).\n\n```dql\nvenues_answered < venues_listed\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 0,\n    \"next_cursor\": null\n  }\n}\n```\n\n## Stale, missing and not published are three different things\n\nIntent: instruments where at least one venue's funding rate is **stale** — we have a value, but it is older than the freshness bound.\n\n```dql\ncount(venues where status(funding) = stale) >= 1\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"status(funding)\": {\n              \"value\": \"stale\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\n## As of a past moment\n\nIntent: which instruments had positive funding on three or more venues at 08:00 UTC today, using only what DEBYKO had received by then.\n\n```dql\ncount(venues where funding > 0) >= 3 as of 2026-09-21T08:00:00Z\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": \"2026-09-21T08:00:00Z\",\n  \"settled\": true,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 0,\n    \"next_cursor\": null\n  }\n}\n```\n\n## Relaxed freshness for a historical question\n\nIntent: a week ago at noon, did any venue show open interest at all — accepting values up to ten minutes old.\n\n```dql\nany(venues where oi > 0) freshness 10m as of 2026-09-14T12:00:00Z\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": \"2026-09-14T12:00:00Z\",\n  \"settled\": true,\n  \"freshness\": {\n    \"ticker\": \"10m\",\n    \"mark\": \"10m\",\n    \"oi\": \"10m\",\n    \"book\": \"10m\",\n    \"stats\": \"10m\",\n    \"funding\": \"10m\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0xNFQxMjowMDowMFoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6Ijg5MDVkMmI1ZmRjNWVhNzEifQ\"\n  }\n}\n```\n\n## Like-for-like quotes only\n\nIntent: dispersion of mark prices above ten basis points, comparing only listings quoted in a USD stablecoin or USD.\n\n```dql\nmax(venues where quote in (USDT, USDC, USD), mark) / min(venues where quote in (USDT, USDC, USD), mark) - 1 > 10bps\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 0,\n    \"next_cursor\": null\n  }\n}\n```\n\n## Ordering the screen\n\nIntent: instruments answering on at least two venues, highest eight-hour funding first.\n\n```dql\nvenues_answered >= 2 order by max(venues, funding_8h) desc\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {\n        \"venues_answered\": {\n          \"value\": 4,\n          \"from\": \"reference\",\n          \"as_of\": \"2026-09-23T12:00:05Z\"\n        },\n        \"max(venues, funding_8h)\": {\n          \"value\": 0.000104,\n          \"unit\": \"fraction\",\n          \"from\": [\n            {\n              \"venue\": \"HYPERLIQUID\",\n              \"value\": 0.000104,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 2e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 0.000104,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 8e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 5.4e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjE0MTk1NWNjMGNhMzliODEifQ\"\n  }\n}\n```\n\n## Alerts, with Agent\n\nIntent: be told when, for any instrument, the 20/50 EMA cross happens on hourly candles on a venue with a clean 200-candle history. The condition is a query like any other:\n\n```dql\nany(venues where crossover(ema(close, 20), ema(close, 50)) and gaps(200) = 0) timeframe 1h\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"timeframe\": \"1h\",\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"crossover(ema(close, 20), ema(close, 50))\": {\n              \"value\": null,\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 201,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"gaps(200)\": {\n              \"value\": null,\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"crossover(ema(close, 20), ema(close, 50))\": {\n              \"value\": null,\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 201,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"gaps(200)\": {\n              \"value\": null,\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"crossover(ema(close, 20), ema(close, 50))\": {\n              \"value\": null,\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 201,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"gaps(200)\": {\n              \"value\": null,\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"crossover(ema(close, 20), ema(close, 50))\": {\n              \"value\": null,\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 201,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"gaps(200)\": {\n              \"value\": null,\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImViMGQ5ZmE4NmMxMzc3ZWIifQ\"\n  }\n}\n```\n\n## A rate of change on a snapshot field\n\nIntent: the mark price is more than half a per cent above where it stood five minutes ago, on any venue. `mark` is a snapshot field, not a candle, and DQL samples it at the effective timeframe.\n\n```dql\nany(venues where roc(mark, 5) > 0.5%) timeframe 1m\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"timeframe\": \"1m\",\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"roc(mark, 5)\": {\n              \"value\": null,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"mark\",\n              \"timeframe\": \"1m\",\n              \"bars\": 6,\n              \"sample_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"roc(mark, 5)\": {\n              \"value\": null,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"mark\",\n              \"timeframe\": \"1m\",\n              \"bars\": 6,\n              \"sample_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"roc(mark, 5)\": {\n              \"value\": null,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"mark\",\n              \"timeframe\": \"1m\",\n              \"bars\": 6,\n              \"sample_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"roc(mark, 5)\": {\n              \"value\": null,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"mark\",\n              \"timeframe\": \"1m\",\n              \"bars\": 6,\n              \"sample_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjRhZDZhYmRjMjY0ZGMzYTEifQ\"\n  }\n}\n```\n\n## A spread that is unusually wide for this venue\n\nIntent: the current spread sits above the 90th percentile of its own last hour — \"wide for this venue\", not \"wide compared with a number I guessed\".\n\n```dql\nany(venues where spread > percentile(spread, 60, 90%)) timeframe 1m\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"timeframe\": \"1m\",\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"spread\": {\n              \"value\": 1.1495574203931486e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"percentile(spread, 60, 0.9)\": {\n              \"value\": null,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"book\",\n              \"timeframe\": \"1m\",\n              \"bars\": 60,\n              \"sample_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"spread\": {\n              \"value\": 2.2985863693828294e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"percentile(spread, 60, 0.9)\": {\n              \"value\": null,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"book\",\n              \"timeframe\": \"1m\",\n              \"bars\": 60,\n              \"sample_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"spread\": {\n              \"value\": 2.2988505747126437e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"percentile(spread, 60, 0.9)\": {\n              \"value\": null,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"book\",\n              \"timeframe\": \"1m\",\n              \"bars\": 60,\n              \"sample_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"spread\": {\n              \"value\": 2.298982700289e-06,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"percentile(spread, 60, 0.9)\": {\n              \"value\": null,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"book\",\n              \"timeframe\": \"1m\",\n              \"bars\": 60,\n              \"sample_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjA0NWQ1MGE0MmE4NzI1NjkifQ\"\n  }\n}\n```\n\n## Real money resting near the mid\n\nIntent: at least one venue has more than two million quote units resting within ten basis points of the mid on the bid side.\n\n```dql\nany(venues where depth_bid_value(10bps) > 2000000)\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"ETH-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"ETHUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"depth_bid_value(0.001)\": {\n              \"value\": 330108.0,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"book\",\n              \"band\": \"10bps\",\n              \"reference\": \"mid\",\n              \"levels\": 4,\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_ETHUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"depth_bid_value(0.001)\": {\n              \"value\": 109996.0,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"book\",\n              \"band\": \"10bps\",\n              \"reference\": \"mid\",\n              \"levels\": 4,\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"ETH-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"depth_bid_value(0.001)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"book\",\n              \"band\": \"10bps\",\n              \"reference\": \"mid\",\n              \"levels\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\n## Choosing the columns, and ordering by two keys\n\nIntent: the instruments where at least two venues answer, the widest funding first and, where that ties, the tighter spread first — and bring back only the three numbers I want.\n\n```dql\nvenues_answered >= 2 select max(venues, funding_8h), min(venues, spread), venues_answered order by max(venues, funding_8h) desc, min(venues, spread) asc\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {\n        \"venues_answered\": {\n          \"value\": 4,\n          \"from\": \"reference\",\n          \"as_of\": \"2026-09-23T12:00:05Z\"\n        },\n        \"max(venues, funding_8h)\": {\n          \"value\": 0.000104,\n          \"unit\": \"fraction\",\n          \"from\": [\n            {\n              \"venue\": \"HYPERLIQUID\",\n              \"value\": 0.000104,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        },\n        \"min(venues, spread)\": {\n          \"value\": 2.298982700289e-06,\n          \"unit\": \"fraction\",\n          \"from\": [\n            {\n              \"venue\": \"OKX-PERP\",\n              \"value\": 2.298982700289e-06,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 2e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            },\n            \"spread\": {\n              \"value\": 1.1495574203931486e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 0.000104,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 2.2985863693828294e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 8e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 2.2988505747126437e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 5.4e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 2.298982700289e-06,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjJhYWQwMDMyMGM4MjFiOTgifQ\"\n  }\n}\n```\n\n## The venue's mark candle, not its trade candle\n\nIntent: compare the last closed hourly **mark** candle with the live mark price.\n\n```dql\nany(venues where mark > mark_close) timeframe 1h\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"timeframe\": \"1h\",\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 86990,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"mark_close\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"price_type\": \"mark\",\n              \"timeframe\": \"1h\",\n              \"bars\": 1,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 87010,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"mark_close\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"price_type\": \"mark\",\n              \"timeframe\": \"1h\",\n              \"bars\": 1,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"not_published\",\n              \"reason\": \"venue_capability\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 87000,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"mark_close\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"price_type\": \"mark\",\n              \"timeframe\": \"1h\",\n              \"bars\": 1,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 86995,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"mark_close\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"price_type\": \"mark\",\n              \"timeframe\": \"1h\",\n              \"bars\": 1,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjIwNWFiZDlmN2QwZTQ2YzQifQ\"\n  }\n}\n```\n\n## Asking for older data on purpose\n\nIntent: a question about yesterday, where a reading a few minutes old is perfectly good.\n\n```dql\nany(venues where oi > 1000) freshness 30m as of 2026-09-20T12:00:00Z\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": \"2026-09-20T12:00:00Z\",\n  \"settled\": true,\n  \"freshness\": {\n    \"ticker\": \"30m\",\n    \"mark\": \"30m\",\n    \"oi\": \"30m\",\n    \"book\": \"30m\",\n    \"stats\": \"30m\",\n    \"funding\": \"30m\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yMFQxMjowMDowMFoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjY0MGUzZjQ5NjgwNDc3MTYifQ\"\n  }\n}\n```\n\n## One venue's own symbol\n\nIntent: the listing a venue calls `BTCUSDT`, whatever DEBYKO calls the instrument.\n\n```dql\nany(venues where mark > 0) where symbol = \"BTCUSDT\"\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 86990,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\n\n\n# The guide\n\n# DEBYKO Query Language — Guide\n\nThis guide teaches the DEBYKO Query Language (DQL) by example. The generated API reference\n(`/v2` in Scalar) lists every endpoint field; the normative language definition is the\nspecification. This document is the tutorial and the cookbook.\n\n> **Every response in this guide was produced by the engine.** They are rendered from a small fixture\n> (`DocumentationFixture`) whose venue codes and symbols are the ones the platform really collects and\n> whose prices are invented, and they are regenerated on every build — so the shape here is the shape\n> you will get, field for field. What is made up is the numbers, never the form, and no page claims a\n> price. The whole answers, including the canonical query each one echoes back, are in `examples.json`\n> beside this file.\n\n---\n\n## 1. What DQL is for\n\nDEBYKO stores what perpetual-futures venues published, when they published it, and when we\nreceived it. DQL is how you ask questions about that store:\n\n- **Screening** — \"which instruments satisfy this condition right now?\" (`POST /v2/screen`)\n- **Screening in the past** — the same question, answered with only what was known at a moment\n  you name (`as of`)\n- **Alerts** — \"call my webhook when this condition becomes true for an instrument\", with a tag\n  you choose in the payload (`POST /v2/rules`)\n\nA DQL query is a **condition**: a yes/no statement about data, written the way you would write a\n`WHERE` clause. Indicators use the names you already know (`ema`, `rsi`, `atr`, `crossover`).\nThere are no variables, loops or scripts — a query is one expression, and the same expression has\nan equivalent JSON form for programs.\n\nThree things make DQL different from other screeners, and they come from how DEBYKO treats data:\n\n1. **Venues stay separate.** There is no \"BTC price\"; there is a BTC price on each venue. Every\n   condition about a venue value says which venues it is about: `any(...)`, `all(...)`,\n   `count(...)` or `max/min/sum(...)`.\n2. **Missing data stays missing.** A venue that has not sent a funding rate has no funding rate —\n   not zero, not yesterday's. A condition on it is neither true nor false; it is *unknown*, and\n   the language has rules for that (§6).\n3. **Everything has an age and a source.** Every value in every response tells you which venue\n   sent it, when we received it and how old it was when the query used it.\n\n---\n\n## 2. Your first query\n\n**Question:** which instruments have a positive funding rate on at least one venue?\n\n```dql\nany(venues where funding > 0)\n```\n\nRead it as: *for this instrument, is there any venue where funding is greater than zero?*\n`funding` on its own would not be a valid query — the language insists you say which venues.\n\nSend it:\n\n```http\nPOST /v2/screen\nContent-Type: application/json\n\n{ \"query\": \"any(venues where funding > 0)\", \"limit\": 2 }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00002,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000013,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00001,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000054,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjdlZjMxMGZmYTMyOTI2ZDEifQ\"\n  }\n}\n```\n\nThings to notice:\n\n- `result` is `\"true\"` for each returned instrument. Instruments where the answer is *unknown* are\n  not returned unless you ask (`\"include_unknown\": true`).\n- Under each instrument, **every listed venue** appears, even the one whose value is missing\n  (OKX-PERP above). That is how you see *why* `any` was true: three venues said yes, one said\n  nothing.\n- Every value carries `venue`, `received_at`, `age_ms` and `status`. There is no bare number\n  anywhere in a DEBYKO response.\n- `next_cursor` continues the **same** evaluation instant, so page two is consistent with page one\n  even though the market moved.\n\n---\n\n## 3. Reading a value\n\n```json\n{ \"value\": 0.0001, \"venue\": \"BYBIT-PERP\", \"layer\": \"funding\",\n  \"venue_ts\": \"2026-09-21T09:30:03.517Z\", \"received_at\": \"2026-09-21T09:30:03.702Z\",\n  \"age_ms\": 1410, \"status\": \"present\" }\n```\n\n| Key | Meaning |\n|---|---|\n| `value` | the number the query used; `null` when there was nothing to use |\n| `venue` | which venue published it |\n| `layer` | the data layer it came from (`funding`, `mark`, `book`, `candles`, …); fields in one layer share a timestamp |\n| `venue_ts` | the venue's own timestamp, when the venue sends one; `null` when it does not |\n| `received_at` | when DEBYKO received it |\n| `age_ms` | `evaluated_at − received_at` (or `as_of − received_at`) |\n| `status` | `present`, `stale`, `missing`, `not_published` or `off` — see §6 |\n| `reason` | only with a null value: `no_value`, `not_retained`, `gap`, `insufficient_history`, `venue_capability`, `policy_off` |\n\nIndicator values add `timeframe`, `bars` (how many candles the number was computed from) and\n`candle_end` (the close time of the newest candle used). Cross-venue aggregates (`max`, `min`,\n`sum`) replace the single venue with a `from` list naming every venue that contributed.\n\nUnits, once:\n\n- Prices are plain numbers in the venue's quote currency (`quote`), never converted.\n- Rates and spreads are **fractions**: `0.0001` is one basis point, `0.01` is one percent. You\n  may write them with a suffix — `1bps`, `0.01%` — and the language turns the suffix into the\n  fraction. `spread < 5bps` and `spread < 0.0005` are the same condition.\n- `funding` is the rate per funding interval **as the venue publishes it**; intervals differ\n  (`1h`, `4h`, `8h`), so `funding_8h` is provided as the same rate scaled to eight hours.\n- Durations are `10s`, `2m`, `1h`, `1d` (one unit, no `1h30m`).\n\n---\n\n## 3a. Saying what the query is about\n\nA condition says *what must be true*. A `where` clause says *which listings to ask at all*, and it is\nthe same clause on every endpoint — screen, snapshots, history, candles, books, stream. It runs first,\nagainst the listing's own identity, and never against a measurement:\n\n```dql\nvenues_answered >= 1 where base = BTC\nvenues_answered >= 1 where instrument in (BTC-PERP, ETH-PERP)\nvenues_answered >= 1 where venue = KRAKEN-FUTURES\nvenues_answered >= 1 where quote = USDT\nvenues_answered >= 1 where symbol = \"BTCUSDT\"\n```\n\nFive things can be named there:\n\n| In the clause | What it is | Written as |\n|---|---|---|\n| `instrument` | the market code DEBYKO normalised the listing to | a code: `BTC-PERP` |\n| `base` | the base asset of that market | a code: `BTC` |\n| `venue` | the venue's **published** code | a code: `KRAKEN-FUTURES`, from `GET /v2/venues` |\n| `quote` | the listing's quote currency | a code: `USDT` |\n| `symbol` | the venue's own name for the listing | a quoted string: `\"BTCUSDT\"` |\n\nA selection may stand alone: `where base = BTC` with no condition means \"every listing of BTC\", which\nis what the data endpoints send. A venue code that no longer exists, or an instrument that never did,\nis an error naming what is known — never an empty answer that looks like \"nothing matched\".\n\nVenue codes come from `GET /v2/venues`, which needs no key:\n\n```json\n{ \"evaluated_at\": \"2026-09-23T08:51:50.944Z\",\n  \"items\": [ { \"venue\": \"KRAKEN-FUTURES\", \"name\": \"Kraken Futures\", \"kind\": \"order_book\",\n               \"listings\": 296, \"listings_collected\": 5, \"since\": \"2026-09-20T15:11:19.524Z\" } ] }\n```\n\n`listings` is what the venue lists; `listings_collected` is what DEBYKO collects today. The two differ\non purpose, and the difference is not hidden.\n\n## 3b. Units, and what a value says about itself\n\nA venue publishes what it publishes: one exchange counts open interest in contracts, another in the\nbase asset. DQL does not guess. You ask for the units you want, and every value tells you what it is.\n\n- `\"units\": \"published\"` (the default) — exactly what the venue published.\n- `\"units\": \"base\"` — converted to base-asset units with the listing's multiplier and contract size.\n\nEvery value in every response carries `unit`: `quote`, `base`, `contracts`, `fraction`, `count` or\n`duration`. Nothing has to be assumed from a field name.\n\nTwo consequences worth knowing before they surprise you:\n\n- Summing a quantity across venues (`sum(venues, oi)`) is **refused** under `units: published` — the\n  sum of Bybit contracts and Kraken contracts is not a number anybody should print. Ask for\n  `units: base` and it is allowed.\n- Under `units: base`, a listing whose multiplier or contract size DEBYKO does not know answers null\n  with reason `unit_unknown` rather than an unconverted number that looks right.\n\nThree response options, while you are here:\n\n- `\"number_format\": \"string\"` returns every number as the venue's own digits in a JSON string, so a\n  price that does not fit a double survives the round trip. `\"json\"` (the default) returns numbers.\n- `\"include_raw\": true` adds the venue's untouched payload for each layer beside the parsed values.\n- `items_sha256` comes back on every data answer: the hash of the items as serialised. Two answers\n  with the same hash are the same answer, which is cheaper to check than a diff.\n\n---\n\n## 4. Cookbook\n\nEach entry gives the intent, the string form, the JSON form, a request and a rendered\nresponse. Responses are shortened to the instruments and venues that make the point; a real\nresponse lists every venue of every returned instrument.\n\n### 4.1 Positive funding on any venue\n\nIntent: instruments with a positive funding rate on at least one venue.\n\n```dql\nany(venues where funding > 0)\n```\n\nCovered in §2, including the JSON form and the full response.\n\n### 4.2 Fresh positive funding on at least three venues\n\nIntent: the funding rate, normalised to eight hours, is above one basis point on three or more\nvenues, and each of those readings is less than two minutes old.\n\n```dql\ncount(venues where funding_8h > 1bps and age(funding) < 2m) >= 3\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"condition\": { \"type\": \"cmp\", \"op\": \">=\",\n  \"left\": { \"type\": \"count\", \"where\": { \"type\": \"and\", \"args\": [\n    { \"type\": \"cmp\", \"op\": \">\", \"left\": { \"type\": \"field\", \"name\": \"funding_8h\" }, \"right\": { \"type\": \"number\", \"value\": 0.0001 } },\n    { \"type\": \"cmp\", \"op\": \"<\", \"left\": { \"type\": \"call\", \"name\": \"age\", \"args\": [ { \"type\": \"field\", \"name\": \"funding\" } ] },\n      \"right\": { \"type\": \"duration\", \"value\": \"2m\" } } ] } },\n  \"right\": { \"type\": \"number\", \"value\": 3 } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"count(venues where funding_8h > 1bps and age(funding) < 2m) >= 3\", \"limit\": 50 }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 0,\n    \"next_cursor\": null\n  }\n}\n```\n\nDYDX-PERP is listed but did not count: its rate is below the threshold. Three venues did, so the\ncondition holds. Note the canonical string in `query.string`: `1bps` became `0.0001`.\n\n### 4.3 Cross-venue mark dispersion\n\nIntent: the highest and lowest mark price across venues differ by more than five basis points of\nthe lowest, and at least three venues are answering.\n\n```dql\n(max(venues, mark) - min(venues, mark)) / min(venues, mark) > 5bps and venues_answered >= 3\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"condition\": { \"type\": \"and\", \"args\": [\n  { \"type\": \"cmp\", \"op\": \">\",\n    \"left\": { \"type\": \"arith\", \"op\": \"/\",\n      \"left\": { \"type\": \"arith\", \"op\": \"-\", \"left\": { \"type\": \"agg\", \"fn\": \"max\", \"expr\": { \"type\": \"field\", \"name\": \"mark\" } },\n                                              \"right\": { \"type\": \"agg\", \"fn\": \"min\", \"expr\": { \"type\": \"field\", \"name\": \"mark\" } } },\n      \"right\": { \"type\": \"agg\", \"fn\": \"min\", \"expr\": { \"type\": \"field\", \"name\": \"mark\" } } },\n    \"right\": { \"type\": \"number\", \"value\": 0.0005 } },\n  { \"type\": \"cmp\", \"op\": \">=\", \"left\": { \"type\": \"field\", \"name\": \"venues_answered\" }, \"right\": { \"type\": \"number\", \"value\": 3 } } ] } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"(max(venues, mark) - min(venues, mark)) / min(venues, mark) > 5bps and venues_answered >= 3\" }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"ETH-PERP\",\n      \"result\": \"true\",\n      \"values\": {\n        \"max(venues, mark)\": {\n          \"value\": 2751,\n          \"unit\": \"quote\",\n          \"from\": [\n            {\n              \"venue\": \"BYBIT-PERP\",\n              \"value\": 2751,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        },\n        \"min(venues, mark)\": {\n          \"value\": 2749,\n          \"unit\": \"quote\",\n          \"from\": [\n            {\n              \"venue\": \"OKX-PERP\",\n              \"value\": 2749,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        },\n        \"venues_answered\": {\n          \"value\": 3,\n          \"from\": \"reference\",\n          \"as_of\": \"2026-09-23T12:00:05Z\"\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"ETHUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 2751,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_ETHUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 2750,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"ETH-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"mark\": {\n              \"value\": 2749,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\nDispersion is `(0.8134 − 0.8119) / 0.8119 ≈ 18.5 bps`. KRAKEN-FUTURES had a mark, but it was\n84 seconds old — older than the 30-second freshness bound — so it was **stale**, excluded from\n`max`/`min`, and not counted in `venues_answered`. The response shows the value's age; it does not\npretend the value is current. Also note that `max`/`min` provenance names the winning venue.\n\n### 4.4 Two named venues\n\nIntent: the mark price on KRAKEN-FUTURES and BYBIT-PERP differs by more than 10 (quote units).\n\n```dql\nmax(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark) - min(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark) > 10\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"condition\": { \"type\": \"cmp\", \"op\": \">\",\n  \"left\": { \"type\": \"arith\", \"op\": \"-\",\n    \"left\":  { \"type\": \"agg\", \"fn\": \"max\", \"expr\": { \"type\": \"field\", \"name\": \"mark\" },\n               \"where\": { \"type\": \"in\", \"left\": { \"type\": \"field\", \"name\": \"venue\" }, \"values\": [ { \"type\": \"code\", \"value\": \"KRAKEN-FUTURES\" }, { \"type\": \"code\", \"value\": \"BYBIT-PERP\" } ] } },\n    \"right\": { \"type\": \"agg\", \"fn\": \"min\", \"expr\": { \"type\": \"field\", \"name\": \"mark\" },\n               \"where\": { \"type\": \"in\", \"left\": { \"type\": \"field\", \"name\": \"venue\" }, \"values\": [ { \"type\": \"code\", \"value\": \"KRAKEN-FUTURES\" }, { \"type\": \"code\", \"value\": \"BYBIT-PERP\" } ] } } },\n  \"right\": { \"type\": \"number\", \"value\": 10 } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"max(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark) - min(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark) > 10\" }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"SOL-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {\n        \"max(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark)\": {\n          \"value\": null,\n          \"unit\": \"quote\",\n          \"from\": [],\n          \"reason\": \"no_value\"\n        },\n        \"min(venues where venue in (KRAKEN-FUTURES, BYBIT-PERP), mark)\": {\n          \"value\": null,\n          \"unit\": \"quote\",\n          \"from\": [],\n          \"reason\": \"no_value\"\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"SOL\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"venue\": {\n              \"value\": \"HYPERLIQUID\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"reference\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T00:00:00Z\",\n              \"age_ms\": 43205000,\n              \"status\": \"present\"\n            },\n            \"mark\": {\n              \"value\": 118,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"mark\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\nThe `where` inside `max(...)` restricts the venues the aggregate looks at; other venues still\nappear in the response because they are part of the instrument, but they did not contribute.\n\n### 4.5 Tight books wherever there is a book\n\nIntent: every venue that publishes an order book has a spread below five basis points. Venues\nthat publish no book (oracle-priced venues) must not make the condition fail.\n\n```dql\nall(venues where status(bid) = not_published or spread < 5bps)\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"condition\": { \"type\": \"all\", \"where\": { \"type\": \"or\", \"args\": [\n  { \"type\": \"cmp\", \"op\": \"=\", \"left\": { \"type\": \"call\", \"name\": \"status\", \"args\": [ { \"type\": \"field\", \"name\": \"bid\" } ] }, \"right\": { \"type\": \"status\", \"value\": \"not_published\" } },\n  { \"type\": \"cmp\", \"op\": \"<\", \"left\": { \"type\": \"field\", \"name\": \"spread\" }, \"right\": { \"type\": \"number\", \"value\": 0.0005 } } ] } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"all(venues where status(bid) = not_published or spread < 5bps)\" }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"status(bid)\": {\n              \"value\": \"present\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 1.1495574203931486e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"status(bid)\": {\n              \"value\": \"present\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 2.2985863693828294e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"status(bid)\": {\n              \"value\": \"present\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 2.2988505747126437e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"status(bid)\": {\n              \"value\": \"present\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            },\n            \"spread\": {\n              \"value\": 2.298982700289e-06,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"book\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImI5ZTY0YzFjZWJmOTkzZmQifQ\"\n  }\n}\n```\n\nWithout the `status(bid) = not_published or` part, a venue that publishes no book would make the\n`all` **unknown** (they have no spread, so `spread < 5bps` is neither true nor false) and ETH would\nnot be returned. §6 explains why.\n\n### 4.6 Trend on hourly candles, any venue\n\nIntent: on at least one venue, the 20-candle EMA of hourly closes is above the 50-candle EMA.\n\n```dql\nany(venues where ema(close, 20) > ema(close, 50)) timeframe 1h\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"timeframe\": \"1h\", \"condition\": { \"type\": \"any\", \"where\": { \"type\": \"cmp\", \"op\": \">\",\n  \"left\":  { \"type\": \"call\", \"name\": \"ema\", \"args\": [ { \"type\": \"source\", \"name\": \"close\" }, { \"type\": \"number\", \"value\": 20 } ] },\n  \"right\": { \"type\": \"call\", \"name\": \"ema\", \"args\": [ { \"type\": \"source\", \"name\": \"close\" }, { \"type\": \"number\", \"value\": 50 } ] } } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"any(venues where ema(close, 20) > ema(close, 50)) timeframe 1h\", \"limit\": 20 }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"timeframe\": \"1h\",\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6ImRkOWI3MzhhMWQzNzY1OTQifQ\"\n  }\n}\n```\n\nTwo details. First, the candle used is the **last completed** hourly candle (`candle_end`\n09:00); the candle that is still forming is never used, so a condition cannot become true and\nthen untrue within the same hour as the price wobbles. Second, `ema(close, 20)` uses exactly 80\ncandles (`bars`), and `ema(close, 50)` exactly 200 — a fixed window, defined in the\nspecification, so you can recompute the number yourself. WEEX-FUTURES had a hole somewhere in\nits last 200 hourly candles, so both EMAs are null there (`reason: gap`); DEBYKO does not fill\nholes, and the other two venues carried the condition.\n\n### 4.7 A cross on the latest closed 15-minute candle, one venue, clean history\n\nIntent: on KRAKEN-FUTURES, the 20-EMA crossed above the 50-EMA on the most recent completed\n15-minute candle, and the last 200 candles have no gaps.\n\n```dql\nany(venues where venue = KRAKEN-FUTURES and crossover(ema(close, 20), ema(close, 50)) and gaps(200) = 0) timeframe 15m\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"timeframe\": \"15m\", \"condition\": { \"type\": \"any\", \"where\": { \"type\": \"and\", \"args\": [\n  { \"type\": \"cmp\", \"op\": \"=\", \"left\": { \"type\": \"field\", \"name\": \"venue\" }, \"right\": { \"type\": \"code\", \"value\": \"KRAKEN-FUTURES\" } },\n  { \"type\": \"call\", \"name\": \"crossover\", \"args\": [\n      { \"type\": \"call\", \"name\": \"ema\", \"args\": [ { \"type\": \"source\", \"name\": \"close\" }, { \"type\": \"number\", \"value\": 20 } ] },\n      { \"type\": \"call\", \"name\": \"ema\", \"args\": [ { \"type\": \"source\", \"name\": \"close\" }, { \"type\": \"number\", \"value\": 50 } ] } ] },\n  { \"type\": \"cmp\", \"op\": \"=\", \"left\": { \"type\": \"call\", \"name\": \"gaps\", \"args\": [ { \"type\": \"number\", \"value\": 200 } ] }, \"right\": { \"type\": \"number\", \"value\": 0 } } ] } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"any(venues where venue = KRAKEN-FUTURES and crossover(ema(close, 20), ema(close, 50)) and gaps(200) = 0) timeframe 15m\" }\n```\n\nIllustrative response (only the named venue is shown; the others are listed in a real response\nwith `venue = KRAKEN-FUTURES` evaluating to false):\n\n```json\n{\n  \"dql\": \"1\",\n  \"query\": { \"string\": \"any(venues where venue = KRAKEN-FUTURES and crossover(ema(close, 20), ema(close, 50)) and gaps(200) = 0) timeframe 15m\", \"json\": { \"…\": \"…\" } },\n  \"evaluated_at\": \"2026-09-21T09:30:05.112Z\", \"as_of\": null, \"settled\": false, \"timeframe\": \"15m\",\n  \"freshness\": { \"ticker\": \"30s\", \"mark\": \"30s\", \"oi\": \"30s\", \"book\": \"30s\", \"stats\": \"120s\", \"funding\": \"300s\" },\n  \"instruments\": [\n    { \"instrument\": \"DOGE\", \"result\": \"true\", \"values\": {},\n      \"venues\": [\n        { \"venue\": \"KRAKEN-FUTURES\", \"symbol\": \"DOGEUSDT\", \"quote\": \"USDT\", \"values\": {\n            \"venue\": { \"value\": \"KRAKEN-FUTURES\", \"venue\": \"KRAKEN-FUTURES\", \"layer\": \"reference\", \"venue_ts\": null, \"received_at\": \"2026-08-30T00:00:12.000Z\", \"age_ms\": 1934393112, \"status\": \"present\" },\n            \"crossover(ema(close, 20), ema(close, 50))\": { \"value\": true, \"venue\": \"KRAKEN-FUTURES\", \"layer\": \"candles\", \"timeframe\": \"15m\", \"bars\": 201, \"candle_end\": \"2026-09-21T09:30:00Z\", \"venue_ts\": \"2026-09-21T09:30:00Z\", \"received_at\": \"2026-09-21T09:30:00.455Z\", \"age_ms\": 4657, \"status\": \"present\" },\n            \"gaps(200)\": { \"value\": 0, \"venue\": \"KRAKEN-FUTURES\", \"layer\": \"candles\", \"timeframe\": \"15m\", \"bars\": 200, \"candle_end\": \"2026-09-21T09:30:00Z\", \"venue_ts\": \"2026-09-21T09:30:00Z\", \"received_at\": \"2026-09-21T09:30:00.455Z\", \"age_ms\": 4657, \"status\": \"present\" } } }\n      ] }\n  ],\n  \"page\": { \"limit\": 100, \"returned\": 1, \"next_cursor\": null }\n}\n```\n\n`crossover(a, b)` means: on the newest completed candle `a > b`, and on the one before it\n`a <= b`. It is a statement about two candles, not a forecast.\n\n### 4.8 Two timeframes in one condition\n\nIntent: hourly trend up (EMA 20 above EMA 50 on 1h candles) while the 15-minute RSI is low.\n\n```dql\nany(venues where ema(close, 20, 1h) > ema(close, 50, 1h) and rsi(close, 14, 15m) < 35)\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"condition\": { \"type\": \"any\", \"where\": { \"type\": \"and\", \"args\": [\n  { \"type\": \"cmp\", \"op\": \">\",\n    \"left\":  { \"type\": \"call\", \"name\": \"ema\", \"args\": [ { \"type\": \"source\", \"name\": \"close\" }, { \"type\": \"number\", \"value\": 20 } ], \"timeframe\": \"1h\" },\n    \"right\": { \"type\": \"call\", \"name\": \"ema\", \"args\": [ { \"type\": \"source\", \"name\": \"close\" }, { \"type\": \"number\", \"value\": 50 } ], \"timeframe\": \"1h\" } },\n  { \"type\": \"cmp\", \"op\": \"<\",\n    \"left\":  { \"type\": \"call\", \"name\": \"rsi\", \"args\": [ { \"type\": \"source\", \"name\": \"close\" }, { \"type\": \"number\", \"value\": 14 } ], \"timeframe\": \"15m\" },\n    \"right\": { \"type\": \"number\", \"value\": 35 } } ] } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"any(venues where ema(close, 20, 1h) > ema(close, 50, 1h) and rsi(close, 14, 15m) < 35)\" }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"rsi(close, 14, 15m)\": {\n              \"value\": null,\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 57,\n              \"candle_end\": \"2026-09-23T12:00:00Z\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:00.300Z\",\n              \"age_ms\": 4700,\n              \"status\": \"present\",\n              \"reason\": \"gap\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"ema(close, 20, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"rsi(close, 14, 15m)\": {\n              \"value\": 88.19612724877551,\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 57,\n              \"candle_end\": \"2026-09-23T12:00:00Z\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:00.300Z\",\n              \"age_ms\": 4700,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"ema(close, 20, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"rsi(close, 14, 15m)\": {\n              \"value\": 88.19612724877551,\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 57,\n              \"candle_end\": \"2026-09-23T12:00:00Z\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:00.300Z\",\n              \"age_ms\": 4700,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"ema(close, 20, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 80,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"ema(close, 50, 1h)\": {\n              \"value\": null,\n              \"unit\": \"quote\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"1h\",\n              \"bars\": 200,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            },\n            \"rsi(close, 14, 15m)\": {\n              \"value\": null,\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"candles\",\n              \"timeframe\": \"15m\",\n              \"bars\": 57,\n              \"candle_end\": null,\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjMxOTVhZGUxMDU2YTFhOWMifQ\"\n  }\n}\n```\n\nWhen every series function carries its own timeframe, the `timeframe` clause is not needed. Mixing\nis fine as long as each function's series is consistent: `crossover(ema(close, 20, 1h),\nema(close, 50, 4h))` is rejected because the two series have different timeframes.\n\n### 4.9 Which instruments have a venue that has gone quiet\n\nIntent: instruments where at least one listed venue is not answering (no fresh mark price).\n\n```dql\nvenues_answered < venues_listed\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"condition\": { \"type\": \"cmp\", \"op\": \"<\", \"left\": { \"type\": \"field\", \"name\": \"venues_answered\" }, \"right\": { \"type\": \"field\", \"name\": \"venues_listed\" } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"venues_answered < venues_listed\", \"limit\": 3 }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 0,\n    \"next_cursor\": null\n  }\n}\n```\n\nThis query references no venue field, so per-venue `values` are empty; add `status(mark)` inside a\nquantifier if you want to see which venue is quiet (next entry).\n\n### 4.10 Stale, missing and not published are three different things\n\nIntent: instruments where at least one venue's funding rate is **stale** — we have a value, but it\nis older than the freshness bound.\n\n```dql\ncount(venues where status(funding) = stale) >= 1\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"condition\": { \"type\": \"cmp\", \"op\": \">=\",\n  \"left\": { \"type\": \"count\", \"where\": { \"type\": \"cmp\", \"op\": \"=\", \"left\": { \"type\": \"call\", \"name\": \"status\", \"args\": [ { \"type\": \"field\", \"name\": \"funding\" } ] }, \"right\": { \"type\": \"status\", \"value\": \"stale\" } } },\n  \"right\": { \"type\": \"number\", \"value\": 1 } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"count(venues where status(funding) = stale) >= 1\", \"limit\": 1 }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"status(funding)\": {\n              \"value\": \"stale\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"status(funding)\": {\n              \"value\": \"present\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": null\n  }\n}\n```\n\nFour situations, one per venue: a reading that arrived a second ago is **present**; one that arrived\neight minutes ago, past the layer's freshness bound, is **stale** — the value comes back with its true\nage, and a comparison treats it as unknown; a layer DEBYKO collects for which nothing has arrived for\nthis listing is **missing**; a field the venue does not publish at all — Hyperliquid's mark candles,\nKraken's funding interval — is **not_published**. A fifth status, **off**, means DEBYKO does not\ncollect that layer for that instrument's group by policy. Only the first counts as data in a\ncomparison.\n\n### 4.11 As of a past moment\n\nIntent: which instruments had positive funding on three or more venues at 08:00 UTC today, using\nonly what DEBYKO had received by then.\n\n```dql\ncount(venues where funding > 0) >= 3 as of 2026-09-21T08:00:00Z\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"as_of\": \"2026-09-21T08:00:00Z\", \"condition\": { \"type\": \"cmp\", \"op\": \">=\",\n  \"left\": { \"type\": \"count\", \"where\": { \"type\": \"cmp\", \"op\": \">\", \"left\": { \"type\": \"field\", \"name\": \"funding\" }, \"right\": { \"type\": \"number\", \"value\": 0 } } },\n  \"right\": { \"type\": \"number\", \"value\": 3 } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"count(venues where funding > 0) >= 3 as of 2026-09-21T08:00:00Z\", \"limit\": 1 }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": \"2026-09-21T08:00:00Z\",\n  \"settled\": true,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 0,\n    \"next_cursor\": null\n  }\n}\n```\n\nNotice the ages: they are measured against 08:00:00, not against now, and they are up to a minute\nbecause funding history is retained once per minute. `settled: true` says the answer will not\nchange if you ask again — the moment is older than the platform's settle window, so nothing is\nstill in flight. Every `received_at` is before 08:00:00; a value received at 08:00:00.100 would not\nbe visible to this query even if the venue stamped it 07:59:59.\n\n### 4.12 Relaxed freshness for a historical question\n\nIntent: a week ago at noon, did any venue show open interest at all — accepting values up to ten\nminutes old.\n\n```dql\nany(venues where oi > 0) freshness 10m as of 2026-09-14T12:00:00Z\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"freshness\": \"10m\", \"as_of\": \"2026-09-14T12:00:00Z\",\n  \"condition\": { \"type\": \"any\", \"where\": { \"type\": \"cmp\", \"op\": \">\", \"left\": { \"type\": \"field\", \"name\": \"oi\" }, \"right\": { \"type\": \"number\", \"value\": 0 } } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"any(venues where oi > 0) freshness 10m as of 2026-09-14T12:00:00Z\", \"limit\": 1 }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": \"2026-09-14T12:00:00Z\",\n  \"settled\": true,\n  \"freshness\": {\n    \"ticker\": \"10m\",\n    \"mark\": \"10m\",\n    \"oi\": \"10m\",\n    \"book\": \"10m\",\n    \"stats\": \"10m\",\n    \"funding\": \"10m\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"unknown\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"oi\": {\n              \"value\": null,\n              \"unit\": \"base\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"oi\",\n              \"venue_ts\": null,\n              \"received_at\": null,\n              \"age_ms\": null,\n              \"status\": \"missing\",\n              \"reason\": \"no_value\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0xNFQxMjowMDowMFoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6Ijg5MDVkMmI1ZmRjNWVhNzEifQ\"\n  }\n}\n```\n\nBybit's reading above was almost eight minutes old; under the default 30-second bound it would have\nbeen stale, under `freshness 10m` it is present — and its true age comes back either way. A venue\nwhose history is kept for a shorter period answers `missing` with reason `not_retained` instead:\nnothing from that day exists any more. The query still runs; it simply cannot see that venue.\n\n### 4.13 Like-for-like quotes only\n\nIntent: dispersion of mark prices above ten basis points, comparing only listings quoted in a USD\nstablecoin or USD.\n\n```dql\nmax(venues where quote in (USDT, USDC, USD), mark) / min(venues where quote in (USDT, USDC, USD), mark) - 1 > 10bps\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\", \"condition\": { \"type\": \"cmp\", \"op\": \">\",\n  \"left\": { \"type\": \"arith\", \"op\": \"-\",\n    \"left\": { \"type\": \"arith\", \"op\": \"/\",\n      \"left\":  { \"type\": \"agg\", \"fn\": \"max\", \"expr\": { \"type\": \"field\", \"name\": \"mark\" }, \"where\": { \"type\": \"in\", \"left\": { \"type\": \"field\", \"name\": \"quote\" }, \"values\": [ { \"type\": \"code\", \"value\": \"USDT\" }, { \"type\": \"code\", \"value\": \"USDC\" }, { \"type\": \"code\", \"value\": \"USD\" } ] } },\n      \"right\": { \"type\": \"agg\", \"fn\": \"min\", \"expr\": { \"type\": \"field\", \"name\": \"mark\" }, \"where\": { \"type\": \"in\", \"left\": { \"type\": \"field\", \"name\": \"quote\" }, \"values\": [ { \"type\": \"code\", \"value\": \"USDT\" }, { \"type\": \"code\", \"value\": \"USDC\" }, { \"type\": \"code\", \"value\": \"USD\" } ] } } },\n    \"right\": { \"type\": \"number\", \"value\": 1 } },\n  \"right\": { \"type\": \"number\", \"value\": 0.001 } } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"max(venues where quote in (USDT, USDC, USD), mark) / min(venues where quote in (USDT, USDC, USD), mark) - 1 > 10bps\", \"limit\": 1 }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 0,\n    \"next_cursor\": null\n  }\n}\n```\n\nDQL never converts currencies. `USDT`, `USDC` and `USD` are three different values of\n`quote`; if you want to treat them as one group, say so in the query, as here. (The comparison page\ngroups them for display; the language does not.)\n\n### 4.14 Ordering the screen\n\nIntent: instruments answering on at least two venues, highest eight-hour funding first.\n\n```dql\nvenues_answered >= 2 order by max(venues, funding_8h) desc\n```\n\nJSON form:\n\n```json\n{ \"dql\": \"1\",\n  \"condition\": { \"type\": \"cmp\", \"op\": \">=\", \"left\": { \"type\": \"field\", \"name\": \"venues_answered\" }, \"right\": { \"type\": \"number\", \"value\": 2 } },\n  \"order_by\": { \"expr\": { \"type\": \"agg\", \"fn\": \"max\", \"expr\": { \"type\": \"field\", \"name\": \"funding_8h\" } }, \"direction\": \"desc\" } }\n```\n\nRequest:\n\n```json\n{ \"query\": \"venues_answered >= 2 order by max(venues, funding_8h) desc\", \"limit\": 3 }\n```\n\nResponse, on the documentation fixture — real venue codes, invented numbers, the query echo dropped:\n\n```json\n{\n  \"dql\": \"1\",\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {\n        \"venues_answered\": {\n          \"value\": 4,\n          \"from\": \"reference\",\n          \"as_of\": \"2026-09-23T12:00:05Z\"\n        },\n        \"max(venues, funding_8h)\": {\n          \"value\": 0.000104,\n          \"unit\": \"fraction\",\n          \"from\": [\n            {\n              \"venue\": \"HYPERLIQUID\",\n              \"value\": 0.000104,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          ]\n        }\n      },\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 2e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 0.000104,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 8e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding_8h\": {\n              \"value\": 5.4e-05,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 1,\n    \"returned\": 1,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkJUQy1QRVJQIiwicSI6IjE0MTk1NWNjMGNhMzliODEifQ\"\n  }\n}\n```\n\nThe ordering key appears in `values` so you can see what the sort used (BTC's venue list is shortened here; a real response lists all fourteen). Instruments whose key is\nnull (no venue had a usable `funding_8h`) sort last, in either direction.\n\n### 4.15 Alerts, with Agent\n\nIntent: be told when, for any instrument, the 20/50 EMA cross happens on hourly candles on a venue\nwith a clean 200-candle history.\n\nThe condition is a query like any other:\n\n```dql\nany(venues where crossover(ema(close, 20), ema(close, 50)) and gaps(200) = 0) timeframe 1h\n```\n\n**The API does not hold alerts.** It answers questions; it does not remember them, does not run them\non a schedule and does not deliver anything to a webhook. That belongs to **Agent**: Agent holds the\nquery, the cadence, the destination and your own tag, calls this API on that cadence, and decides\nwhat a firing means.\n\nThe reason is not architectural tidiness. A saved rule with a webhook makes the data API responsible\nfor delivery, for retries, and — once a rule can be public — for showing somebody's words next to a\nnumber, which is how a data platform ends up looking like it recommends a trade. The language has no\nvocabulary for an action or an opinion (spec §7.5), and now it has no tag to store either.\n\nUntil Agent opens, the same thing is four lines of your own code: run the query on your cadence,\ncompare with the previous answer, act on the difference. Everything the query needs — the canonical\nform to compare against, `items_sha256` to see that nothing changed, `settled` to know the answer may\nstill move — is in the response.\n\n### 4.16 A rate of change on a snapshot field\n\nIntent: the mark price is more than half a per cent above where it stood five minutes ago, on any\nvenue. `mark` is a snapshot field, not a candle, and DQL samples it at the effective timeframe.\n\n```dql\nany(venues where roc(mark, 5) > 0.5%) timeframe 1m\n```\n\nThe samples are the platform's own per-second readings collapsed to the timeframe (spec §7.2a); a\nperiod with nothing retained is a gap, and a gap makes the answer null rather than a smaller number.\n\n### 4.17 A spread that is unusually wide for this venue\n\nIntent: the current spread sits above the 90th percentile of its own last hour — \"wide for this\nvenue\", not \"wide compared with a number I guessed\".\n\n```dql\nany(venues where spread > percentile(spread, 60, 90%)) timeframe 1m\n```\n\n`percentile` takes the nearest rank by default; add `linear` as a fourth argument for interpolation\nbetween the two neighbouring readings.\n\n### 4.18 Real money resting near the mid\n\nIntent: at least one venue has more than two million quote units resting within ten basis points of\nthe mid on the bid side.\n\n```dql\nany(venues where depth_bid_value(10bps) > 2000000)\n```\n\nThe bands are the platform's, not yours: ask `GET /v2/dql/catalogue` for the set. A book that did not\nreach the band's edge answers null with reason `band_truncated` — never the sum of the levels that\nhappened to arrive.\n\n### 4.19 Choosing the columns, and ordering by two keys\n\nIntent: the instruments where at least two venues answer, the widest funding first and, where that\nties, the tighter spread first — and bring back only the three numbers I want.\n\n```dql\nvenues_answered >= 2 select max(venues, funding_8h), min(venues, spread), venues_answered order by max(venues, funding_8h) desc, min(venues, spread) asc\n```\n\n`select` decides what comes back; without it the answer carries every atom the condition touched.\n\n### 4.20 The venue's mark candle, not its trade candle\n\nIntent: compare the last closed hourly **mark** candle with the live mark price.\n\n```dql\nany(venues where mark > mark_close) timeframe 1h\n```\n\nA venue that publishes no mark candles answers `not_published` for `mark_close` — Hyperliquid today —\nand the comparison is unknown for that venue rather than false.\n\n### 4.21 Asking for older data on purpose\n\nIntent: a question about yesterday, where a reading a few minutes old is perfectly good.\n\n```dql\nany(venues where oi > 1000) freshness 30m as of 2026-09-20T12:00:00Z\n```\n\n`freshness` replaces every layer's default bound at once. It does not make stale data fresh: it\nchanges where the line between `present` and `stale` is drawn for this question, and every value\nstill comes back with its true age.\n\n### 4.22 One venue's own symbol\n\nIntent: the listing a venue calls `BTCUSDT`, whatever DEBYKO calls the instrument.\n\n```dql\nany(venues where mark > 0) where symbol = \"BTCUSDT\"\n```\n\n`symbol` is the venue's own string and is quoted; it may appear only in the `where` selection. A bare\ncode there (`symbol = BTCUSDT`) is `DQL_TYPE`, because a symbol is not a code.\n\n## 5. Two ways to write the same query\n\nEvery query has a string form and a JSON form, and they are interchangeable: send either to\n`POST /v2/screen`, and the response contains both, normalised. `POST /v2/dql/parse` converts and\nvalidates without evaluating — useful for editors and for programs that generate queries.\n\n```json\n{ \"query\": \"count(venues where funding_8h > 1bps) >= 3\", \"context\": \"screen\" }\n```\n\nreturns the canonical string (`1bps` becomes `0.0001`), the JSON tree, the list of fields and\nfunctions the query touches, and its complexity score — or a precise error with a position and\na hint. Errors are structured:\n\n```json\n{ \"errors\": [ { \"code\": \"DQL_SCOPE\", \"message\": \"'funding' is venue-scoped at 1:1\",\n                \"position\": { \"line\": 1, \"column\": 1, \"offset\": 0, \"length\": 7 },\n                \"hint\": \"wrap it in any(venues where …), all(…), count(…) or an aggregate\" } ] }\n```\n\n`GET /v2/dql/catalogue` lists every field (with type, unit, layer and which venues do not publish\nit), every function, every venue, currency and timeframe, the freshness defaults and the limits.\nIf you generate queries programmatically, read it first.\n\n---\n\n## 6. Missing data, for humans\n\nA DQL comparison can come out three ways: **true**, **false**, or **unknown**. Unknown means\n\"there was no value to compare\", and it happens more often than in a stock screener because DEBYKO\nrefuses to invent values:\n\n- a venue has not sent a field for a while (**stale**): the last value is shown with its age,\n  but the language will not compare it as if it were current;\n- a venue has never sent the field for this instrument, or its history was not kept that long\n  (**missing**);\n- the venue does not have the field at all — an oracle-priced venue has no order book\n  (**not_published**);\n- DEBYKO does not collect that layer for that instrument group (**off**);\n- an indicator needs 80 candles and one is absent (**gap**), or only 30 exist\n  (**insufficient history**).\n\nThe combining rules are the ones SQL uses for `NULL`:\n\n- `unknown and false` is **false** (one false is enough), `unknown and true` is **unknown**;\n- `unknown or true` is **true** (one true is enough), `unknown or false` is **unknown**;\n- `not unknown` is **unknown**;\n- `any(...)` is true if some venue is true, otherwise unknown if some venue is unknown, otherwise\n  false;\n- `all(...)` is false if some venue is false, otherwise unknown if some venue is unknown,\n  otherwise true;\n- `count(...)` counts only venues that are true, so it is never unknown.\n\nA screen returns instruments where the condition is **true**. A rule fires only on **true**.\nUnknown is silent by default; ask for it with `\"include_unknown\": true` when you are debugging a\ncondition.\n\nWriting conditions that handle it:\n\n| You want | Write |\n|---|---|\n| ignore venues that do not publish the field | `all(venues where status(field) = not_published or <condition>)` |\n| only count venues with fresh data | `count(venues where status(field) = present and <condition>)` |\n| require a minimum number of answering venues | `... and venues_answered >= 3` |\n| treat \"no data\" as a failure of the screen | leave the condition as it is — unknown is already excluded |\n| find the instruments where data quality is the problem | `count(venues where status(field) != present) >= 1` |\n| accept older readings on purpose | `... freshness 10m` |\n\nA useful habit: when a screen returns fewer instruments than you expect, run it once with\n`include_unknown: true` and look at the `status` and `reason` of the values. The answer is always\nin the response.\n\n---\n\n### The two reasons that are about DEBYKO, not about the venue\n\nSeven of the nine reasons say something about the venue or the moment. Two say something about us:\n\n- `unit_unknown` — you asked for `units: base` and we do not know this listing's contract size, so we\n  will not convert. Ask for `units: published` and do the conversion yourself, or tell us the\n  contract rules are missing.\n- `unmapped` — the listing is collected but belongs to no market yet, so it has no `instrument`. It\n  still answers by `venue` and `symbol`; it just cannot be compared with anything.\n\n## 6a. Four mistakes, and what the API says about them\n\nEach of these is rejected before anything is evaluated, with the position and a suggestion. They are\nworth reading once: three of the four are the difference between DQL and the query languages it\nresembles.\n\n**A venue-scoped field on its own.** Which venue's funding? The language will not guess.\n\n```dql-error DQL_SCOPE\nfunding > 0\n```\n\n> `'funding' is venue-scoped; wrap it in any(venues where …), all(…), count(…) or an aggregate`\n\n**A series without a period.** `ema` over what candles?\n\n```dql-error DQL_TIMEFRAME_REQUIRED\nany(venues where ema(close, 20) > 0)\n```\n\n> add `timeframe 1h`, or write the period into the call: `ema(close, 20, 1h)`\n\n**A period the platform does not keep.**\n\n```dql-error DQL_TIMEFRAME_UNSUPPORTED\nany(venues where ema(close, 20) > 0) timeframe 7m\n```\n\n> `timeframe '7m' is not supported; supported: 1m, 2m, 3m, 5m, 15m, 30m, 1h, 4h, 12h, 1d`\n\n**A venue's symbol written as a code.** `symbol` is the venue's own string, so it is quoted.\n\n```dql-error DQL_TYPE\nany(venues where mark > 0) where symbol = BTCUSDT\n```\n\n> `symbol takes a quoted string`\n\n## 7. Coming from Pine Script\n\nDQL borrows indicator names, nothing else. Pine is a scripting language that runs bar by bar over\na chart; DQL is a single condition evaluated over many instruments and venues at one instant.\n\n| In Pine you write | In DQL you write | Note |\n|---|---|---|\n| `ta.ema(close, 20)` | `ema(close, 20)` | no `ta.` prefix; fixed 80-candle window with SMA seed (see spec §7.3) |\n| `close` | `close` | the last **completed** candle; the forming candle is never used |\n| `close[1]` | `prev(close, 1)` | no `[]` operator |\n| `ta.crossover(a, b)` | `crossover(a, b)` | same meaning: `a > b` now and `a <= b` one candle earlier |\n| `ta.rsi(close, 14)` | `rsi(close, 14)` | Wilder smoothing, fixed 56-change window |\n| `ta.atr(14)` | `atr(14)` | same |\n| chart timeframe | `timeframe 15m` clause, or `ema(close, 20, 15m)` | no implicit timeframe |\n| `request.security(...)` | trailing timeframe argument per function | several timeframes in one condition |\n| `and or not` | `and or not` | same words; `not` binds below comparisons (`not a > b` is `not (a > b)`) |\n| `==` `!=` | `=` `!=` (`==` and `<>` accepted) | |\n| `na(x)` | `status(x) != present` | five statuses instead of one `na` |\n| `nz(x, 0)` | — | deliberately absent; missing is never zero |\n| `ta.percentile_nearest_rank(S, n, p)` | `percentile(S, n, p)` | and `percentile(S, n, p, linear)` for interpolation |\n| `math.abs(x)` | `abs(x)` | element-wise over a series |\n| `math.sum(S, n)` | `rolling_sum(S, n)` | |\n| a script per symbol, switched by hand | `where base = BTC`, `where venue = KRAKEN-FUTURES`, `where symbol = \"BTCUSDT\"` | selection is part of the query |\n| `input`, `var`, `:=`, `if`, `for`, `plot`, `strategy.*`, `alertcondition` | — | not a scripting language |\n| one symbol per script | `any(venues where ...)`, `all(...)`, `count(...)`, `max(venues, ...)` | every venue value needs a venue scope |\n\nNumbers will not match TradingView exactly. TradingView's EMA depends on how much chart history\nis loaded; DQL's uses a fixed window so that anyone can recompute it from public candles.\n\n## 8. Coming from SQL\n\nThink of a table with one row per (instrument, venue). A DQL condition is a `WHERE` clause over\nthat table, grouped by instrument.\n\n| In SQL you write | In DQL you write | Note |\n|---|---|---|\n| `WHERE funding > 0` | `any(venues where funding > 0)` | the group-by is built in; say which rows |\n| `HAVING COUNT(*) FILTER (WHERE funding > 0) >= 3` | `count(venues where funding > 0) >= 3` | |\n| `HAVING MAX(mark) - MIN(mark) > 5` | `max(venues, mark) - min(venues, mark) > 5` | |\n| `MAX(mark) FILTER (WHERE quote = 'USDT')` | `max(venues where quote = USDT, mark)` | codes are unquoted, uppercase |\n| `venue IN ('KRAKEN-FUTURES', 'BYBIT-PERP')` | `venue in (KRAKEN-FUTURES, BYBIT-PERP)` | |\n| `funding IS NULL` | `status(funding) != present` | and the status tells you *why* |\n| `NULL` semantics in `AND`/`OR`/`NOT` | identical | three-valued logic |\n| `AVG(mark)` | — | deliberately absent: venues are never averaged |\n| `SUM(oi)` | `sum(venues, oi)` | only additive quantities can be summed |\n| `AS OF SYSTEM TIME '...'` | `as of 2026-09-21T08:00:00Z` | visibility by `received_at`, not by venue timestamp |\n| `ORDER BY x DESC LIMIT 50` | `order by x desc` in the query, `\"limit\": 50` in the request | |\n| `WHERE base = 'BTC'` (choosing rows before aggregating) | the `where` **clause**: `… where base = BTC` | selection and condition are separate; the clause runs first |\n| `SELECT a, b, c` | `select max(venues, funding_8h), min(venues, spread)` | chooses what comes back, not what is compared |\n| `ORDER BY a DESC, b ASC` | `order by max(venues, funding_8h) desc, min(venues, spread) asc` | several keys, C1-06 |\n| `WHERE symbol = 'BTCUSDT'` | `where symbol = \"BTCUSDT\"` | the venue's own symbol is a quoted string, not a code |\n| `SUM(oi)` across venues with mixed contract sizes | `sum(venues, oi)` with `units: base` | refused under `units: published`, because contracts do not add up |\n| `LIKE`, joins, subqueries, `CASE` | — | not in the language |\n\nKeywords are lowercase (`and`, not `AND`); uppercase words are venue, currency and asset codes.\n\n---\n\n## 9. What DQL deliberately does not do\n\n- **It does not express actions or opinions.** There is no `buy`, `sell`, `long`, `short`,\n  `signal`, `entry`, `exit`, `strength` or `confidence` anywhere in the language, and there will\n  not be. `ema(close, 20) > ema(close, 50)` is a statement about two numbers; what you do with it\n  is not DEBYKO's business. The alert tag is text you choose; DEBYKO stores it, sends it back, and\n  never reads it. This keeps DEBYKO a data service, and it keeps your rules yours.\n- **It does not blend venues.** No average price, no consensus price, no \"best\" price. You can\n  ask for the maximum, the minimum, the count, the sum, or any single venue.\n- **It does not fill gaps.** A missing candle stays missing and an indicator over it is null. If\n  you want indicators that tolerate holes, you have all the candles via `/v1/candles` and can\n  compute your own.\n- **It does not convert currencies.** A price is a number in the venue's quote currency.\n- **It does not run code.** No variables, loops, user-defined functions or state. A query is one\n  condition. If you need more, the data endpoints are there.\n- **It does not let you see the future.** `as of` uses only what had been received by that\n  moment, including candles that had not yet arrived.\n\nNothing in a response is a forecast, a rating or advice. Every number is something a venue\npublished, or an arithmetic function of such numbers defined in the specification, with the\nvenue, the receipt time and the age attached.\n\n---\n\n## 10. Every function, with one example\n\nOne runnable query per function, the function's name visible in the query itself. Every line here is\nrun by `GuideExampleTests` against the conformance fixture, so an example that stops working fails\nthe build instead of sitting here misleading you.\n\nSeries functions — all need a period, from the `timeframe` clause or a trailing argument:\n\n```dql\nany(venues where close > prev(close, 1)) timeframe 15m\nany(venues where close > sma(close, 20)) timeframe 15m\nany(venues where ema(close, 20) > ema(close, 50)) timeframe 1h\nany(venues where rsi(close, 14) < 30) timeframe 1h\nany(venues where atr(14) > 100) timeframe 15m\nany(venues where stdev(close, 20) > 50) timeframe 15m\nany(venues where close >= highest(close, 50)) timeframe 15m\nany(venues where close <= lowest(close, 50)) timeframe 15m\nany(venues where change(close, 10) > 0) timeframe 15m\nany(venues where roc(close, 12) > 1%) timeframe 5m\nany(venues where crossover(close, sma(close, 3))) timeframe 15m\nany(venues where crossunder(sma(close, 3), close)) timeframe 15m\nany(venues where gaps(100) = 0) timeframe 15m\nany(venues where abs(change(close, 5)) > 100) timeframe 15m\nany(venues where rolling_sum(volume, 12) > 1000) timeframe 5m\nany(venues where close > percentile(close, 100, 95%)) timeframe 15m\nany(venues where close > percentile(close, 100, 95%, linear)) timeframe 15m\nany(venues where percentile_rank(close, 100) > 0.8) timeframe 15m\n```\n\nData quality — these two are the reason the language exists:\n\n```dql\nany(venues where age(mark) < 5s)\nany(venues where status(funding) = stale)\n```\n\nBook depth — the bands are the platform's, from `GET /v2/dql/catalogue`:\n\n```dql\nany(venues where depth_bid(10bps) > 5)\nany(venues where depth_ask(10bps) > 5)\nany(venues where depth_bid_value(10bps) > 250000)\nany(venues where depth_ask_value(10bps) > 250000)\n```\n\n## 11. Every field, with one example\n\nThe instrument, and the two counts that say how many venues answered:\n\n```dql\nvenues_answered >= 2 where instrument = BTC-PERP\nvenues_answered >= 2 where base = BTC\nvenues_listed >= 3\nvenues_answered < venues_listed\n```\n\nThe listing — what a venue calls it and what its contract rules are:\n\n```dql\nany(venues where venue = KRAKEN-FUTURES and mark > 0)\nany(venues where quote = USDT and mark > 0)\nvenues_answered >= 1 where symbol = \"BTCUSDT\"\nany(venues where tick_size <= 0.1)\nany(venues where lot_size <= 0.001)\nany(venues where min_qty <= 0.001)\n```\n\nWhat the venue publishes, layer by layer:\n\n```dql\nany(venues where last > 0)\nmax(venues, mark) - min(venues, mark) > 5bps\nany(venues where index > 0)\nany(venues where basis > 10bps)\nany(venues where funding > 0)\nany(venues where funding_interval = 8h)\nany(venues where funding_8h > 1bps)\nany(venues where time_to_funding < 30m)\nsum(venues, oi) > 10000\nany(venues where ask - bid > 0)\nany(venues where mid > 0)\nall(venues where status(bid) = not_published or spread < 5bps)\nany(venues where bid_size > 1 and ask_size > 1)\nany(venues where volume_24h > 10000)\nany(venues where turnover_24h > 100000000)\nany(venues where change_24h < -1%)\n```\n\nCandles. Trade candles are `open high low close volume`; the venue's mark and index candles carry the\nsame five names with a prefix. A venue that publishes no mark candle answers `not_published` for every\n`mark_*` source rather than repeating its trade candle:\n\n```dql\nany(venues where high - low > 0 and close > open) timeframe 1h\nany(venues where volume > 0) timeframe 1h\nany(venues where mark_high - mark_low > 0 and mark_close > mark_open) timeframe 1h\nany(venues where mark_volume >= 0) timeframe 1h\nany(venues where index_high - index_low > 0 and index_close > index_open) timeframe 1h\nany(venues where index_volume >= 0) timeframe 1h\n```\n\n\n# The endpoints\n\nTen endpoints. Four need no key.\n\n| endpoint | key | what it answers |\n| --- | --- | --- |\n| [`GET /v2/venues`](#getv2venues) | — | Every venue in DQL, with how many listings it has and how many of them the platform collects. |\n| [`GET /v2/instruments`](#getv2instruments) | — | Every selected listing: how its venue names it, the rules it trades under, and what is collected for it. |\n| [`GET /v2/dql/catalogue`](#getv2dqlcatalogue) | — | Every field, source, function, code and limit a query may use. |\n| [`POST /v2/dql/parse`](#postv2dqlparse) | — | A query checked but not run: what it means, what it reads, what it costs. |\n| [`POST /v2/screen`](#postv2screen) | yes | Run a DQL query across venues and return what matched. |\n| [`POST /v2/snapshots`](#postv2snapshots) | yes | The latest reading of each layer for the selected listings. |\n| [`POST /v2/snapshots/history`](#postv2snapshotshistory) | yes | The same snapshot as it stood in the past: one row per period, per named instant, or per message as it arrived. |\n| [`POST /v2/candles`](#postv2candles) | yes | Completed candles, in any stored period and price type. |\n| [`POST /v2/books`](#postv2books) | yes | Order books to the depth the plan allows, with the depth resting in each band around the mid. |\n| [`GET /v2/stream`](#getv2stream) | yes | A live stream of the selected listings, as server-sent events. |\n\nEvery one of them refuses in the same shape — a list of errors with a stable `code` — and every one of\nthem takes the same selection grammar in `where`. The full schemas are in\n[the reference](#reference); what follows is the shape of each in prose.\n\n## GET /v2/venues\n\nEvery venue in DQL, with how many listings it has and how many of them the platform collects.\n\nRead it before anything else: a venue that is not here cannot be named in a query, and the gap between `listings` and `listings_collected` is the coverage you actually have.\n\n**No key.** What exists is not a paid fact.\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n| `evaluated_at` | `Instant` |  |\n| `items` | array | The venues, by public code. |\n\n### An answer\n\n```json\n{\n  \"evaluated_at\": \"2026-09-23T11:28:26.904Z\",\n  \"items\": [\n    {\n      \"venue\": \"HYPERLIQUID\",\n      \"name\": \"Hyperliquid\",\n      \"kind\": \"order_book\",\n      \"listings\": 234,\n      \"listings_collected\": 5,\n      \"since\": \"2026-09-21T12:03:13.315Z\"\n    }\n  ],\n  \"items_note\": \"1 more, cut here for length\"\n}\n```\n\n## GET /v2/instruments\n\nEvery selected listing: how its venue names it, the rules it trades under, and what is collected for it.\n\nThis is where a bot learns the exchange's own symbol for an instrument, its tick and lot size, and which layers exist for it. `?where=` takes the same selection grammar as everything else.\n\n**No key.** What exists is not a paid fact.\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n| `evaluated_at` | `Instant` |  |\n| `as_of` | `Instant` | The instant the answer describes: the moment of the request, or the `as_of` it asked for. |\n| `catalogue` | string | The catalogue version the answer was built against. |\n| `units` | `published`, `base`, `quote` | The unit mode applied. |\n| `listings_as_of` | `NullableInstant` | When the listing set itself was last known to change. Present when asking about the past. |\n| `capabilities_as_of` | `NullableInstant` | When what each venue publishes was last known to change. |\n| `items` | array | The listings, one object each. |\n\n### An answer\n\n```json\n{\n  \"evaluated_at\": \"2026-09-23T11:28:27.118Z\",\n  \"as_of\": \"2026-09-23T11:28:27.118Z\",\n  \"catalogue\": \"2026-09-22\",\n  \"units\": \"published\",\n  \"items\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"venue\": \"HYPERLIQUID\",\n      \"venue_symbol\": \"BTC\",\n      \"base\": \"BTC\",\n      \"base_venue_alias\": null,\n      \"quote\": \"USDC\",\n      \"kind\": \"perpetual\",\n      \"venue_kind\": null,\n      \"pair\": null,\n      \"status\": \"tradeable\",\n      \"post_only\": null,\n      \"contract_size\": 1,\n      \"multiplier\": 1,\n      \"tick_size\": null,\n      \"lot_size\": null,\n      \"min_qty\": null,\n      \"min_notional\": null,\n      \"price_decimals\": null,\n      \"qty_decimals\": 5,\n      \"units\": {\n        \"tick_size\": \"quote\",\n        \"lot_size\": \"base\",\n        \"min_qty\": \"base\",\n        \"min_notional\": \"quote\"\n      },\n      \"funding_interval\": \"1h\",\n      \"funding_interval_source\": \"venue\",\n      \"funding_normalisation\": {\n        \"venue_field\": \"funding\",\n        \"transform\": \"identity\"\n      },\n      \"rules_normalisation\": {\n        \"funding_interval\": {\n          \"venue_field\": \"fundingIntervalHours\",\n          \"transform\": \"hours_to_duration\"\n        },\n        \"qty_decimals\": {\n          \"venue_field\": \"szDecimals\",\n          \"transform\": \"identity\"\n        }\n      },\n      \"candles\": {\n        \"base_timeframe\": \"1m\",\n        \"price_types\": [\n          \"trade\"\n        ],\n        \"timeframes\": [\n          \"1m\",\n          \"2m\",\n          \"3m\",\n          \"5m\",\n          \"15m\",\n          \"30m\",\n          \"1h\",\n          \"4h\",\n          \"12h\",\n          \"1d\"\n        ]\n      },\n      \"layers\": {\n        \"ticker\": {\n          \"policy\": \"on\",\n          \"cadence\": \"live\"\n        },\n        \"mark\": {\n          \"policy\": \"on\",\n          \"cadence\": \"live\"\n        },\n        \"funding\": {\n          \"policy\": \"on\",\n          \"cadence\": \"live\"\n        },\n        \"oi\": {\n          \"policy\": \"on\",\n          \"cadence\": \"live\"\n        },\n        \"book\": {\n          \"policy\": \"on\",\n          \"cadence\": \"live\"\n        },\n        \"stats\": {\n          \"policy\": \"on\",\n          \"cadence\": \"live\"\n        },\n        \"candles\": {\n          \"policy\": \"on\",\n          \"cadence\": \"live\"\n        },\n        \"trades\": {\n          \"policy\": \"on\",\n          \"cadence\": \"live\"\n        },\n        \"book_bands\": {\n          \"policy\": \"on\",\n          \"cadence\": \"live\"\n        }\n      },\n      \"not_published\": [\n        \"change_24h\",\n        \"index_close\",\n        \"index_high\",\n        \"index_low\",\n        \"index_open\",\n        \"index_volume\",\n        \"mark_close\",\n        \"mark_high\",\n        \"mark_low\",\n        \"mark_open\",\n        \"mark_volume\"\n      ],\n      \"bands\": [\n        \"10bps\",\n        \"25bps\",\n        \"50bps\",\n        \"100bps\"\n      ],\n      \"listed_at\": null,\n      \"first_seen_at\": \"2026-09-21T20:05:09.829Z\",\n      \"delisted_at\": null,\n      \"venue_ts\": null,\n      \"received_at\": \"2026-09-23T11:20:39.343Z\",\n      \"age_ms\": 467774\n    }\n  ],\n  \"items_note\": \"1 more, cut here for length\"\n}\n```\n\n## GET /v2/dql/catalogue\n\nEvery field, source, function, code and limit a query may use.\n\nRead this rather than hard-coding a list. It is generated from the registry and the policy the collectors run on, so it changes the moment the platform does.\n\n**No key.** What exists is not a paid fact.\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n| `dql` | string | The language version this catalogue describes. |\n| `catalogue` | string | A version that changes whenever the catalogue's content does. Cache against it. |\n| `evaluated_at` | `Instant` |  |\n| `fields` | array | Every field. |\n| `sources` | array | Every candle source. |\n| `functions` | array | Every function. |\n| `venues` | array | Every venue code a query may name. |\n| `currencies` | array | Every quote currency. DQL never converts between them. |\n| `assets` | array | Every base asset. |\n| `instruments` | array | Every instrument code. |\n| `timeframes` | array | Every period a series may be read at. |\n| `bands` | array | Every price band the depth functions accept. |\n| `freshness_defaults` | object | The default freshness bound per layer. A reading older than its bound is stale and compares as unknown. |\n| `limits` | `CatalogueLimits` |  |\n| `settle_after` | integer | Seconds after which an instant is settled: late arrivals can no longer change an answer about it. |\n| `earliest_retained` | `NullableInstant` | The earliest instant any query may ask about. |\n| `units` | array | The unit modes a request may ask for. |\n| `number_formats` | array | The number formats a request may ask for. |\n\n### An answer\n\n```json\n{\n  \"dql\": \"1\",\n  \"catalogue\": \"2026-09-22\",\n  \"evaluated_at\": \"2026-09-23T11:28:26.994Z\",\n  \"fields\": [\n    {\n      \"name\": \"instrument\",\n      \"type\": \"code\",\n      \"scope\": \"instrument\",\n      \"layer\": \"reference\",\n      \"unit\": \"code\",\n      \"description\": \"the market code, e.g. BTC-PERP\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"base\",\n      \"type\": \"code\",\n      \"scope\": \"instrument\",\n      \"layer\": \"reference\",\n      \"unit\": \"code\",\n      \"description\": \"the base asset\\u0027s registry code, e.g. BTC\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"venues_listed\",\n      \"type\": \"number\",\n      \"scope\": \"instrument\",\n      \"layer\": \"reference\",\n      \"unit\": \"count\",\n      \"description\": \"number of (selected) listings at T\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"venues_answered\",\n      \"type\": \"number\",\n      \"scope\": \"instrument\",\n      \"layer\": \"reference\",\n      \"unit\": \"count\",\n      \"description\": \"number of (selected) listings whose mark is present at T\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"venue\",\n      \"type\": \"code\",\n      \"scope\": \"venue\",\n      \"layer\": \"reference\",\n      \"unit\": \"code\",\n      \"description\": \"the venue\\u0027s public code\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"quote\",\n      \"type\": \"code\",\n      \"scope\": \"venue\",\n      \"layer\": \"reference\",\n      \"unit\": \"code\",\n      \"description\": \"the listing\\u0027s quote currency\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"tick_size\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"reference\",\n      \"unit\": \"quote\",\n      \"description\": \"minimum price increment of the listing\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"lot_size\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"reference\",\n      \"unit\": \"quantity\",\n      \"description\": \"minimum quantity increment\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"min_qty\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"reference\",\n      \"unit\": \"quantity\",\n      \"description\": \"minimum order quantity\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"last\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"ticker\",\n      \"unit\": \"quote\",\n      \"description\": \"last trade price\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"mark\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"mark\",\n      \"unit\": \"quote\",\n      \"description\": \"venue mark price\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"index\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"mark\",\n      \"unit\": \"quote\",\n      \"description\": \"venue index price\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"basis\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"mark\",\n      \"unit\": \"fraction\",\n      \"description\": \"(mark \\u2212 index) / index\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"funding\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"funding\",\n      \"unit\": \"fraction\",\n      \"description\": \"published rate for the next settlement, per interval\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"funding_interval\",\n      \"type\": \"duration\",\n      \"scope\": \"venue\",\n      \"layer\": \"funding\",\n      \"unit\": \"ms\",\n      \"description\": \"settlement interval as published\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": [\n        \"KRAKEN-FUTURES\"\n      ]\n    },\n    {\n      \"name\": \"funding_8h\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"funding\",\n      \"unit\": \"fraction\",\n      \"description\": \"funding \\u00D7 8h / funding_interval\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": [\n        \"KRAKEN-FUTURES\"\n      ]\n    },\n    {\n      \"name\": \"time_to_funding\",\n      \"type\": \"duration\",\n      \"scope\": \"venue\",\n      \"layer\": \"funding\",\n      \"unit\": \"ms\",\n      \"description\": \"next_funding_at \\u2212 T\",\n      \"sampleable\": false,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"oi\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"oi\",\n      \"unit\": \"quantity\",\n      \"description\": \"open interest\",\n      \"sampleable\": true,\n      \"additive\": true,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"bid\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"quote\",\n      \"description\": \"best bid price\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"ask\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"quote\",\n      \"description\": \"best ask price\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"mid\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"quote\",\n      \"description\": \"(bid \\u002B ask) / 2\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"spread\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"fraction\",\n      \"description\": \"(ask \\u2212 bid) / mid\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"bid_size\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"quantity\",\n      \"description\": \"resting quantity at the best bid\",\n      \"sampleable\": true,\n      \"additive\": true,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"ask_size\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"quantity\",\n      \"description\": \"resting quantity at the best ask\",\n      \"sampleable\": true,\n      \"additive\": true,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"volume_24h\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"stats\",\n      \"unit\": \"quantity\",\n      \"description\": \"rolling 24h traded volume as published\",\n      \"sampleable\": true,\n      \"additive\": true,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"turnover_24h\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"stats\",\n      \"unit\": \"quote\",\n      \"description\": \"rolling 24h traded value as published\",\n      \"sampleable\": true,\n      \"additive\": true,\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"change_24h\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"stats\",\n      \"unit\": \"fraction\",\n      \"description\": \"24h price change as published\",\n      \"sampleable\": true,\n      \"additive\": false,\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    }\n  ],\n  \"sources\": [\n    {\n      \"name\": \"open\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"trade\",\n      \"unit\": \"quote\",\n      \"description\": \"trade candle open\",\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"high\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"trade\",\n      \"unit\": \"quote\",\n      \"description\": \"trade candle high\",\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"low\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"trade\",\n      \"unit\": \"quote\",\n      \"description\": \"trade candle low\",\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"close\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"trade\",\n      \"unit\": \"quote\",\n      \"description\": \"trade candle close\",\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"volume\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"trade\",\n      \"unit\": \"quantity\",\n      \"description\": \"trade candle volume\",\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"mark_open\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"mark\",\n      \"unit\": \"quote\",\n      \"description\": \"mark-price candle open\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    },\n    {\n      \"name\": \"mark_high\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"mark\",\n      \"unit\": \"quote\",\n      \"description\": \"mark-price candle high\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    },\n    {\n      \"name\": \"mark_low\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"mark\",\n      \"unit\": \"quote\",\n      \"description\": \"mark-price candle low\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    },\n    {\n      \"name\": \"mark_close\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"mark\",\n      \"unit\": \"quote\",\n      \"description\": \"mark-price candle close\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    },\n    {\n      \"name\": \"mark_volume\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"mark\",\n      \"unit\": \"quantity\",\n      \"description\": \"mark-price candle volume as published\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    },\n    {\n      \"name\": \"index_open\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"index\",\n      \"unit\": \"quote\",\n      \"description\": \"index-price candle open\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    },\n    {\n      \"name\": \"index_high\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"index\",\n      \"unit\": \"quote\",\n      \"description\": \"index-price candle high\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    },\n    {\n      \"name\": \"index_low\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"index\",\n      \"unit\": \"quote\",\n      \"description\": \"index-price candle low\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    },\n    {\n      \"name\": \"index_close\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"index\",\n      \"unit\": \"quote\",\n      \"description\": \"index-price candle close\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    },\n    {\n      \"name\": \"index_volume\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"price_type\": \"index\",\n      \"unit\": \"quantity\",\n      \"description\": \"index-price candle volume as published\",\n      \"not_published_on\": [\n        \"HYPERLIQUID\"\n      ]\n    }\n  ],\n  \"functions\": [\n    {\n      \"name\": \"prev\",\n      \"signature\": \"prev(S, k)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"S[k]\"\n    },\n    {\n      \"name\": \"sma\",\n      \"signature\": \"sma(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"simple moving average\"\n    },\n    {\n      \"name\": \"ema\",\n      \"signature\": \"ema(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"exponential moving average over a fixed 4n window\"\n    },\n    {\n      \"name\": \"rsi\",\n      \"signature\": \"rsi(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"relative strength index, Wilder smoothing over 4n\"\n    },\n    {\n      \"name\": \"atr\",\n      \"signature\": \"atr(n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"average true range of the trade candles\"\n    },\n    {\n      \"name\": \"stdev\",\n      \"signature\": \"stdev(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"population standard deviation\"\n    },\n    {\n      \"name\": \"highest\",\n      \"signature\": \"highest(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"max(S[0] \\u2026 S[n\\u22121])\"\n    },\n    {\n      \"name\": \"lowest\",\n      \"signature\": \"lowest(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"min(S[0] \\u2026 S[n\\u22121])\"\n    },\n    {\n      \"name\": \"change\",\n      \"signature\": \"change(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"S[0] \\u2212 S[n]\"\n    },\n    {\n      \"name\": \"roc\",\n      \"signature\": \"roc(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"(S[0] \\u2212 S[n]) / S[n]\"\n    },\n    {\n      \"name\": \"crossover\",\n      \"signature\": \"crossover(A, B)\",\n      \"type\": \"boolean\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"A[0] \\u003E B[0] and A[1] \\u2264 B[1]\"\n    },\n    {\n      \"name\": \"crossunder\",\n      \"signature\": \"crossunder(A, B)\",\n      \"type\": \"boolean\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"A[0] \\u003C B[0] and A[1] \\u2265 B[1]\"\n    },\n    {\n      \"name\": \"gaps\",\n      \"signature\": \"gaps(n)\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"missing periods among the last n\"\n    },\n    {\n      \"name\": \"abs\",\n      \"signature\": \"abs(x)\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"\",\n      \"unit\": \"none\",\n      \"description\": \"|x|, element-wise for series\"\n    },\n    {\n      \"name\": \"rolling_sum\",\n      \"signature\": \"rolling_sum(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"S[n\\u22121] \\u002B \\u2026 \\u002B S[0]\"\n    },\n    {\n      \"name\": \"percentile\",\n      \"signature\": \"percentile(S, n, p, [method])\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"nearest-rank (default) or linear percentile of S[0] \\u2026 S[n\\u22121]\"\n    },\n    {\n      \"name\": \"percentile_rank\",\n      \"signature\": \"percentile_rank(S, n)\",\n      \"type\": \"series\",\n      \"scope\": \"venue\",\n      \"layer\": \"candles\",\n      \"unit\": \"none\",\n      \"description\": \"share of S[0] \\u2026 S[n\\u22121] that are \\u2264 S[0]\"\n    },\n    {\n      \"name\": \"age\",\n      \"signature\": \"age(F)\",\n      \"type\": \"duration\",\n      \"scope\": \"venue\",\n      \"layer\": \"\",\n      \"unit\": \"none\",\n      \"description\": \"T \\u2212 received_at of the value used for F\"\n    },\n    {\n      \"name\": \"status\",\n      \"signature\": \"status(F)\",\n      \"type\": \"status\",\n      \"scope\": \"venue\",\n      \"layer\": \"\",\n      \"unit\": \"none\",\n      \"description\": \"state of F\\u0027s layer at T\"\n    },\n    {\n      \"name\": \"depth_bid\",\n      \"signature\": \"depth_bid(band)\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"quantity\",\n      \"description\": \"bid quantity within band of mid\",\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"depth_ask\",\n      \"signature\": \"depth_ask(band)\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"quantity\",\n      \"description\": \"ask quantity within band of mid\",\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"depth_bid_value\",\n      \"signature\": \"depth_bid_value(band)\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"quote\",\n      \"description\": \"bid value (price \\u00D7 size) within band of mid\",\n      \"not_published_on\": []\n    },\n    {\n      \"name\": \"depth_ask_value\",\n      \"signature\": \"depth_ask_value(band)\",\n      \"type\": \"number\",\n      \"scope\": \"venue\",\n      \"layer\": \"book\",\n      \"unit\": \"quote\",\n      \"description\": \"ask value (price \\u00D7 size) within band of mid\",\n      \"not_published_on\": []\n    }\n  ],\n  \"venues\": [\n    \"HYPERLIQUID\",\n    \"KRAKEN-FUTURES\"\n  ],\n  \"currencies\": [\n    \"USD\",\n    \"USDC\"\n  ],\n  \"assets\": [\n    \"\",\n    \"BTC\",\n    \"CYPH\",\n    \"DOGE\",\n    \"ETH\",\n    \"GTLB\",\n    \"KSTR\",\n    \"MSTU\",\n    \"OURA\",\n    \"SOL\",\n    \"XRP\"\n  ],\n  \"instruments\": [\n    \"-PERP\"\n  ],\n  \"timeframes\": [\n    \"1m\",\n    \"2m\",\n    \"3m\",\n    \"5m\",\n    \"15m\",\n    \"30m\",\n    \"1h\",\n    \"4h\",\n    \"12h\",\n    \"1d\"\n  ],\n  \"bands\": [\n    \"10bps\",\n    \"25bps\",\n    \"50bps\",\n    \"100bps\"\n  ],\n  \"freshness_defaults\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"funding\": \"300s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\"\n  },\n  \"limits\": {\n    \"source_bytes\": 8192,\n    \"nodes\": 256,\n    \"depth\": 24,\n    \"quantifiers_and_aggregates\": 16,\n    \"series_calls\": 32,\n    \"timeframes\": 3,\n    \"window\": 500,\n    \"bars_per_atom\": 2000,\n    \"cost\": 10000,\n    \"in_list\": 32,\n    \"select\": 16,\n    \"order_by\": 4,\n    \"freshness_min\": \"1s\",\n    \"freshness_max\": \"604800s\",\n    \"screen_limit\": 500,\n    \"endpoints\": {\n      \"snapshots_listings\": 500,\n      \"history_listings\": 100,\n      \"history_rows_per_layer\": 2000,\n      \"history_raw_rows\": 100000,\n      \"candles_listings\": 100,\n      \"candles_per_listing\": 1500,\n      \"books_listings\": 100,\n      \"book_depth\": 25,\n      \"stream_listings\": 500,\n      \"response_bytes\": 8388608\n    }\n  },\n  \"settle_after\": 120,\n  \"earliest_retained\": \"2026-09-14T00:00:00Z\",\n  \"units\": [\n    \"published\",\n    \"base\"\n  ],\n  \"number_formats\": [\n    \"json\",\n    \"string\"\n  ],\n  \"instruments_note\": \"10 more, cut here for length\"\n}\n```\n\n## POST /v2/dql/parse\n\nA query checked but not run: what it means, what it reads, what it costs.\n\nIt touches no market data and needs no key, which makes it the right thing for an editor to call on every keystroke — and the right way to see a query's cost before spending it.\n\n**No key.** What exists is not a paid fact.\n\n### What it takes\n\n| field | type | required | meaning |\n| --- | --- | --- | --- |\n| `query` | string or object | yes | The query, as text or as the machine form of specification §3.1. |\n| `dql` | string | — | The language version. Only `1` exists. |\n| `context` | string | — | What the query is for. Only `screen` exists. |\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n| `dql` | string | The language version. |\n| `query` | object | The query in both forms, canonical. |\n| `atoms` | object | What the query reads, by scope. Useful for showing a reader which data a query depends on. |\n| `timeframes` | array | Every period the query reads. |\n| `complexity` | object | What the query costs, against the catalogue's limits. |\n\n### An answer\n\n```json\n{\n  \"query\": \"any(venues where funding \\u003E 0)\"\n}\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"query\": {\n    \"string\": \"any(venues where funding \\u003E 0)\",\n    \"json\": {\n      \"dql\": \"1\",\n      \"condition\": {\n        \"type\": \"any\",\n        \"where\": {\n          \"type\": \"cmp\",\n          \"op\": \"\\u003E\",\n          \"left\": {\n            \"type\": \"field\",\n            \"name\": \"funding\"\n          },\n          \"right\": {\n            \"type\": \"number\",\n            \"value\": 0\n          }\n        }\n      }\n    }\n  },\n  \"atoms\": {\n    \"instrument\": [],\n    \"venue\": [\n      \"funding\"\n    ]\n  },\n  \"timeframes\": [],\n  \"complexity\": {\n    \"nodes\": 4,\n    \"bars\": 0,\n    \"cost\": 4\n  }\n}\n```\n\n## POST /v2/screen\n\nRun a DQL query across venues and return what matched.\n\nThe endpoint the language exists for. Everything else on this page is a projection of it.\n\n**Needs a key.** Refuses with `401` without one, `429` when the plan's rate is used up.\n\n### What it takes\n\n| field | type | required | meaning |\n| --- | --- | --- | --- |\n| `query` | string | — | The query in DQL. |\n| `query_object` | object | — | The same query in the machine form of specification §3.1. |\n| `limit` | integer | — | How many instruments to return in one page. The catalogue states the ceiling your plan allows. |\n| `cursor` | string | — | A cursor from a previous answer's `page.next_cursor`. It pins the instant, so page two sees the world page one saw. |\n| `include_unknown` | boolean | — | Also return the instruments the data could not decide, with `result: unknown`, instead of dropping them. Ask for this whenever coverage matters. |\n| `units` | `published`, `base`, `quote` | — | What quantities are expressed in. `published` leaves each venue's own unit alone; `base` and `quote` convert, and give null with `unit_unknown` where a contract … |\n| `number_format` | `json`, `string` | — | `string` returns every number as a string with the same digits, for a client whose JSON parser would round them. |\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n| `dql` | string | The query in canonical form — what the platform understood, which may differ in spacing and clause order from what was sent. |\n| `query` | object | The query echoed in both forms, so a client that sent text can keep the machine form and a client that sent the machine form can show the text. |\n| `evaluated_at` | `Instant` |  |\n| `as_of` | `NullableInstant` |  |\n| `settled` | boolean | Whether the instant is far enough in the past that late arrivals can no longer change the answer. A false here means the same query may answer differently in … |\n| `timeframe` | string | The period the query's series were read at, when it asked for one. |\n| `freshness` | object | The bound applied to each layer: a reading older than this is stale and compares as unknown. Stated per answer because a request may override it. |\n| `listings_as_of` | `NullableInstant` |  |\n| `capabilities_as_of` | `NullableInstant` |  |\n| `instruments` | array |  |\n| `page` | `Page` |  |\n\n### An answer\n\n```json\n{\n  \"query\": \"any(venues where funding \\u003E 0)\",\n  \"limit\": 2\n}\n```\n\n```json\n{\n  \"dql\": \"1\",\n  \"query\": {\n    \"string\": \"any(venues where funding \\u003E 0)\",\n    \"json\": {\n      \"dql\": \"1\",\n      \"condition\": {\n        \"type\": \"any\",\n        \"where\": {\n          \"type\": \"cmp\",\n          \"op\": \"\\u003E\",\n          \"left\": {\n            \"type\": \"field\",\n            \"name\": \"funding\"\n          },\n          \"right\": {\n            \"type\": \"number\",\n            \"value\": 0\n          }\n        }\n      }\n    }\n  },\n  \"evaluated_at\": \"2026-09-23T12:00:05Z\",\n  \"as_of\": null,\n  \"settled\": false,\n  \"freshness\": {\n    \"ticker\": \"30s\",\n    \"mark\": \"30s\",\n    \"oi\": \"30s\",\n    \"book\": \"30s\",\n    \"stats\": \"120s\",\n    \"funding\": \"300s\"\n  },\n  \"instruments\": [\n    {\n      \"instrument\": \"BTC-PERP\",\n      \"result\": \"true\",\n      \"values\": {},\n      \"venues\": [\n        {\n          \"venue\": \"BYBIT-PERP\",\n          \"symbol\": \"BTCUSDT\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00002,\n              \"unit\": \"fraction\",\n              \"venue\": \"BYBIT-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T11:52:00Z\",\n              \"age_ms\": 485000,\n              \"status\": \"stale\"\n            }\n          }\n        },\n        {\n          \"venue\": \"HYPERLIQUID\",\n          \"symbol\": \"BTC\",\n          \"quote\": \"USDC\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000013,\n              \"unit\": \"fraction\",\n              \"venue\": \"HYPERLIQUID\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"KRAKEN-FUTURES\",\n          \"symbol\": \"PF_XBTUSD\",\n          \"quote\": \"USD\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.00001,\n              \"unit\": \"fraction\",\n              \"venue\": \"KRAKEN-FUTURES\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        },\n        {\n          \"venue\": \"OKX-PERP\",\n          \"symbol\": \"BTC-USDT-SWAP\",\n          \"quote\": \"USDT\",\n          \"values\": {\n            \"funding\": {\n              \"value\": 0.000054,\n              \"unit\": \"fraction\",\n              \"venue\": \"OKX-PERP\",\n              \"layer\": \"funding\",\n              \"venue_ts\": null,\n              \"received_at\": \"2026-09-23T12:00:04Z\",\n              \"age_ms\": 1000,\n              \"status\": \"present\"\n            }\n          }\n        }\n      ]\n    }\n  ],\n  \"page\": {\n    \"limit\": 2,\n    \"returned\": 2,\n    \"next_cursor\": \"eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkVUSC1QRVJQIiwicSI6IjExZDhjM2VmZWNkZGNjNTYifQ\"\n  },\n  \"instruments_note\": \"1 more, cut here for length\"\n}\n```\n\n## POST /v2/snapshots\n\nThe latest reading of each layer for the selected listings.\n\nWhen you want the state of things rather than an answer to a question. It also returns the instrument-venue pairs you asked for that do not exist, rather than leaving you to infer them from a short answer.\n\n**Needs a key.** Refuses with `401` without one, `429` when the plan's rate is used up.\n\n### What it takes\n\n| field | type | required | meaning |\n| --- | --- | --- | --- |\n| `where` | `Selection` | — |  |\n| `units` | `published`, `base`, `quote` | — | What quantities are expressed in. |\n| `number_format` | `json`, `string` | — | `string` returns every number as a string with the same digits. |\n| `include_synthetic` | boolean | — | Include venues that exist in the registry but are not published. For the platform's own use; a public key sees nothing extra. |\n| `layers` | array | — | Which layers to read. Every layer when omitted. |\n| `include_raw` | boolean | — | Also return each layer's message as the venue sent it. |\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n| `evaluated_at` | `Instant` |  |\n| `units` | `published`, `base`, `quote` | The unit mode applied. |\n| `freshness` | object | The bound applied to each layer. |\n| `items` | array | One object per listing. |\n| `missing` | array | The instrument-venue pairs that do not exist. |\n\n## POST /v2/snapshots/history\n\nThe same snapshot as it stood in the past: one row per period, per named instant, or per message as it arrived.\n\nThree different questions, and the endpoint makes you say which. `raw` is every row as received — the thing to use when you are checking the platform rather than the market.\n\n**Needs a key.** Refuses with `401` without one, `429` when the plan's rate is used up.\n\n### What it takes\n\n| field | type | required | meaning |\n| --- | --- | --- | --- |\n| `where` | `Selection` | — |  |\n| `units` | `published`, `base`, `quote` | — | What quantities are expressed in. |\n| `number_format` | `json`, `string` | — | `string` returns every number as a string with the same digits. |\n| `include_synthetic` | boolean | — | Include venues that exist in the registry but are not published. For the platform's own use; a public key sees nothing extra. |\n| `layers` | array | — | Which layers to read. |\n| `interval` | string | — | One row per period of this length, each holding the last reading in it. |\n| `at` | array | — | One row per instant, strictly ascending. `from` and `to` do not apply here — the instants are the rows. |\n| `raw` | boolean | — | Every row as it arrived, unsampled. |\n| `from` | `Instant` | yes | Start of the window. Required for `interval` and `raw`. |\n| `to` | `Instant` | yes | End of the window. Required for `interval` and `raw`. |\n| `include_gaps` | boolean | — | Keep the rows that have no reading. Keeping them is the default because dropping them turns a gap into a shorter series. |\n| `freshness` | string | — | Override the freshness bound for every layer asked for. |\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n| `evaluated_at` | `Instant` |  |\n| `settled` | boolean | Whether the window is far enough in the past that a late arrival can no longer change it. |\n| `items_sha256` | string | SHA-256 of `items` as serialised. |\n| `mode` | `interval`, `at`, `raw` | Which question was asked. |\n| `interval` | string | The period, in `interval` mode. |\n| `from` | `NullableInstant` | The window, in `interval` and `raw` modes. Absent in `at` mode. |\n| `to` | `NullableInstant` |  |\n| `units` | `published`, `base`, `quote` | The unit mode applied. |\n| `freshness` | object | The bound applied per layer. |\n| `listings_as_of` | `NullableInstant` |  |\n| `capabilities_as_of` | `NullableInstant` |  |\n| `items` | array | One object per listing. |\n\n## POST /v2/candles\n\nCompleted candles, in any stored period and price type.\n\nOne-minute candles are the venue's own klines; every longer period is rolled up from them, and exists only when every base minute exists. Gaps are rows, not holes.\n\n**Needs a key.** Refuses with `401` without one, `429` when the plan's rate is used up.\n\n### What it takes\n\n| field | type | required | meaning |\n| --- | --- | --- | --- |\n| `where` | `Selection` | — |  |\n| `units` | `published`, `base`, `quote` | — | What quantities are expressed in. |\n| `number_format` | `json`, `string` | — | `string` returns every number as a string with the same digits. |\n| `include_synthetic` | boolean | — | Include venues that exist in the registry but are not published. For the platform's own use; a public key sees nothing extra. |\n| `timeframe` | string | yes | The period. `1m` comes from the venue's own klines; every longer period is rolled up from them. |\n| `price_type` | `trade`, `mark`, `index` | — | Which price. |\n| `from` | `Instant` | yes |  |\n| `to` | `Instant` | yes |  |\n| `include_gaps` | boolean | — | Keep the periods with no candle, as gap rows. |\n| `closed_only` | boolean | — | Accepted and has no effect: only closed minutes are stored, so there is never a forming candle to return. |\n| `trade` | boolean | — | Reserved. |\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n| `evaluated_at` | `Instant` |  |\n| `settled` | boolean | Whether the window is far enough in the past that a late arrival can no longer change it. |\n| `items_sha256` | string | SHA-256 of `items` as serialised. Two answers with the same hash are the same answer, which is how a client can skip work rather than re-parse. |\n| `timeframe` | string | The period returned. |\n| `price_type` | `trade`, `mark`, `index` | Which price the candles are of. |\n| `from` | `Instant` |  |\n| `to` | `Instant` |  |\n| `units` | `published`, `base`, `quote` | The unit mode applied. |\n| `listings_as_of` | `NullableInstant` |  |\n| `capabilities_as_of` | `NullableInstant` |  |\n| `items` | array | One object per listing. |\n\n## POST /v2/books\n\nOrder books to the depth the plan allows, with the depth resting in each band around the mid.\n\nPrices and sizes are strings, always. A book is where a rounded digit becomes a wrong order.\n\n**Needs a key.** Refuses with `401` without one, `429` when the plan's rate is used up.\n\n### What it takes\n\n| field | type | required | meaning |\n| --- | --- | --- | --- |\n| `where` | `Selection` | — |  |\n| `units` | `published`, `base`, `quote` | — | What quantities are expressed in. |\n| `number_format` | `json`, `string` | — | `string` returns every number as a string with the same digits. |\n| `include_synthetic` | boolean | — | Include venues that exist in the registry but are not published. For the platform's own use; a public key sees nothing extra. |\n| `depth` | integer | — | Levels per side. Clamped to what the plan allows; the answer states what was applied. |\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n| `evaluated_at` | `Instant` |  |\n| `units` | `published`, `base`, `quote` | The unit mode applied. |\n| `depth` | integer | How many levels per side were returned, after the plan's ceiling was applied. |\n| `liquidity_note` | string | How the depth figures relate to the levels shown, in one sentence. |\n| `items` | array | One object per listing. |\n\n## GET /v2/stream\n\nA live stream of the selected listings, as server-sent events.\n\nOne `snapshot` per listing and layer, then an `update` for every change — including a change of status with no new value, because a listing going stale is news. A heartbeat every fifteen seconds means silence is a broken connection, not a quiet market.\n\n**Needs a key.** Refuses with `401` without one, `429` when the plan's rate is used up.\n\n### What it answers\n\n| field | type | meaning |\n| --- | --- | --- |\n\n\n\n# Limits\n\nEvery limit below is served as data by `GET /v2/dql/catalogue`. Read it from there rather than carrying\na copy: these are what the platform runs on today, and a client that hard-codes them will be wrong on\nthe day they change. The sentences here say what to do when you meet one.\n\nNothing is silently truncated. A request past a limit is refused with `DQL_LIMIT` or `DQL_COMPLEXITY`\nand the message states both your figure and the ceiling — because a short answer that looks complete is\nworse than a refusal.\n\n## What a query may be\n\n| limit | value | what it means |\n| --- | --- | --- |\n| `source_bytes` | 8,192 | The longest query text accepted. |\n| `nodes` | 256 | Nodes in the parsed query. A condition with dozens of clauses meets this before it meets anything else. |\n| `depth` | 24 | How deeply the expression may nest. |\n| `quantifiers_and_aggregates` | 16 | How many `any`, `all`, `count`, `max`, `min` and `sum` one query may hold together. |\n| `series_calls` | 32 | How many series functions one query may call. |\n| `timeframes` | 3 | How many different periods one query may read. Reading three is a heavy query; reading four is a different question asked twice. |\n| `window` | 500 | The largest window a series function may ask for, in periods — `sma(close, 500)` is the longest average there is. |\n| `bars_per_atom` | 2,000 | The most bars one series read may cost. |\n| `cost` | 10,000 | What the whole query may cost. `POST /v2/dql/parse` returns a query's cost without running it, so this can be seen before it is hit. |\n| `in_list` | 32 | The longest `in (…)` list. |\n| `select` | 16 | How many values one `select` may return. |\n| `order_by` | 4 | How many keys one `order by` may have. |\n| `freshness_min` | 1 s | The shortest freshness bound a query may set. Below this you are asking about jitter, not about staleness. |\n| `freshness_max` | 7 d | The longest. Past it, `stale` stops meaning anything. |\n| `screen_limit` | 500 | The largest page `POST /v2/screen` returns. Use `page.next_cursor` for the rest; the cursor pins the instant, so page two sees the world page one saw. |\n\n## What one request may ask for\n\n| limit | value | endpoint |\n| --- | --- | --- |\n| `snapshots_listings` | 500 | `POST /v2/snapshots` — or every listing of a single venue, however many that is. |\n| `history_listings` | 100 | `POST /v2/snapshots/history`. |\n| `history_rows_per_layer` | 2,000 | `POST /v2/snapshots/history`, in `interval` and `at` modes. |\n| `history_raw_rows` | 100,000 | `POST /v2/snapshots/history`, in `raw` mode, across every listing and layer together. |\n| `candles_listings` | 100 | `POST /v2/candles`. |\n| `candles_per_listing` | 1,500 | `POST /v2/candles`. |\n| `books_listings` | 100 | `POST /v2/books`. |\n| `book_depth` | 25 | `POST /v2/books` — levels per side. A larger `depth` is clamped to this and the answer states what was applied. |\n| `stream_listings` | 500 | `GET /v2/stream` — listings on one connection. |\n| `response_bytes` | 8,388,608 | Any endpoint. A response that would be larger is refused rather than cut. |\n\n## Plan limits are a different thing\n\nThe numbers above are the same for everyone: they are what one request may ask the platform to do at\nonce. How far back you may look, how often you may ask, and how many streams you may hold are set by\nthe plan, and are refused with `PLAN_LIMIT` or `RATE_LIMITED` instead. A `429` carries `Retry-After`.\n\n\n# Errors\n\nEvery failure answers in the same shape: a list, because one request can be wrong in several places at\nonce, and each entry says what is wrong, where, and what to do instead.\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_UNKNOWN_FIELD\",\n      \"message\": \"unknown field 'fundng' at 1:18; did you mean 'funding'?\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 18,\n        \"offset\": 17,\n        \"length\": 6\n      },\n      \"hint\": \"did you mean 'funding'?\"\n    }\n  ]\n}\n```\n\nBranch on `code`. It is stable. `message` explains and may be reworded between releases, and `hint`\nis advice, not a contract. `position` is present whenever the fault has a place in the query text:\n`line` and `column` are 1-based, `offset` is 0-based, and `length` covers the offending token, so an\neditor can underline it exactly.\n\n## What the language refuses\n\nEach of these was produced by running the query beside it through the parser. The messages are the\nserver's own.\n\n### DQL_SYNTAX\n\nThe text is not a query. The position is where reading stopped and the message names what was expected there.\n\n```dql\nfunding > \n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_SYNTAX\",\n      \"message\": \"unexpected end of input at 1:11; expected an expression\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 11,\n        \"offset\": 10,\n        \"length\": 0\n      },\n      \"hint\": \"expected an expression\"\n    }\n  ]\n}\n```\n\nUnderline the position. `POST /v2/dql/parse` answers this without running anything, which is what an editor should call on every keystroke.\n\n### DQL_UNKNOWN_FIELD\n\nA name that is not a field. The message suggests the nearest one it knows.\n\n```dql\nany(venues where fundng > 0)\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_UNKNOWN_FIELD\",\n      \"message\": \"unknown field 'fundng' at 1:18; did you mean 'funding'?\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 18,\n        \"offset\": 17,\n        \"length\": 6\n      },\n      \"hint\": \"did you mean 'funding'?\"\n    }\n  ]\n}\n```\n\nRead `GET /v2/dql/catalogue` for the fields that exist rather than carrying a list in your client.\n\n### DQL_UNKNOWN_FUNCTION\n\nA name that is not a function.\n\n```dql\nany(venues where emma(close, 20) > 0)\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_UNKNOWN_FUNCTION\",\n      \"message\": \"unknown function 'emma' at 1:18; did you mean 'ema'?\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 18,\n        \"offset\": 17,\n        \"length\": 15\n      },\n      \"hint\": \"did you mean 'ema'?\"\n    }\n  ]\n}\n```\n\nThe catalogue lists every function with its signature.\n\n### DQL_UNKNOWN_VENUE\n\nA venue code the platform does not have. The message lists the ones it does.\n\n```dql\nany(venues where venue = BINANCE-PERP)\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_UNKNOWN_VENUE\",\n      \"message\": \"unknown venue 'BINANCE-PERP' at 1:26; known: BYBIT-PERP, HYPERLIQUID, KRAKEN-FUTURES, OKX-PERP\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 26,\n        \"offset\": 25,\n        \"length\": 12\n      },\n      \"hint\": \"known: BYBIT-PERP, HYPERLIQUID, KRAKEN-FUTURES, OKX-PERP\"\n    }\n  ]\n}\n```\n\nRead `GET /v2/venues`. A venue the platform is still onboarding is not queryable until it appears there.\n\n### DQL_UNKNOWN_CURRENCY\n\nA quote currency that exists on no listing.\n\n```dql\nany(venues where quote = USDD)\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_UNKNOWN_CURRENCY\",\n      \"message\": \"unknown currency 'USDD'\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 26,\n        \"offset\": 25,\n        \"length\": 4\n      },\n      \"hint\": \"did you mean 'USD'?\"\n    }\n  ]\n}\n```\n\nThe catalogue's `currencies` is the whole set. DQL never converts between them, so the spelling has to match.\n\n### DQL_UNKNOWN_ASSET\n\nA base asset the platform does not have.\n\n```dql\nbase = BITCOIN\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_UNKNOWN_ASSET\",\n      \"message\": \"unknown asset 'BITCOIN'\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 8,\n        \"offset\": 7,\n        \"length\": 7\n      },\n      \"hint\": \"known: BTC, ETH, SOL\"\n    }\n  ]\n}\n```\n\nThe catalogue's `assets` is the whole set.\n\n### DQL_UNKNOWN_INSTRUMENT\n\nAn instrument code that does not exist — often the base asset written where the instrument belongs.\n\n```dql\ninstrument = BTC\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_UNKNOWN_INSTRUMENT\",\n      \"message\": \"unknown instrument 'BTC'\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 14,\n        \"offset\": 13,\n        \"length\": 3\n      },\n      \"hint\": \"known: BTC-PERP, ETH-PERP, SOL-PERP\"\n    }\n  ]\n}\n```\n\nInstruments are `BTC-PERP`, not `BTC`. The catalogue's `instruments` lists them.\n\n### DQL_SCOPE\n\nA venue-scoped field used as though it belonged to the instrument. Funding is a fact about one venue's listing; an instrument has several.\n\n```dql\nfunding > 0\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_SCOPE\",\n      \"message\": \"'funding' is venue-scoped; wrap it in any(venues where …), all(…), count(…) or an aggregate\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 1,\n        \"offset\": 0,\n        \"length\": 7\n      },\n      \"hint\": \"wrap in any(venues where ...) / all(...) / count(...) or an aggregate\"\n    }\n  ]\n}\n```\n\nSay which venues you mean: `any(venues where funding > 0)`, or `all`, `count`, or an aggregate.\n\n### DQL_NESTING\n\nA quantifier inside a quantifier. There is one level of venues, so the inner one would have nothing to range over.\n\n```dql\nany(venues where any(venues where funding > 0))\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_NESTING\",\n      \"message\": \"quantifiers cannot be nested\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 18,\n        \"offset\": 17,\n        \"length\": 29\n      }\n    }\n  ]\n}\n```\n\nFlatten the condition.\n\n### DQL_TYPE\n\nAn operation on a value of the wrong kind. Summing prices across venues is a category error, not a small inaccuracy — the result would be a number with no meaning.\n\n```dql\nsum(venues, mark) > 0\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_TYPE\",\n      \"message\": \"sum requires an additive field; mark is a price\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 1,\n        \"offset\": 0,\n        \"length\": 17\n      },\n      \"hint\": \"additive: oi, volume_24h, turnover_24h, bid_size, ask_size, volume, the depth functions, or arithmetic over those\"\n    }\n  ]\n}\n```\n\nSum only additive fields; the catalogue's `additive` says which. For a price across venues, use `max`, `min` or an average of your own.\n\n### DQL_TIMEFRAME_REQUIRED\n\nA series function with no period to read at. A moving average is a different number on every timeframe, so the platform will not choose one for you.\n\n```dql\nany(venues where ema(close, 20) > close)\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_TIMEFRAME_REQUIRED\",\n      \"message\": \"series function 'ema' needs a timeframe: add 'timeframe 15m' or a trailing argument\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 18,\n        \"offset\": 17,\n        \"length\": 14\n      }\n    }\n  ]\n}\n```\n\nAdd `timeframe 1h` to the query, or give the function its own: `ema(close, 20, 1h)`.\n\n### DQL_TIMEFRAME_UNSUPPORTED\n\nA period the platform does not store. The message lists the ones it does.\n\n```dql\nany(venues where sma(close, 3) > 0) timeframe 7m\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_TIMEFRAME_UNSUPPORTED\",\n      \"message\": \"timeframe '7m' is not supported; supported: 1m, 2m, 3m, 5m, 15m, 30m, 1h, 4h, 12h, 1d\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 37,\n        \"offset\": 36,\n        \"length\": 9\n      }\n    }\n  ]\n}\n```\n\nUse a period from the catalogue's `timeframes`.\n\n### DQL_TIMEFRAME_MISMATCH\n\nTwo series of different periods compared as though they lined up. They do not: one bar of the first is not one bar of the second.\n\n```dql\nany(venues where crossover(ema(close, 20, 1h), ema(close, 50, 4h)))\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_TIMEFRAME_MISMATCH\",\n      \"message\": \"series timeframes differ (1h vs 4h)\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 18,\n        \"offset\": 17,\n        \"length\": 49\n      }\n    }\n  ]\n}\n```\n\nRead both at the same period.\n\n### DQL_ARGUMENT\n\nAn argument outside what the function accepts. The message states the range.\n\n```dql\nany(venues where ema(close, 0) > 0) timeframe 1h\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_ARGUMENT\",\n      \"message\": \"argument 'n' of ema must be an integer in 1…500\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 29,\n        \"offset\": 28,\n        \"length\": 1\n      }\n    }\n  ]\n}\n```\n\nUse a window inside the stated range.\n\n### DQL_DUPLICATE_CLAUSE\n\nA clause given twice. The platform will not guess which one you meant.\n\n```dql\nvenues_listed > 0 timeframe 1h timeframe 4h\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_DUPLICATE_CLAUSE\",\n      \"message\": \"clause 'timeframe' given twice\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 32,\n        \"offset\": 31,\n        \"length\": 9\n      },\n      \"hint\": \"each clause may appear at most once\"\n    }\n  ]\n}\n```\n\nGive it once.\n\n### DQL_AS_OF_RANGE\n\nAn instant outside what can be answered — in the future, or before the earliest data retained.\n\n```dql\nany(venues where funding > 0) as of 2030-01-01T00:00:00Z\n```\n\n```json\n{\n  \"errors\": [\n    {\n      \"code\": \"DQL_AS_OF_RANGE\",\n      \"message\": \"as_of is in the future\",\n      \"position\": {\n        \"line\": 1,\n        \"column\": 31,\n        \"offset\": 30,\n        \"length\": 2\n      },\n      \"hint\": \"the server clock is 2026-09-23T12:00:05Z\"\n    }\n  ]\n}\n```\n\nThe catalogue's `earliest_retained` is the floor; the present is the ceiling.\n\n## What the request refuses\n\nThese are about the request rather than about the query, so no query produces them and none is shown.\n\n| code | status | what it means |\n| --- | --- | --- |\n| `DQL_JSON_SCHEMA` | 400 | The request body is not the shape the endpoint takes. `path` points at the offending member, as a JSON pointer. |\n| `DQL_VERSION` | 400 | A language version other than `1` was asked for. There is only one. |\n| `DQL_LIMIT` | 400 | The request is within the grammar but past a batch limit — too many listings, too many rows, or a response too large. The message states both the figure and the limit. |\n| `DQL_COMPLEXITY` | 400 | The query is within the grammar but costs more than the limits allow. `POST /v2/dql/parse` returns a query's cost, so this can be seen before it is hit. |\n| `AUTH_REQUIRED` | 401 | The endpoint needs a key and none was sent. |\n| `AUTH_INVALID` | 401 | The key is unknown, revoked, expired, or the header is not `Bearer <key>`. |\n| `KEY_IN_URL` | 400 | A key was sent as a query parameter. Query strings are written to logs and browser history, so the key should be treated as compromised and replaced. |\n| `PLAN_LIMIT` | 403 | The request is valid but reaches past what the plan includes — usually further back in history. |\n| `RATE_LIMITED` | 429 | A per-second, per-day or stream limit of the plan. `Retry-After` says when to come back. |\n| `UNAVAILABLE` | 503 | The platform cannot answer yet; retry in a minute. |\n\nA `400` from `POST /v2/dql/parse` is not a failure of the API: it is the answer you asked for.\n\n\n# How the language behaves\n\nHow the language behaves, executably.\n\nEvery case below is a query, the dataset it runs on, and the answer it must give. They are not\nillustrations: `src/Debyko.Dql.Tests` runs each one on every build, and a release that answered any of\nthem differently would not have shipped. If you want to know what DQL does in a corner, this is the\nplace that cannot be out of date.\n\nThe dataset is synthetic — four venues, three instruments, values chosen so that every result can be\nchecked by hand. Those venue codes exist only here: a query you send to the platform must name a venue\nfrom [Venues in DQL](#venues-in-dql).\n\n## The dataset\n\nEvaluation instant `T = 2026-09-21T09:30:05.000Z` unless a query says otherwise. Freshness\ndefaults as in §8.4. Timeframe set as in §3.4. Candle layer `off` for GMX-PERP's group; all other\nlayers `on` for all groups. Retention covers everything below. `settle_after = 60`.\n\nVenues: `BINANCE-USDM`, `BYBIT-PERP`, `HYPERLIQUID`, `GMX-PERP`. Capability: GMX-PERP does not\npublish the book layer. Instruments and listings at `T`: `BTC` on all four; `ETH` on\nBINANCE-USDM, BYBIT-PERP, GMX-PERP; `SOL` on HYPERLIQUID.\n\nSnapshot values. \"P\" = received at `2026-09-21T09:30:04.000Z` (age 1 000 ms, present). Quote:\nBINANCE-USDM and BYBIT-PERP `USDT`; HYPERLIQUID and GMX-PERP `USDC`. `funding_interval` is `8h`\non BINANCE-USDM and BYBIT-PERP, `1h` on HYPERLIQUID and GMX-PERP.\n\n| Instrument | Venue | mark | funding | oi | bid / ask |\n|---|---|---|---|---|---|\n| BTC | BINANCE-USDM | 65000 P | 0.0001 received 09:29:35.000 (age 30 000 ms, present) | 1000 P | 64999 / 65001 P |\n| BTC | BYBIT-PERP | 65010 P | 0.0002 received 09:20:00.000 (age 605 000 ms, **stale**) | 800 P | 65005 / 65015 P |\n| BTC | HYPERLIQUID | **missing** | 0.00005 P | 500 P | 64990 / 65010 P |\n| BTC | GMX-PERP | 65020 P | −0.00003 P | 200 P | not_published |\n| ETH | BINANCE-USDM | 3200 P | 0.0003 P | 5000 P | 3199.9 / 3200.1 P |\n| ETH | BYBIT-PERP | 3201 P | 0.0001 P | 4000 P | 3200.5 / 3201.5 P |\n| ETH | GMX-PERP | 3199 P | **missing** | 1000 P | not_published |\n| SOL | HYPERLIQUID | 150 P | 0.0002 P | 30000 P | 149.99 / 150.01 P |\n\nDerived: BTC/BINANCE `spread = 2/65000 = 3.0769230769230769e-5`; BTC/BYBIT `spread = 10/65010 =\n1.5382248884786956e-4`; BTC/HYPERLIQUID `spread = 20/65000 = 3.076923076923077e-4`; BTC/GMX\n`spread` null (not_published). `funding_8h`: BINANCE BTC 0.0001, BYBIT BTC 0.0002 (stale),\nHYPERLIQUID BTC 0.0004, GMX BTC −0.00024.\n\nCandles (15m, UTC-aligned). Candle `k` has period `[end − 15m, end)`, `received_at = end + 0.4 s`,\n`open = previous close`, `high = close + 100`, `low = close − 100`, `volume = 10`.\n\n- BTC / BINANCE-USDM: 10 candles, ends `07:15, 07:30, …, 09:30`; `close = 60000` for the first\n  nine and `66000` for the candle ending `09:30`.\n- BTC / BYBIT-PERP: same ends and closes (all `60000`), except the candle ending `08:45` is\n  **absent** (gap).\n- BTC / HYPERLIQUID: 3 candles, ends `09:00, 09:15, 09:30`, closes `59000, 59500, 60000`.\n- BTC / GMX-PERP: layer `off`.\n- ETH and SOL: no candles received on any venue (status `missing`).\n\n## The cases\n\n**This table is generated from `src/Debyko.Dql.Tests/Corpus.cs` and checked against it by\n`CorpusSpecTests`: a case added to the tests and not to this table, or the other way round, fails\nthe build.** Numbering is continuous across the origins — 01–47 from draft 1, 48–72 from change\nset 01, 73–82 from change set 02, 83–88 from change set 03, 89–95 from change set 04, and the\nlettered ones (14a, 20a, 62a, 82a, 94a …) added while implementing, each pinning a decision of the\nimplementation notes.\n\n\"Result\" is the set of instruments whose result is true, written as market codes (C4-01). Cases run\nwith `units: base` unless the row says otherwise.\n\n| # | Query | Expected |\n|---|---|---|\n| 01 | `any(venues where funding > 0)` | BTC-PERP, ETH-PERP, SOL-PERP |\n| 02 | `all(venues where funding > 0)` | SOL-PERP (ETH-PERP unknown) |\n| 03 | `count(venues where funding > 0) >= 3` | none |\n| 04 | `count(venues where funding > 0) >= 2` | BTC-PERP, ETH-PERP |\n| 05 | `count(venues where status(funding) = stale) = 1` | BTC-PERP |\n| 06 | `any(venues where status(funding) = missing)` | ETH-PERP |\n| 07 | `any(venues where status(bid) = not_published)` | BTC-PERP, ETH-PERP |\n| 08 | `all(venues where status(bid) = not_published or spread < 5bps)` | BTC-PERP, ETH-PERP, SOL-PERP |\n| 09 | `all(venues where spread < 5bps)` | SOL-PERP (BTC-PERP, ETH-PERP unknown) |\n| 10 | `venues_answered >= 3` | BTC-PERP, ETH-PERP |\n| 11 | `venues_answered < venues_listed` | BTC-PERP |\n| 12 | `max(venues, mark) - min(venues, mark) > 15` | BTC-PERP |\n| 13 | `max(venues where quote = USDT, mark) - min(venues where quote = USDT, mark) > 5` | BTC-PERP (SOL-PERP unknown) |\n| 14a | `sum(venues, oi) > 2000` | BTC-PERP, ETH-PERP, SOL-PERP |\n| 14b | `sum(venues, oi) > 5000` | ETH-PERP, SOL-PERP |\n| 15 | `sum(venues, mark) > 0` | error `DQL_TYPE` |\n| 16 | `funding > 0` | error `DQL_SCOPE` |\n| 17 | `any(venues where venue = HYPERLIQUID and funding_8h > 3bps)` | BTC-PERP, SOL-PERP |\n| 18 | `any(venues where funding > 0 and age(funding) < 10s)` | BTC-PERP, ETH-PERP, SOL-PERP |\n| 19 | `any(venues where age(funding) < 10s) freshness 10s` | BTC-PERP, ETH-PERP, SOL-PERP |\n| 20a | `any(venues where funding > 0) freshness 1d` | BTC-PERP, ETH-PERP, SOL-PERP |\n| 20b | `count(venues where funding > 0) >= 3 freshness 1d` | BTC-PERP |\n| 21 | `any(venues where sma(close, 3) = 62000) timeframe 15m` | BTC-PERP |\n| 22 | `any(venues where ema(close, 2) = 64000) timeframe 15m` | BTC-PERP |\n| 23 | `any(venues where venue = BYBIT-PERP and sma(close, 3) = 60000) timeframe 15m` | BTC-PERP |\n| 24 | `any(venues where venue = BYBIT-PERP and sma(close, 5) > 0) timeframe 15m` | none (BTC-PERP unknown, gap) |\n| 25 | `any(venues where venue = BYBIT-PERP and gaps(10) = 1) timeframe 15m` | BTC-PERP |\n| 26 | `any(venues where venue = HYPERLIQUID and ema(close, 2) > 0) timeframe 15m` | none (BTC-PERP unknown, insufficient_history) |\n| 27 | `any(venues where venue = HYPERLIQUID and sma(close, 3) = 59500) timeframe 15m` | BTC-PERP |\n| 28 | `any(venues where status(close) = off) timeframe 15m` | BTC-PERP |\n| 29 | `any(venues where crossover(close, sma(close, 3))) timeframe 15m` | BTC-PERP |\n| 30 | `any(venues where rsi(close, 2) = 100) timeframe 15m` | BTC-PERP |\n| 31 | `any(venues where atr(2) = 3150) timeframe 15m` | BTC-PERP |\n| 32 | `any(venues where stdev(close, 3) > 2828.42 and stdev(close, 3) < 2828.43) timeframe 15m` | BTC-PERP |\n| 33 | `any(venues where change(close, 1) = 6000 and roc(close, 1) = 0.1 and prev(close, 1) = 60000 and highest(close, 3) = 66000 and lowest(close, 3) = 60000) timeframe 15m` | BTC-PERP |\n| 34 | `any(venues where ema(close, 20) > 0)` | error `DQL_TIMEFRAME_REQUIRED` |\n| 35 | `any(venues where sma(close, 3) = 60000 and venue = BINANCE-USDM) timeframe 15m as of 2026-09-21T09:30:00Z` | BTC-PERP |\n| 36 | `any(venues where crossover(close, sma(close, 3))) timeframe 15m as of 2026-09-21T09:30:00Z` | none |\n| 37 | `any(venues where funding > 0) as of 2030-01-01T00:00:00Z` | error `DQL_AS_OF_RANGE` |\n| 38 | `venues_listed >= 1 order by sum(venues, oi) desc` | SOL-PERP, ETH-PERP, BTC-PERP (in this order) |\n| 39 | `venues_listed >= 1 order by max(venues where quote = USDT, mark) desc` | BTC-PERP, ETH-PERP, SOL-PERP (in this order) |\n| 40 | `any(venues where quote in (USDT, USDC) and funding > 0) or venues_answered = 0` | BTC-PERP, ETH-PERP, SOL-PERP |\n| 41 | `any(venues where funding > 0 and not (status(funding) = stale))` | BTC-PERP, ETH-PERP, SOL-PERP |\n| 42 | `not any(venues where funding < 0)` | SOL-PERP |\n| 43 | `any(venues where funding > 0) AND venues_listed > 1` | error `DQL_SYNTAX` |\n| 44 | `any(venues where 5min > 0)` | error `DQL_SYNTAX` |\n| 45 | `any( venues where funding>=0.0001 and (spread<5bps) )  // note` | canonical `any(venues where funding >= 0.0001 and spread < 0.0005)` |\n| 46 | `any( venues where funding>=0.0001 and (spread<5bps) )  // note` | canonical `any(venues where funding >= 0.0001 and spread < 0.0005)` |\n| 47 | `any(venues where funding > 0)` | response shape: BTC-PERP lists all four venues with provenance |\n| 48 | `any(venues where sma(mark, 5) = 64986) timeframe 1m` | BTC-PERP |\n| 49 | `any(venues where sma(mark, 6) > 0) timeframe 1m` | none (BTC-PERP unknown, gap) |\n| 50 | `any(venues where change(mark, 4) = 10 and prev(mark, 1) = 64970 and highest(mark, 5) = 65010 and lowest(mark, 5) = 64960) timeframe 1m` | BTC-PERP |\n| 51 | `any(venues where mark > sma(mark, 5)) timeframe 1m` | BTC-PERP |\n| 52 | `any(venues where percentile(mark, 5, 50%) = 64990 and percentile(mark, 5, 95%) = 65010 and percentile(mark, 5, 20%) = 64960) timeframe 1m` | BTC-PERP |\n| 53 | `any(venues where percentile_rank(mark, 5) = 0.8) timeframe 1m` | BTC-PERP |\n| 54 | `any(venues where rolling_sum(abs(change(mark, 1)), 4) = 150 and abs(change(mark, 4)) = 10) timeframe 1m` | BTC-PERP |\n| 55 | `any(venues where abs(change(mark, 4)) / rolling_sum(abs(change(mark, 1)), 4) > 0.06 and abs(change(mark, 4)) / rolling_sum(abs(change(mark, 1)), 4) < 0.07) timeframe 1m` | BTC-PERP |\n| 56 | `any(venues where age(mark) = 1s and age(mark, 1m) = 5500ms and status(mark, 1m) = present)` | BTC-PERP |\n| 57 | `any(venues where sma(mark, 2) = 64990) timeframe 1m as of 2026-09-21T09:29:59Z` | BTC-PERP |\n| 58 | `any(venues where status(mark) = stale) as of 2026-09-21T09:29:59Z` | BTC-PERP |\n| 59 | `any(venues where bid_size = 2 and ask_size = 1.5)` | BTC-PERP |\n| 60 | `any(venues where depth_bid(1bps) = 5 and depth_ask(1bps) = 4 and depth_bid_value(1bps) = 324992 and depth_ask_value(1bps) = 260006.5)` | BTC-PERP |\n| 61 | `any(venues where depth_bid(10bps) > 0)` | none (BTC-PERP unknown, band_truncated) |\n| 62a | `any(venues where depth_bid(0) > 0)` | error `DQL_ARGUMENT` |\n| 62b | `any(venues where depth_bid(6%) > 0)` | error `DQL_ARGUMENT` |\n| 63 | `sum(venues, depth_bid(1bps)) = 5` | BTC-PERP |\n| 64 | `any(venues where tick_size / mark < 1bps and lot_size = 0.001)` | BTC-PERP |\n| 65 | `any(venues where quote in (USDT, USDC)) select venues_listed, sum(venues, oi), funding_8h` | BTC-PERP, ETH-PERP, SOL-PERP (as corpus test 14) |\n| 66 | `venues_listed >= 1 order by venues_answered desc, sum(venues, oi) asc` | BTC-PERP, ETH-PERP, SOL-PERP (in this order) |\n| 67 | `venues_listed >= 1 order by max(venues where quote = USDT, mark) desc, venues_listed asc` | BTC-PERP, ETH-PERP, SOL-PERP (in this order) |\n| 68 | `any(venues where sma(quote, 3) > 0) timeframe 1m` | error `DQL_TYPE` |\n| 69 | `any(venues where sma(venues_listed, 3) > 0) timeframe 1m` | error `DQL_TYPE` |\n| 70 | `any(venues where percentile(mark, 5, 1.5) > 0) timeframe 1m` | error `DQL_ARGUMENT` |\n| 71 | `count(venues where roc(mark, 5) > 0.5%) >= 3 select venues_listed timeframe 1m order by venues_listed desc` | canonical `count(venues where roc(mark, 5) > 0.005) >= 3 timeframe 1m order by venues_listed desc select venues_listed` |\n| 72 | `any(venues where venue = BYBIT-PERP) select spread, bid` | spread prints 0.00015382248884786957, bid prints 65005 |\n| 73 | `any(venues where sma(mark, 5) = 64972) timeframe 2m` | BTC-PERP |\n| 74 | `any(venues where lowest(change(mark, 1), 3) > 0) timeframe 2m` | none (BTC-PERP false) |\n| 75 | `any(venues where mark_close - close = 10) timeframe 15m` | BTC-PERP |\n| 76 | `any(venues where venue = BYBIT-PERP and status(mark_close) = not_published) timeframe 15m` | BTC-PERP |\n| 77 | `any(venues where sma(mark_close, 3) = 62010) timeframe 15m` | BTC-PERP |\n| 78 | `any(venues where percentile(mark, 5, 90%, linear) > 65005.99 and percentile(mark, 5, 90%, linear) < 65006.01) timeframe 1m` | BTC-PERP |\n| 79 | `any(venues where percentile(mark, 5, 50%, linear) = 64990) timeframe 1m` | BTC-PERP |\n| 80 | `any(venues where percentile(mark, 5, 50%, midrank) > 0) timeframe 1m` | error `DQL_ARGUMENT` |\n| 81 | `any(venues where sma(close, 3) > 0) timeframe 7m` | error `DQL_TIMEFRAME_UNSUPPORTED` |\n| 82a | `any(venues where percentile(mark, 5, 90%, nearest) > 0) timeframe 1m` | canonical `any(venues where percentile(mark, 5, 0.9) > 0) timeframe 1m` |\n| 82b | `any(venues where percentile(mark, 5, 90%, linear) > 0) timeframe 1m` | canonical `any(venues where percentile(mark, 5, 0.9, linear) > 0) timeframe 1m` |\n| 83 | `any(venues where depth_bid(25bps) > 0)` | error `DQL_ARGUMENT` |\n| 84 | `any(venues where depth_bid(50bps) > 0)` | none (BTC-PERP unknown, band_truncated) |\n| 85 | `any(venues where sma(mark_volume, 3) = 0) timeframe 15m` | BTC-PERP |\n| 86 | `any(venues where venue = BYBIT-PERP and status(mark_volume) = not_published) timeframe 15m` | BTC-PERP |\n| 87 | `any(venues where depth_bid_value(1bps) = 324992) as of 2026-09-21T09:30:04Z` | BTC-PERP |\n| 88 | `any(venues where depth_bid_value(1bps) > 0) as of 2026-09-21T09:30:03Z` | none (BTC-PERP unknown, no_value) |\n| 89 | `any(venues where funding > 0) where venue = HYPERLIQUID` | BTC-PERP, SOL-PERP |\n| 90 | `venues_listed = 1 where venue = BINANCE-USDM` | BTC-PERP, ETH-PERP |\n| 91 | `any(venues where mark > 0) where symbol = \"BTCUSDT\"` | BTC-PERP |\n| 92 | `any(venues where mark > 0) where symbol = BTCUSDT` | error `DQL_TYPE` |\n| 93 | `any(venues where mark > 0) where venue = \"HYPERLIQUID\"` | error `DQL_TYPE` |\n| 94a | `sum(venues, oi) > 0` | error `DQL_TYPE`; with `units: published` |\n| 94b | `sum(venues, oi) > 0` | BTC-PERP, ETH-PERP, SOL-PERP (as corpus test 14) |\n| 95 | `any(venues where funding > 0) where base = BTC timeframe 1m` | canonical `any(venues where funding > 0) timeframe 1m where base = BTC` |\n| 96 | `any(venues where crossunder(sma(close, 3), close)) timeframe 15m` | BTC-PERP |\n| 97 | `all(venues where crossunder(close, sma(close, 3))) timeframe 15m` | none |\n| 98 | `any(venues where basis > 0.001)` | BTC-PERP |\n| 99 | `any(venues where index > 64000)` | BTC-PERP |\n| 100 | `count(venues where funding_interval = 8h) >= 2` | ETH-PERP |\n| 101 | `any(venues where time_to_funding < 1h)` | BTC-PERP |\n| 102 | `any(venues where volume_24h > 10000)` | BTC-PERP |\n| 103 | `any(venues where turnover_24h > 800000000)` | BTC-PERP |\n| 104 | `any(venues where change_24h < 0)` | BTC-PERP |\n| 105 | `any(venues where min_qty <= 0.001)` | BTC-PERP |\n| 106 | `any(venues where index_close > 0) timeframe 15m` | none |\n| 107 | `any(venues where index_volume > 0) timeframe 15m` | none |\n| 108 | `any(venues where volume_24h > 0) where base = SOL` | none |\n\n---\n\n\n# Decided, deferred and not planned\n\nWhat the language has decided, what it has deferred, and what it will not do.\n\nA language's edges are as much a part of it as its middle. Everything below was decided rather than\nforgotten, and each row says where the decision is written down. Nothing here is a bug, and nothing here\nis a promise.\n\nDraft 1 ended with ten open questions; change set 04 answered most, the implementation settled\nseveral more, and the platform measured two. Each row below is either **decided**, with the section\nthat now states it, or **open**, with what is missing.\n\n| # | Question | Status |\n|---|---|---|\n| 1 | `as of` on every layer | **decided**: the engine reads cold storage for every layer (ADR-018); §11 |\n| 2 | Instrument identity | **decided**: an instrument is a market code, `BTC-PERP`; §8.1 |\n| 3 | Capability registry history | **decided**: not versioned; a historical answer uses the registry as it stands. **Open in part**: the decision said a response would state that moment as `capabilities_as_of`, and nothing writes it (§26) |\n| 4 | Units of `oi`, `volume_24h`, depth | **decided**: requested per query, every value states its own; §8.5 |\n| 5 | Funding on oracle venues | **deferred**: no oracle venue is collected |\n| 6 | Derived candle rule | **decided**: a derived candle exists only when every base minute exists; §7.2 |\n| 7 | Freshness defaults | **decided**: measured cadences sit well inside them; §8.4 |\n| 8 | Settle window | **decided**: measured, 120 s; §11.5 |\n| 9 | Spot instruments and tape functions | **out of v1**; §17.1 below |\n| 10 | Public tags | **moot**: alerts left the API; §12.3 |\n| 11 | Mark and index candles | **decided**: Kraken publishes them, Hyperliquid does not; §8.6 |\n| 12 | Cross-instrument references | **deferred**; §17.1 below |\n| 13 | Book levels under `as of` | **decided**: metrics only, never the raw book; §7.4a |\n| 14 | Contract rules per listing | **decided**: in the reference layer where the venue publishes them; §8.2 |\n| 15 | ADR-016 supersession | **decided**: yes (ADR-018) |\n| 17 | Funding normalisation | **decided**: identity on both venues |\n| 18 | v1 aliasing | **decided**: no |\n| 19 | Batch and rate numbers | **decided**: §13.1 |\n| 21 | Band reference price | **decided**: the mid; §7.4a |\n| 22 | Band sets per group | **decided**: platform-wide; §7.4a |\n| 23 | Book cadence | **decided**: live |\n| 25 | Kraken's funding interval | **open**: Kraken does not publish the interval. Leave `funding_interval` null, or record a documented venue constant (`1h`, provenance `venue_documentation`). Operator's decision |\n| 26 | `capabilities_as_of` | **open**: decided in C4-03, absent from the code. Either every `/v2` answer carries the registry instant it was resolved against, or the decision is withdrawn and §11.2 says the registry is always current |\n| 27 | Which venues `/v2` shows | **open**: `/v2` shows a venue only once its public code is *published*. Bybit and OKX are collected and invisible there. Either publishing is part of bringing a venue online, or the language shows collected venues and marks them unpublished |\n\n### 17.1 Not yet\n\nDeliberately absent from v1, with the reason. None of these is a gap to be filled quietly: each\nwould change what a query means, so each needs a change set of its own.\n\n| Feature | Why not yet |\n|---|---|\n| Boolean series and `count_if(condition, n)` | A boolean series would need a second type of series with its own null rules; the useful cases (`crossover`, `gaps`) are already functions |\n| Cross-instrument references (`BTC-PERP.mark` inside an `ETH-PERP` row) | Evaluation is per instrument by construction (§5); a reference across instruments makes the universe a join and the cost unbounded |\n| Sub-minute sampling | The stored granularity is one second for snapshot layers, but a series at a sub-minute period would imply candles nobody published; `snapshots/history` with an interval answers the same question honestly |\n| `mark_sampled` and other synthetic series | A series built by DEBYKO from its own samples is not what a venue published, and the language's rule is that a value is what a venue published |\n| Spot instruments, trade-tape functions (VWAP, trade counts) | Out of v1 scope; the grammar has room (`market = spot`, `trades_1m`) and the registry does not yet carry them |\n| User-defined functions, variables, `let` | A query is one expression on purpose: it can be printed, canonicalised, hashed and replayed |\n\n---\n\n\n# Language changelog\n\nHow DQL changed, set by set.\n\nThe language reached its current shape through four change sets. They are kept because a client written\nagainst an earlier one needs to know what moved, and because a decision is easier to argue with when you\ncan see when it was taken.\n\nNothing in a change set was a breaking change to a released client: the platform had no public clients\nwhile they were made. From here on, a change that would break one gets its own note here first.\n\n## DQL v1 — Change Set 01\n\n- 0. Verdict on the review\n- 1. C1-01 — Sampled snapshot series\n- Motivation\n- Amendments\n- 2. C1-02 — Functions: `abs`, `rolling_sum`, `percentile`, `percentile_rank`\n- 3. C1-03 — Fields: `bid_size`, `ask_size`, `tick_size`, `lot_size`, `min_qty`\n- 4. C1-04 — Book depth within a price band (replaces the top-25 sums)\n- 5. C1-05 — `select` clause (projection)\n- 6. C1-06 — Multi-key `order by`\n- 7. C1-07 — Numeric precision in responses\n- 8. C1-08 — Small corrections to draft 1\n- 9. Conformance additions\n- 9.1 Fixture additions (§16.1)\n- 9.2 Queries and expected results (§16.2, continued)\n- 10. Guide additions (new cookbook entries)\n- 4.16 Mark price up more than half a percent in five minutes, on three venues or more\n- 4.17 Spread below its own 24-hour 90th percentile\n- 4.18 At least 50 000 quote units resting within 10 bps of mid on the bid side, on any venue\n- 4.19 Ask for values you are not filtering on, and order by two keys\n- Guide §6 (missing data) — add one line to the table\n- Guide §7 (Pine) — add\n- Guide §8 (SQL) — add\n- 11. Rejected and deferred, with reasons\n- 12. Notes for the data endpoints (outside DQL)\n- 13. Open questions added to §17\n\n## DQL and Market-Data API — Change Set 02 (bot migration readiness)\n\n- 0. Verdict on the second review\n- 1. C2-01 — Timeframes `2m`, `3m`, `12h`\n- 2. C2-02 — Mark-price and index-price candle sources\n- 3. C2-03 — `percentile` method argument\n- 4. C2-04 — Instruments contract: `GET /v2/instruments`\n- 5. C2-05 — Latest snapshots contract: `POST /v2/snapshots`\n- 6. C2-06 — Snapshot history contract: `POST /v2/snapshots/history`\n- 7. C2-07 — Candles contract: `POST /v2/candles`\n- 8. C2-08 — Order books contract: `POST /v2/books`\n- 9. C2-09 — Batch limits, numbers, consistency\n- 10. Migration protocol: source change ≠ indicator change\n- 11. Rejected and still deferred\n- 12. Open questions added\n- 13. Conformance additions (DQL only; endpoint contracts get contract tests, not corpus entries)\n\n## DQL and Market-Data API — Change Set 03\n\n- 0. Verdict on the third review\n- 1. C3-01 — Liquidity band metrics (supersedes C1-04 and change-set-02 §8 for liquidity)\n- 1.1 Definition (ingestion time)\n- 1.2 Exposure in the data endpoints\n- 1.3 DQL (replaces the C1-04 rules)\n- 1.4 Cadence disclosure\n- 2. C3-02 — Candle volume \"as published\"; `mark_volume` / `index_volume` sources\n- 3. C3-03 — Corrections to change-set-02 text\n- 3.1 Hydration (replaces the last paragraph of change set 02 §6)\n- 3.2 Cycle alignment (replaces the `2m` row of change set 02 §0 and the sentence in §1)\n- 3.3 Settled replay (replaces the `settled` rule of change set 02 §6)\n- 4. C3-04 — `include_raw` on `GET /v2/instruments`; rules normalisation\n- 5. C3-05 — Migration protocol additions (change set 02 §10)\n- 6. Open questions added\n- 7. Conformance updates\n\n## DQL and Market-Data API — Change Set 04 (platform decisions)\n\n- 1. C4-01 — An instrument is a market; `instrument` and `base` fields\n- 2. C4-02 — `where`: selection is part of the language\n- 2.1 Grammar\n- 2.2 Semantics\n- 2.3 Every endpoint selects with `where`\n- 3. C4-03 — Venue codes come from the registry: `GET /v2/venues`\n- 4. C4-04 — Units are requested, and every value states its own\n- 5. C4-05 — Alerts leave the API\n- 6. C4-06 — The platform as it is (facts replacing assumptions)\n- 7. C4-07 — Endpoint set of v2\n- 7a. C4-08 — `GET /v2/stream` (decision 2026-09-22)\n- 8. Open questions — status\n- 9. Conformance additions\n\nThe full text of each set is in the repository under `docs/engineering/api/history/`. The specification\nhas absorbed all of them: where the two disagree, the specification is right and the change set is\nhistory.\n\n\n# Migrating from exchange APIs\n\nMoving a bot off an exchange's own API, or off several.\n\nThis page is about the differences that actually cost you time. It is not a sales pitch; where the platform is\nworse for your case, it says so.\n\n## What you stop writing\n\n**One client instead of N.** Every venue's REST is its own dialect: its own symbols, its own rate limits, its\nown funding convention, its own idea of what a \"24h change\" is. Here there is one request shape and one answer\nshape, and the venue's own spelling comes back in `venue_symbol` for when you need to send an order.\n\n**One question instead of N round trips.** \"Which instruments have positive funding on at least three venues,\nwhere the funding reading is under two minutes old\" is one query:\n\n```dql\ncount(venues where funding_8h > 0 and age(funding) < 2m) >= 3\n```\n\nAgainst exchange APIs that is a fan-out, a join, and a set of decisions about what to do when one venue is slow\nto answer — decisions you would be making in your own code, silently, differently each time.\n\n**Normalisation you did not write.** Funding is per-interval as the venue publishes it, and `funding_8h` is the\ncomparable figure; the transform is stated per listing in `GET /v2/instruments` so you can check it rather than\ntrust it.\n\n## What changes in how you think\n\n**A missing value is not a zero.** Exchange APIs are inconsistent about this — some omit a field, some send\nnull, some send `0`, some send the last value they had. Here a value is always an object with a status, and\nfive things are told apart: present, stale, missing, not published by the venue, not collected by the\nplatform. Code that treated absence as zero will need a branch. That branch is the bug you had.\n\n**Comparisons can answer *unknown*.** If a reading is stale, `funding > 0` is neither true nor false. `all(...)`\nover a set with one stale reading is unknown, not false. Ask for `include_unknown` and you get those instruments\nback labelled, instead of a screen that quietly narrowed itself.\n\n**Time is receipt time.** A historical answer uses what was visible at that instant, not what is known now. A\nreading that arrived late was not available to you then, and a backtest that used it would be measuring\ninformation you did not have.\n\n**Venues are never averaged.** There is no \"the price of BTC\". If you want one, you compute it, and you will\nhave to decide what to do about the venue that is stale — which is the decision the platform refuses to make\nfor you.\n\n## A rough map\n\n| what you did | what you do here |\n| --- | --- |\n| `GET /fapi/v1/premiumIndex` per venue | `POST /v2/snapshots` with `where`, or a DQL condition on `funding` |\n| `GET /fapi/v1/klines` per symbol, per venue | `POST /v2/candles`, many listings in one request |\n| `GET /api/v3/depth`, then compute depth yourself | `POST /v2/books`, or `depth_bid_value(10bps)` in a query |\n| exchange info for tick size and lot size | `GET /v2/instruments` |\n| a websocket per venue, reconnect logic per venue | `GET /v2/stream`, one connection, `Last-Event-ID` |\n| your own staleness heuristics | `status(...)` and `age(...)`, stated per value |\n\n## What the platform does not give you\n\nSaid plainly, because finding out later is worse:\n\n- **No orders.** This is data. It will tell you the tick size; it will not place anything.\n- **No spot.** Perpetual futures only.\n- **No raw trade tape in v2.** The trade layer exists in the live surface; it is not part of the language yet.\n- **No per-venue websocket parity.** The stream carries the layers the platform collects, at the platform's\n  cadence, not every message the venue emits.\n- **Only the venues in [Venues in DQL](#venues-in-dql).** A venue the platform does not collect is not there,\n  and the list is read live rather than promised.\n\n## The first hour\n\n1. `GET /v2/venues` and `GET /v2/dql/catalogue` — no key. Learn what exists and what a query may name.\n2. Write the condition you care about and send it to `POST /v2/dql/parse` until it parses. Still no key.\n3. Get a key, run it on `POST /v2/screen` with `include_unknown: true`, and look at what came back *unknown* —\n   that is your real coverage.\n4. Replace your staleness heuristics with `status(...)` and delete them.\n",
    "version": "2"
  },
  "servers": [
    {
      "url": "http://127.0.0.1:5399/"
    }
  ],
  "paths": {
    "/v2/venues": {
      "get": {
        "tags": [
          "Coverage"
        ],
        "summary": "Every venue collected, with its public code and what it quotes",
        "responses": {
          "200": {
            "description": "Every venue in DQL, with how many listings it has and how many of them the platform collects.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VenuesResponse"
                },
                "examples": {
                  "every venue in DQL": {
                    "summary": "What the platform collects, and how much of each venue it collects — `listings` is what the venue lists, `listings_collected` is what is actually gathered.",
                    "description": "Live data, captured from the public endpoints. 2026-09-23T11:28:26.904Z.",
                    "value": {
                      "evaluated_at": "2026-09-23T11:28:26.904Z",
                      "items": [
                        {
                          "venue": "HYPERLIQUID",
                          "name": "Hyperliquid",
                          "kind": "order_book",
                          "listings": 234,
                          "listings_collected": 5,
                          "since": "2026-09-21T12:03:13.315Z"
                        },
                        {
                          "venue": "KRAKEN-FUTURES",
                          "name": "Kraken Futures",
                          "kind": "order_book",
                          "listings": 296,
                          "listings_collected": 5,
                          "since": "2026-09-20T15:11:19.524Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v2/instruments": {
      "get": {
        "tags": [
          "Coverage"
        ],
        "summary": "Every instrument, and the listing of it on each venue that quotes it",
        "responses": {
          "200": {
            "description": "Every selected listing: how its venue names it, what it trades under, and what is collected for it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstrumentsResponse"
                },
                "examples": {
                  "one asset across its venues": {
                    "summary": "`?where=base = BTC` — every BTC listing, with the symbol each venue uses, its contract rules and what is collected for it.",
                    "description": "Live data, captured from the public endpoints. 2026-09-23T11:28:26.904Z.",
                    "value": {
                      "evaluated_at": "2026-09-23T11:28:27.118Z",
                      "as_of": "2026-09-23T11:28:27.118Z",
                      "catalogue": "2026-09-22",
                      "units": "published",
                      "items": [
                        {
                          "instrument": "BTC-PERP",
                          "venue": "HYPERLIQUID",
                          "venue_symbol": "BTC",
                          "base": "BTC",
                          "base_venue_alias": null,
                          "quote": "USDC",
                          "kind": "perpetual",
                          "venue_kind": null,
                          "pair": null,
                          "status": "tradeable",
                          "post_only": null,
                          "contract_size": 1,
                          "multiplier": 1,
                          "tick_size": null,
                          "lot_size": null,
                          "min_qty": null,
                          "min_notional": null,
                          "price_decimals": null,
                          "qty_decimals": 5,
                          "units": {
                            "tick_size": "quote",
                            "lot_size": "base",
                            "min_qty": "base",
                            "min_notional": "quote"
                          },
                          "funding_interval": "1h",
                          "funding_interval_source": "venue",
                          "funding_normalisation": {
                            "venue_field": "funding",
                            "transform": "identity"
                          },
                          "rules_normalisation": {
                            "funding_interval": {
                              "venue_field": "fundingIntervalHours",
                              "transform": "hours_to_duration"
                            },
                            "qty_decimals": {
                              "venue_field": "szDecimals",
                              "transform": "identity"
                            }
                          },
                          "candles": {
                            "base_timeframe": "1m",
                            "price_types": [
                              "trade"
                            ],
                            "timeframes": [
                              "1m",
                              "2m",
                              "3m",
                              "5m",
                              "15m",
                              "30m",
                              "1h",
                              "4h",
                              "12h",
                              "1d"
                            ]
                          },
                          "layers": {
                            "ticker": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "mark": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "funding": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "oi": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "book": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "stats": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "candles": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "trades": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "book_bands": {
                              "policy": "on",
                              "cadence": "live"
                            }
                          },
                          "not_published": [
                            "change_24h",
                            "index_close",
                            "index_high",
                            "index_low",
                            "index_open",
                            "index_volume",
                            "mark_close",
                            "mark_high",
                            "mark_low",
                            "mark_open",
                            "mark_volume"
                          ],
                          "bands": [
                            "10bps",
                            "25bps",
                            "50bps",
                            "100bps"
                          ],
                          "listed_at": null,
                          "first_seen_at": "2026-09-21T20:05:09.829Z",
                          "delisted_at": null,
                          "venue_ts": null,
                          "received_at": "2026-09-23T11:20:39.343Z",
                          "age_ms": 467774
                        },
                        {
                          "instrument": "BTC-PERP",
                          "venue": "KRAKEN-FUTURES",
                          "venue_symbol": "PF_XBTUSD",
                          "base": "BTC",
                          "base_venue_alias": null,
                          "quote": "USD",
                          "kind": "perpetual",
                          "venue_kind": "flexible_futures",
                          "pair": "BTC:USD",
                          "status": "tradeable",
                          "post_only": false,
                          "contract_size": 1,
                          "multiplier": 1,
                          "tick_size": 1,
                          "lot_size": null,
                          "min_qty": null,
                          "min_notional": null,
                          "price_decimals": null,
                          "qty_decimals": 4,
                          "units": {
                            "tick_size": "quote",
                            "lot_size": "base",
                            "min_qty": "base",
                            "min_notional": "quote"
                          },
                          "funding_interval": null,
                          "funding_interval_reason": "venue_capability",
                          "funding_normalisation": {
                            "venue_field": "relative_funding_rate",
                            "transform": "identity"
                          },
                          "rules_normalisation": {
                            "contract_size": {
                              "venue_field": "contractSize",
                              "transform": "identity"
                            },
                            "qty_decimals": {
                              "venue_field": "contractValueTradePrecision",
                              "transform": "identity"
                            },
                            "tick_size": {
                              "venue_field": "tickSize",
                              "transform": "identity"
                            }
                          },
                          "candles": {
                            "base_timeframe": "1m",
                            "price_types": [
                              "trade",
                              "mark",
                              "index"
                            ],
                            "timeframes": [
                              "1m",
                              "2m",
                              "3m",
                              "5m",
                              "15m",
                              "30m",
                              "1h",
                              "4h",
                              "12h",
                              "1d"
                            ]
                          },
                          "layers": {
                            "ticker": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "mark": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "funding": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "oi": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "book": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "stats": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "candles": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "trades": {
                              "policy": "on",
                              "cadence": "live"
                            },
                            "book_bands": {
                              "policy": "on",
                              "cadence": "live"
                            }
                          },
                          "not_published": [
                            "funding_8h",
                            "funding_interval"
                          ],
                          "bands": [
                            "10bps",
                            "25bps",
                            "50bps",
                            "100bps"
                          ],
                          "listed_at": "2022-03-22T13:15:36Z",
                          "first_seen_at": "2026-09-21T20:05:09.829Z",
                          "delisted_at": null,
                          "venue_ts": null,
                          "received_at": "2026-09-23T11:20:44.399Z",
                          "age_ms": 462718
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v2/snapshots": {
      "post": {
        "tags": [
          "Measurements"
        ],
        "summary": "The latest value of each layer for the selected listings",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SnapshotsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The latest reading of each layer for the selected listings, and the instrument-venue pairs that do not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SnapshotsResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not current."
          },
          "429": {
            "description": "The plan's rate has been used up. `Retry-After` says when to come back."
          }
        },
        "security": [
          {}
        ]
      }
    },
    "/v2/snapshots/history": {
      "post": {
        "tags": [
          "Measurements"
        ],
        "summary": "The same snapshot as it stood at a past moment, or per second over an interval",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HistoryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The same snapshot as it stood in the past: one row per period, per named instant, or per message as it arrived.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoryResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not current."
          },
          "429": {
            "description": "The plan's rate has been used up. `Retry-After` says when to come back."
          }
        },
        "security": [
          {}
        ]
      }
    },
    "/v2/candles": {
      "post": {
        "tags": [
          "Measurements"
        ],
        "summary": "Candles for the selected listings, in any stored period and price type",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CandlesRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Completed candles, gaps written out as gaps, nothing synthesised.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CandlesResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not current."
          },
          "429": {
            "description": "The plan's rate has been used up. `Retry-After` says when to come back."
          }
        },
        "security": [
          {}
        ]
      }
    },
    "/v2/books": {
      "post": {
        "tags": [
          "Measurements"
        ],
        "summary": "Order books for the selected listings, to the depth the plan allows",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BooksRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Order books to the depth the plan allows, with the depth resting in each band around the mid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BooksResponse"
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not current."
          },
          "429": {
            "description": "The plan's rate has been used up. `Retry-After` says when to come back."
          }
        },
        "security": [
          {}
        ]
      }
    },
    "/v2/screen": {
      "post": {
        "tags": [
          "Measurements"
        ],
        "summary": "Run a DQL query across venues and return what matched",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScreenRequest"
              },
              "examples": {
                "a condition across venues": {
                  "summary": "The plainest useful query: instruments where some venue pays a positive funding rate. Every value comes back with the venue that published it, when it arrived and how old it was.",
                  "value": {
                    "query": "any(venues where funding > 0)",
                    "limit": 2
                  }
                },
                "a reading that went stale": {
                  "summary": "A stale reading is not an error and is not hidden: it comes back with its true age and `status: stale`, and it compares as unknown. This query finds the instruments that have one.",
                  "value": {
                    "query": "count(venues where status(funding) = stale) >= 1",
                    "limit": 2
                  }
                },
                "an instrument that could not be decided": {
                  "summary": "With `include_unknown` the answer also carries the instruments the data could not decide — `result: unknown` — instead of silently dropping them. A screen that hides what it could not see is a screen that lies about its coverage.",
                  "value": {
                    "query": "all(venues where funding > 0)",
                    "limit": 3,
                    "include_unknown": true
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The instruments that matched, each value with the venue that published it, when it arrived and how old it was.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScreenResponse"
                },
                "examples": {
                  "a condition across venues": {
                    "summary": "The plainest useful query: instruments where some venue pays a positive funding rate. Every value comes back with the venue that published it, when it arrived and how old it was.",
                    "description": "Fixture data: real venue codes and symbols, invented numbers.",
                    "value": {
                      "dql": "1",
                      "query": {
                        "string": "any(venues where funding > 0)",
                        "json": {
                          "dql": "1",
                          "condition": {
                            "type": "any",
                            "where": {
                              "type": "cmp",
                              "op": ">",
                              "left": {
                                "type": "field",
                                "name": "funding"
                              },
                              "right": {
                                "type": "number",
                                "value": 0
                              }
                            }
                          }
                        }
                      },
                      "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"
                                }
                              }
                            }
                          ]
                        },
                        {
                          "instrument": "ETH-PERP",
                          "result": "true",
                          "values": {},
                          "venues": [
                            {
                              "venue": "BYBIT-PERP",
                              "symbol": "ETHUSDT",
                              "quote": "USDT",
                              "values": {
                                "funding": {
                                  "value": 0.000018,
                                  "unit": "fraction",
                                  "venue": "BYBIT-PERP",
                                  "layer": "funding",
                                  "venue_ts": null,
                                  "received_at": "2026-09-23T12:00:04Z",
                                  "age_ms": 1000,
                                  "status": "present"
                                }
                              }
                            },
                            {
                              "venue": "KRAKEN-FUTURES",
                              "symbol": "PF_ETHUSD",
                              "quote": "USD",
                              "values": {
                                "funding": {
                                  "value": 0.000007,
                                  "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": "ETH-USDT-SWAP",
                              "quote": "USDT",
                              "values": {
                                "funding": {
                                  "value": null,
                                  "unit": "fraction",
                                  "venue": "OKX-PERP",
                                  "layer": "funding",
                                  "venue_ts": null,
                                  "received_at": null,
                                  "age_ms": null,
                                  "status": "missing",
                                  "reason": "no_value"
                                }
                              }
                            }
                          ]
                        }
                      ],
                      "page": {
                        "limit": 2,
                        "returned": 2,
                        "next_cursor": "eyJ0IjoiMjAyNi0wOS0yM1QxMjowMDowNVoiLCJhZnRlciI6IkVUSC1QRVJQIiwicSI6IjExZDhjM2VmZWNkZGNjNTYifQ"
                      }
                    }
                  },
                  "a reading that went stale": {
                    "summary": "A stale reading is not an error and is not hidden: it comes back with its true age and `status: stale`, and it compares as unknown. This query finds the instruments that have one.",
                    "description": "Fixture data: real venue codes and symbols, invented numbers.",
                    "value": {
                      "dql": "1",
                      "query": {
                        "string": "count(venues where status(funding) = stale) >= 1",
                        "json": {
                          "dql": "1",
                          "condition": {
                            "type": "cmp",
                            "op": ">=",
                            "left": {
                              "type": "count",
                              "where": {
                                "type": "cmp",
                                "op": "=",
                                "left": {
                                  "type": "call",
                                  "name": "status",
                                  "args": [
                                    {
                                      "type": "field",
                                      "name": "funding"
                                    }
                                  ]
                                },
                                "right": {
                                  "type": "status",
                                  "value": "stale"
                                }
                              }
                            },
                            "right": {
                              "type": "number",
                              "value": 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": {
                                "status(funding)": {
                                  "value": "stale",
                                  "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": {
                                "status(funding)": {
                                  "value": "present",
                                  "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": {
                                "status(funding)": {
                                  "value": "present",
                                  "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": {
                                "status(funding)": {
                                  "value": "present",
                                  "venue": "OKX-PERP",
                                  "layer": "funding",
                                  "venue_ts": null,
                                  "received_at": "2026-09-23T12:00:04Z",
                                  "age_ms": 1000,
                                  "status": "present"
                                }
                              }
                            }
                          ]
                        }
                      ],
                      "page": {
                        "limit": 2,
                        "returned": 1,
                        "next_cursor": null
                      }
                    }
                  },
                  "an instrument that could not be decided": {
                    "summary": "With `include_unknown` the answer also carries the instruments the data could not decide — `result: unknown` — instead of silently dropping them. A screen that hides what it could not see is a screen that lies about its coverage.",
                    "description": "Fixture data: real venue codes and symbols, invented numbers.",
                    "value": {
                      "dql": "1",
                      "query": {
                        "string": "all(venues where funding > 0)",
                        "json": {
                          "dql": "1",
                          "condition": {
                            "type": "all",
                            "where": {
                              "type": "cmp",
                              "op": ">",
                              "left": {
                                "type": "field",
                                "name": "funding"
                              },
                              "right": {
                                "type": "number",
                                "value": 0
                              }
                            }
                          }
                        }
                      },
                      "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"
                                }
                              }
                            }
                          ]
                        },
                        {
                          "instrument": "ETH-PERP",
                          "result": "unknown",
                          "values": {},
                          "venues": [
                            {
                              "venue": "BYBIT-PERP",
                              "symbol": "ETHUSDT",
                              "quote": "USDT",
                              "values": {
                                "funding": {
                                  "value": 0.000018,
                                  "unit": "fraction",
                                  "venue": "BYBIT-PERP",
                                  "layer": "funding",
                                  "venue_ts": null,
                                  "received_at": "2026-09-23T12:00:04Z",
                                  "age_ms": 1000,
                                  "status": "present"
                                }
                              }
                            },
                            {
                              "venue": "KRAKEN-FUTURES",
                              "symbol": "PF_ETHUSD",
                              "quote": "USD",
                              "values": {
                                "funding": {
                                  "value": 0.000007,
                                  "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": "ETH-USDT-SWAP",
                              "quote": "USDT",
                              "values": {
                                "funding": {
                                  "value": null,
                                  "unit": "fraction",
                                  "venue": "OKX-PERP",
                                  "layer": "funding",
                                  "venue_ts": null,
                                  "received_at": null,
                                  "age_ms": null,
                                  "status": "missing",
                                  "reason": "no_value"
                                }
                              }
                            }
                          ]
                        },
                        {
                          "instrument": "SOL-PERP",
                          "result": "true",
                          "values": {},
                          "venues": [
                            {
                              "venue": "HYPERLIQUID",
                              "symbol": "SOL",
                              "quote": "USDC",
                              "values": {
                                "funding": {
                                  "value": 0.0000125,
                                  "unit": "fraction",
                                  "venue": "HYPERLIQUID",
                                  "layer": "funding",
                                  "venue_ts": null,
                                  "received_at": "2026-09-23T12:00:04Z",
                                  "age_ms": 1000,
                                  "status": "present"
                                }
                              }
                            }
                          ]
                        }
                      ],
                      "page": {
                        "limit": 3,
                        "returned": 3,
                        "next_cursor": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not current."
          },
          "429": {
            "description": "The plan's rate has been used up. `Retry-After` says when to come back."
          }
        },
        "security": [
          {}
        ]
      }
    },
    "/v2/dql/parse": {
      "post": {
        "tags": [
          "Coverage"
        ],
        "summary": "Check a query without running it",
        "description": "Answers with the position of the first problem and what was expected there, so an editor can underline it.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParseRequest"
              },
              "examples": {
                "a query checked, not run": {
                  "summary": "What the platform understood, what the query reads, and what it costs — without touching market data or a key.",
                  "value": {
                    "query": "any(venues where funding > 0)"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The query in canonical form, what it reads and what it costs — without reading any market data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParseResponse"
                },
                "examples": {
                  "a query checked, not run": {
                    "summary": "What the platform understood, what the query reads, and what it costs — without touching market data or a key.",
                    "description": "Live data, captured from the public endpoints. 2026-09-23T11:28:26.904Z.",
                    "value": {
                      "dql": "1",
                      "query": {
                        "string": "any(venues where funding > 0)",
                        "json": {
                          "dql": "1",
                          "condition": {
                            "type": "any",
                            "where": {
                              "type": "cmp",
                              "op": ">",
                              "left": {
                                "type": "field",
                                "name": "funding"
                              },
                              "right": {
                                "type": "number",
                                "value": 0
                              }
                            }
                          }
                        }
                      },
                      "atoms": {
                        "instrument": [],
                        "venue": [
                          "funding"
                        ]
                      },
                      "timeframes": [],
                      "complexity": {
                        "nodes": 4,
                        "bars": 0,
                        "cost": 4
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v2/dql/catalogue": {
      "get": {
        "tags": [
          "Coverage"
        ],
        "summary": "What a query may ask for: fields, layers, timeframes, units and every limit",
        "description": "Read this rather than hard-coding a list: it is generated from the registry and the policy the collectors run on, so it changes the moment the platform does.",
        "responses": {
          "200": {
            "description": "Every field, source, function, code and limit a query may use, as data rather than as prose.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogueResponse"
                },
                "examples": {
                  "everything a query may name": {
                    "summary": "Read this instead of hard-coding a list of fields, functions, venues or limits.",
                    "description": "Live data, captured from the public endpoints. 2026-09-23T11:28:26.904Z.",
                    "value": {
                      "dql": "1",
                      "catalogue": "2026-09-22",
                      "evaluated_at": "2026-09-23T11:28:26.994Z",
                      "fields": [
                        {
                          "name": "instrument",
                          "type": "code",
                          "scope": "instrument",
                          "layer": "reference",
                          "unit": "code",
                          "description": "the market code, e.g. BTC-PERP",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "base",
                          "type": "code",
                          "scope": "instrument",
                          "layer": "reference",
                          "unit": "code",
                          "description": "the base asset's registry code, e.g. BTC",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "venues_listed",
                          "type": "number",
                          "scope": "instrument",
                          "layer": "reference",
                          "unit": "count",
                          "description": "number of (selected) listings at T",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "venues_answered",
                          "type": "number",
                          "scope": "instrument",
                          "layer": "reference",
                          "unit": "count",
                          "description": "number of (selected) listings whose mark is present at T",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "venue",
                          "type": "code",
                          "scope": "venue",
                          "layer": "reference",
                          "unit": "code",
                          "description": "the venue's public code",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "quote",
                          "type": "code",
                          "scope": "venue",
                          "layer": "reference",
                          "unit": "code",
                          "description": "the listing's quote currency",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "tick_size",
                          "type": "number",
                          "scope": "venue",
                          "layer": "reference",
                          "unit": "quote",
                          "description": "minimum price increment of the listing",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "lot_size",
                          "type": "number",
                          "scope": "venue",
                          "layer": "reference",
                          "unit": "quantity",
                          "description": "minimum quantity increment",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "min_qty",
                          "type": "number",
                          "scope": "venue",
                          "layer": "reference",
                          "unit": "quantity",
                          "description": "minimum order quantity",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "last",
                          "type": "number",
                          "scope": "venue",
                          "layer": "ticker",
                          "unit": "quote",
                          "description": "last trade price",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "mark",
                          "type": "number",
                          "scope": "venue",
                          "layer": "mark",
                          "unit": "quote",
                          "description": "venue mark price",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "index",
                          "type": "number",
                          "scope": "venue",
                          "layer": "mark",
                          "unit": "quote",
                          "description": "venue index price",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "basis",
                          "type": "number",
                          "scope": "venue",
                          "layer": "mark",
                          "unit": "fraction",
                          "description": "(mark − index) / index",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "funding",
                          "type": "number",
                          "scope": "venue",
                          "layer": "funding",
                          "unit": "fraction",
                          "description": "published rate for the next settlement, per interval",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "funding_interval",
                          "type": "duration",
                          "scope": "venue",
                          "layer": "funding",
                          "unit": "ms",
                          "description": "settlement interval as published",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": [
                            "KRAKEN-FUTURES"
                          ]
                        },
                        {
                          "name": "funding_8h",
                          "type": "number",
                          "scope": "venue",
                          "layer": "funding",
                          "unit": "fraction",
                          "description": "funding × 8h / funding_interval",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": [
                            "KRAKEN-FUTURES"
                          ]
                        },
                        {
                          "name": "time_to_funding",
                          "type": "duration",
                          "scope": "venue",
                          "layer": "funding",
                          "unit": "ms",
                          "description": "next_funding_at − T",
                          "sampleable": false,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "oi",
                          "type": "number",
                          "scope": "venue",
                          "layer": "oi",
                          "unit": "quantity",
                          "description": "open interest",
                          "sampleable": true,
                          "additive": true,
                          "not_published_on": []
                        },
                        {
                          "name": "bid",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "quote",
                          "description": "best bid price",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "ask",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "quote",
                          "description": "best ask price",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "mid",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "quote",
                          "description": "(bid + ask) / 2",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "spread",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "fraction",
                          "description": "(ask − bid) / mid",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": []
                        },
                        {
                          "name": "bid_size",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "quantity",
                          "description": "resting quantity at the best bid",
                          "sampleable": true,
                          "additive": true,
                          "not_published_on": []
                        },
                        {
                          "name": "ask_size",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "quantity",
                          "description": "resting quantity at the best ask",
                          "sampleable": true,
                          "additive": true,
                          "not_published_on": []
                        },
                        {
                          "name": "volume_24h",
                          "type": "number",
                          "scope": "venue",
                          "layer": "stats",
                          "unit": "quantity",
                          "description": "rolling 24h traded volume as published",
                          "sampleable": true,
                          "additive": true,
                          "not_published_on": []
                        },
                        {
                          "name": "turnover_24h",
                          "type": "number",
                          "scope": "venue",
                          "layer": "stats",
                          "unit": "quote",
                          "description": "rolling 24h traded value as published",
                          "sampleable": true,
                          "additive": true,
                          "not_published_on": []
                        },
                        {
                          "name": "change_24h",
                          "type": "number",
                          "scope": "venue",
                          "layer": "stats",
                          "unit": "fraction",
                          "description": "24h price change as published",
                          "sampleable": true,
                          "additive": false,
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        }
                      ],
                      "sources": [
                        {
                          "name": "open",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "trade",
                          "unit": "quote",
                          "description": "trade candle open",
                          "not_published_on": []
                        },
                        {
                          "name": "high",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "trade",
                          "unit": "quote",
                          "description": "trade candle high",
                          "not_published_on": []
                        },
                        {
                          "name": "low",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "trade",
                          "unit": "quote",
                          "description": "trade candle low",
                          "not_published_on": []
                        },
                        {
                          "name": "close",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "trade",
                          "unit": "quote",
                          "description": "trade candle close",
                          "not_published_on": []
                        },
                        {
                          "name": "volume",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "trade",
                          "unit": "quantity",
                          "description": "trade candle volume",
                          "not_published_on": []
                        },
                        {
                          "name": "mark_open",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "mark",
                          "unit": "quote",
                          "description": "mark-price candle open",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        },
                        {
                          "name": "mark_high",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "mark",
                          "unit": "quote",
                          "description": "mark-price candle high",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        },
                        {
                          "name": "mark_low",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "mark",
                          "unit": "quote",
                          "description": "mark-price candle low",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        },
                        {
                          "name": "mark_close",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "mark",
                          "unit": "quote",
                          "description": "mark-price candle close",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        },
                        {
                          "name": "mark_volume",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "mark",
                          "unit": "quantity",
                          "description": "mark-price candle volume as published",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        },
                        {
                          "name": "index_open",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "index",
                          "unit": "quote",
                          "description": "index-price candle open",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        },
                        {
                          "name": "index_high",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "index",
                          "unit": "quote",
                          "description": "index-price candle high",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        },
                        {
                          "name": "index_low",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "index",
                          "unit": "quote",
                          "description": "index-price candle low",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        },
                        {
                          "name": "index_close",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "index",
                          "unit": "quote",
                          "description": "index-price candle close",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        },
                        {
                          "name": "index_volume",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "price_type": "index",
                          "unit": "quantity",
                          "description": "index-price candle volume as published",
                          "not_published_on": [
                            "HYPERLIQUID"
                          ]
                        }
                      ],
                      "functions": [
                        {
                          "name": "prev",
                          "signature": "prev(S, k)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "S[k]"
                        },
                        {
                          "name": "sma",
                          "signature": "sma(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "simple moving average"
                        },
                        {
                          "name": "ema",
                          "signature": "ema(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "exponential moving average over a fixed 4n window"
                        },
                        {
                          "name": "rsi",
                          "signature": "rsi(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "relative strength index, Wilder smoothing over 4n"
                        },
                        {
                          "name": "atr",
                          "signature": "atr(n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "average true range of the trade candles"
                        },
                        {
                          "name": "stdev",
                          "signature": "stdev(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "population standard deviation"
                        },
                        {
                          "name": "highest",
                          "signature": "highest(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "max(S[0] … S[n−1])"
                        },
                        {
                          "name": "lowest",
                          "signature": "lowest(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "min(S[0] … S[n−1])"
                        },
                        {
                          "name": "change",
                          "signature": "change(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "S[0] − S[n]"
                        },
                        {
                          "name": "roc",
                          "signature": "roc(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "(S[0] − S[n]) / S[n]"
                        },
                        {
                          "name": "crossover",
                          "signature": "crossover(A, B)",
                          "type": "boolean",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "A[0] > B[0] and A[1] ≤ B[1]"
                        },
                        {
                          "name": "crossunder",
                          "signature": "crossunder(A, B)",
                          "type": "boolean",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "A[0] < B[0] and A[1] ≥ B[1]"
                        },
                        {
                          "name": "gaps",
                          "signature": "gaps(n)",
                          "type": "number",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "missing periods among the last n"
                        },
                        {
                          "name": "abs",
                          "signature": "abs(x)",
                          "type": "number",
                          "scope": "venue",
                          "layer": "",
                          "unit": "none",
                          "description": "|x|, element-wise for series"
                        },
                        {
                          "name": "rolling_sum",
                          "signature": "rolling_sum(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "S[n−1] + … + S[0]"
                        },
                        {
                          "name": "percentile",
                          "signature": "percentile(S, n, p, [method])",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "nearest-rank (default) or linear percentile of S[0] … S[n−1]"
                        },
                        {
                          "name": "percentile_rank",
                          "signature": "percentile_rank(S, n)",
                          "type": "series",
                          "scope": "venue",
                          "layer": "candles",
                          "unit": "none",
                          "description": "share of S[0] … S[n−1] that are ≤ S[0]"
                        },
                        {
                          "name": "age",
                          "signature": "age(F)",
                          "type": "duration",
                          "scope": "venue",
                          "layer": "",
                          "unit": "none",
                          "description": "T − received_at of the value used for F"
                        },
                        {
                          "name": "status",
                          "signature": "status(F)",
                          "type": "status",
                          "scope": "venue",
                          "layer": "",
                          "unit": "none",
                          "description": "state of F's layer at T"
                        },
                        {
                          "name": "depth_bid",
                          "signature": "depth_bid(band)",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "quantity",
                          "description": "bid quantity within band of mid",
                          "not_published_on": []
                        },
                        {
                          "name": "depth_ask",
                          "signature": "depth_ask(band)",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "quantity",
                          "description": "ask quantity within band of mid",
                          "not_published_on": []
                        },
                        {
                          "name": "depth_bid_value",
                          "signature": "depth_bid_value(band)",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "quote",
                          "description": "bid value (price × size) within band of mid",
                          "not_published_on": []
                        },
                        {
                          "name": "depth_ask_value",
                          "signature": "depth_ask_value(band)",
                          "type": "number",
                          "scope": "venue",
                          "layer": "book",
                          "unit": "quote",
                          "description": "ask value (price × size) within band of mid",
                          "not_published_on": []
                        }
                      ],
                      "venues": [
                        "HYPERLIQUID",
                        "KRAKEN-FUTURES"
                      ],
                      "currencies": [
                        "USD",
                        "USDC"
                      ],
                      "assets": [
                        "",
                        "BTC",
                        "CYPH",
                        "DOGE",
                        "ETH",
                        "GTLB",
                        "KSTR",
                        "MSTU",
                        "OURA",
                        "SOL",
                        "XRP"
                      ],
                      "instruments": [
                        "-PERP",
                        "BTC-PERP",
                        "CYPH-PERP",
                        "DOGE-PERP",
                        "ETH-PERP",
                        "GTLB-PERP",
                        "KSTR-PERP",
                        "MSTU-PERP",
                        "OURA-PERP",
                        "SOL-PERP",
                        "XRP-PERP"
                      ],
                      "timeframes": [
                        "1m",
                        "2m",
                        "3m",
                        "5m",
                        "15m",
                        "30m",
                        "1h",
                        "4h",
                        "12h",
                        "1d"
                      ],
                      "bands": [
                        "10bps",
                        "25bps",
                        "50bps",
                        "100bps"
                      ],
                      "freshness_defaults": {
                        "ticker": "30s",
                        "mark": "30s",
                        "funding": "300s",
                        "oi": "30s",
                        "book": "30s",
                        "stats": "120s"
                      },
                      "limits": {
                        "source_bytes": 8192,
                        "nodes": 256,
                        "depth": 24,
                        "quantifiers_and_aggregates": 16,
                        "series_calls": 32,
                        "timeframes": 3,
                        "window": 500,
                        "bars_per_atom": 2000,
                        "cost": 10000,
                        "in_list": 32,
                        "select": 16,
                        "order_by": 4,
                        "freshness_min": "1s",
                        "freshness_max": "604800s",
                        "screen_limit": 500,
                        "endpoints": {
                          "snapshots_listings": 500,
                          "history_listings": 100,
                          "history_rows_per_layer": 2000,
                          "history_raw_rows": 100000,
                          "candles_listings": 100,
                          "candles_per_listing": 1500,
                          "books_listings": 100,
                          "book_depth": 25,
                          "stream_listings": 500,
                          "response_bytes": 8388608
                        }
                      },
                      "settle_after": 120,
                      "earliest_retained": "2026-09-14T00:00:00Z",
                      "units": [
                        "published",
                        "base"
                      ],
                      "number_formats": [
                        "json",
                        "string"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v2/stream": {
      "get": {
        "tags": [
          "Measurements"
        ],
        "summary": "A live stream of the selected listings, as server-sent events",
        "responses": {
          "200": {
            "description": "A server-sent event stream. One `snapshot` event per selected listing and layer, then an `update` for every change, and a `heartbeat` every fifteen seconds so silence means a broken connection rather than a quiet market. Every event carries an `id`; reconnecting with `Last-Event-ID` is answered with a fresh snapshot, never a replay.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/StreamEvent"
                }
              }
            }
          },
          "400": {
            "description": "The request or the query was refused. `code` is stable and is what to branch on; `message` explains and may be reworded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not current."
          },
          "429": {
            "description": "The plan's rate has been used up. `Retry-After` says when to come back."
          }
        },
        "security": [
          {}
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AggregateSource": {
        "required": [
          "venue",
          "value",
          "received_at",
          "age_ms"
        ],
        "type": "object",
        "properties": {
          "venue": {
            "type": "string"
          },
          "value": {
            "$ref": "#/components/schemas/Number"
          },
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "age_ms": {
            "type": [
              "null",
              "integer"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          }
        },
        "additionalProperties": false
      },
      "AggregateValue": {
        "required": [
          "value",
          "from"
        ],
        "type": "object",
        "properties": {
          "value": {
            "$ref": "#/components/schemas/Number"
          },
          "unit": {
            "$ref": "#/components/schemas/Unit"
          },
          "from": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AggregateSource"
            },
            "description": "Every venue reading the aggregate stands on, so a reader can see what it hides."
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          }
        },
        "additionalProperties": false,
        "description": "One number standing for several venues — max, min, sum, count. It has no single venue, so instead of one provenance it carries every reading it was computed from."
      },
      "ApiError": {
        "required": [
          "code",
          "message"
        ],
        "type": "object",
        "properties": {
          "code": {
            "pattern": "^DQL_[A-Z_]+$",
            "type": "string",
            "description": "The stable name of the fault. Branch on this, never on the message."
          },
          "message": {
            "type": "string",
            "description": "What is wrong, in one sentence, naming what was expected. Wording may change between releases."
          },
          "position": {
            "$ref": "#/components/schemas/ErrorPosition"
          },
          "path": {
            "type": "string",
            "description": "Where the problem is in the machine form of the query, for a request that sent JSON rather than text."
          },
          "hint": {
            "type": "string",
            "description": "What to do about it, where there is something useful to say."
          }
        },
        "additionalProperties": false
      },
      "Band": {
        "required": [
          "bid_qty",
          "bid_value",
          "bid_levels",
          "ask_qty",
          "ask_value",
          "ask_levels"
        ],
        "type": "object",
        "properties": {
          "bid_qty": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "Quantity resting on the bid side within the band."
          },
          "bid_value": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "Its value in the quote currency."
          },
          "bid_levels": {
            "type": [
              "null",
              "integer"
            ],
            "description": "How many bid levels fell inside the band."
          },
          "ask_qty": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "Quantity resting on the ask side within the band."
          },
          "ask_value": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "Its value in the quote currency."
          },
          "ask_levels": {
            "type": [
              "null",
              "integer"
            ],
            "description": "How many ask levels fell inside the band."
          },
          "bid_reason": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullReason"
              }
            ],
            "description": "Present when the bid side is null."
          },
          "ask_reason": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullReason"
              }
            ],
            "description": "Present when the ask side is null."
          }
        },
        "additionalProperties": false,
        "description": "What rests within one band of the mid, per side. A side the received book did not reach is null with `band_truncated` — never a partial sum presented as a whole one."
      },
      "BookItem": {
        "required": [
          "instrument",
          "venue",
          "venue_symbol",
          "quote",
          "status",
          "venue_ts",
          "received_at",
          "age_ms",
          "sequence",
          "bids",
          "asks",
          "levels_available",
          "mid",
          "spread"
        ],
        "type": "object",
        "properties": {
          "instrument": {
            "type": [
              "null",
              "string"
            ],
            "description": "The platform's code, or null when this listing maps to no instrument — and then `reason` says why."
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          },
          "venue": {
            "type": "string",
            "description": "The venue's public code."
          },
          "venue_symbol": {
            "type": "string",
            "description": "The venue's own symbol."
          },
          "quote": {
            "type": [
              "null",
              "string"
            ],
            "description": "What the listing is quoted in."
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "venue_ts": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "age_ms": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Milliseconds since the book was received."
          },
          "sequence": {
            "type": [
              "null",
              "integer"
            ],
            "description": "The venue's book sequence. Always null: the live layer does not keep it, and inventing one would let a client believe it could detect a gap."
          },
          "bids": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BookLevel"
            },
            "description": "Best first."
          },
          "asks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BookLevel"
            },
            "description": "Best first."
          },
          "levels_available": {
            "required": [
              "bid",
              "ask"
            ],
            "type": "object",
            "properties": {
              "bid": {
                "type": "integer",
                "description": "Bid levels shown."
              },
              "ask": {
                "type": "integer",
                "description": "Ask levels shown."
              }
            },
            "additionalProperties": false,
            "description": "How many levels are actually shown, per side."
          },
          "mid": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "The midpoint of the best levels shown, as DQL defines it."
          },
          "spread": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "The spread as a fraction of the mid."
          },
          "units": {
            "required": [
              "price",
              "size",
              "spread"
            ],
            "type": "object",
            "properties": {
              "price": {
                "type": [
                  "null",
                  "string"
                ],
                "description": "The unit of every price."
              },
              "size": {
                "type": [
                  "null",
                  "string"
                ],
                "description": "The unit of every size."
              },
              "spread": {
                "const": "fraction",
                "type": "string",
                "description": "Always a fraction."
              }
            },
            "additionalProperties": false,
            "description": "What the numbers count. Absent when there is no book to describe."
          }
        },
        "additionalProperties": false,
        "description": "One listing's book, to the depth asked for."
      },
      "BookLevel": {
        "maxItems": 2,
        "minItems": 2,
        "type": "array",
        "items": {
          "type": [
            "null",
            "string"
          ]
        },
        "description": "One level as `[price, size]`. Both are strings, always: a book is where a rounded digit becomes a wrong order."
      },
      "BooksRequest": {
        "type": "object",
        "properties": {
          "where": {
            "$ref": "#/components/schemas/Selection"
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "What quantities are expressed in.",
            "default": "published"
          },
          "number_format": {
            "enum": [
              "json",
              "string"
            ],
            "type": "string",
            "description": "`string` returns every number as a string with the same digits.",
            "default": "json"
          },
          "include_synthetic": {
            "type": "boolean",
            "description": "Include venues that exist in the registry but are not published. For the platform's own use; a public key sees nothing extra.",
            "default": false
          },
          "depth": {
            "minimum": 1,
            "type": "integer",
            "description": "Levels per side. Clamped to what the plan allows; the answer states what was applied."
          }
        },
        "additionalProperties": false,
        "description": "Order books for the selected listings."
      },
      "BooksResponse": {
        "required": [
          "evaluated_at",
          "units",
          "depth",
          "liquidity_note",
          "items"
        ],
        "type": "object",
        "properties": {
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "The unit mode applied."
          },
          "depth": {
            "type": "integer",
            "description": "How many levels per side were returned, after the plan's ceiling was applied."
          },
          "liquidity_note": {
            "type": "string",
            "description": "How the depth figures relate to the levels shown, in one sentence."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BookItem"
            },
            "description": "One object per listing."
          }
        },
        "additionalProperties": false,
        "description": "Order books for the selected listings."
      },
      "BudgetView": {
        "required": [
          "ceilingRequestsPerSecond",
          "ceilingMaxConcurrent",
          "effectiveRequestsPerSecond",
          "requestsSent",
          "observedRequestsPerSecond",
          "inFlight",
          "p50LatencyMs",
          "p95LatencyMs",
          "rateLimitedCount",
          "otherFailureCount",
          "throttleWaitMs",
          "state"
        ],
        "type": "object",
        "properties": {
          "ceilingRequestsPerSecond": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "ceilingMaxConcurrent": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "effectiveRequestsPerSecond": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "requestsSent": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "observedRequestsPerSecond": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "inFlight": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "p50LatencyMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "p95LatencyMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "rateLimitedCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "otherFailureCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "throttleWaitMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "state": {
            "type": "string"
          },
          "weightCeilingPerMinute": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "weightUsedPerMinute": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          }
        }
      },
      "Candle": {
        "required": [
          "open_time",
          "close_time",
          "open",
          "high",
          "low",
          "close",
          "volume",
          "trade_count",
          "venue_ts",
          "received_at",
          "status"
        ],
        "type": "object",
        "properties": {
          "open_time": {
            "$ref": "#/components/schemas/Instant"
          },
          "close_time": {
            "$ref": "#/components/schemas/Instant"
          },
          "open": {
            "$ref": "#/components/schemas/Number"
          },
          "high": {
            "$ref": "#/components/schemas/Number"
          },
          "low": {
            "$ref": "#/components/schemas/Number"
          },
          "close": {
            "$ref": "#/components/schemas/Number"
          },
          "volume": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "Volume over the period, in the unit named by the item's `units.volume`."
          },
          "trade_count": {
            "type": [
              "null",
              "integer"
            ],
            "description": "How many trades, where the venue publishes it; null with `reasons.trade_count` on the item where it does not."
          },
          "venue_ts": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "status": {
            "const": "present",
            "type": "string",
            "description": "Always `present` for a candle that exists."
          }
        },
        "additionalProperties": false,
        "description": "One completed period. Nothing is synthesised: a period the platform does not have is a gap row, not an interpolation, and a forming candle is never returned because only closed minutes are stored."
      },
      "CandleGap": {
        "required": [
          "open_time",
          "close_time",
          "status",
          "reason"
        ],
        "type": "object",
        "properties": {
          "open_time": {
            "$ref": "#/components/schemas/Instant"
          },
          "close_time": {
            "$ref": "#/components/schemas/Instant"
          },
          "status": {
            "const": "gap",
            "type": "string",
            "description": "Always `gap`."
          },
          "reason": {
            "enum": [
              "not_retained",
              "no_value"
            ],
            "type": "string",
            "description": "`not_retained` when the period is older than what is kept for this listing, `no_value` when nothing was ever received for it."
          }
        },
        "additionalProperties": false,
        "description": "A period with no candle. It is written out rather than left as a hole in the sequence, so a reader counting bars is never silently short."
      },
      "CandleItem": {
        "required": [
          "instrument",
          "venue",
          "venue_symbol",
          "quote",
          "status",
          "source",
          "retention_from",
          "units",
          "candles"
        ],
        "type": "object",
        "properties": {
          "instrument": {
            "type": [
              "null",
              "string"
            ],
            "description": "The platform's code, or null when this listing maps to no instrument — and then `reason` says why."
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          },
          "venue": {
            "type": "string",
            "description": "The venue's public code."
          },
          "venue_symbol": {
            "type": "string",
            "description": "The venue's own symbol."
          },
          "quote": {
            "type": [
              "null",
              "string"
            ],
            "description": "What the listing is quoted in."
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "source": {
            "enum": [
              "venue",
              "derived"
            ],
            "type": "string",
            "description": "`venue` for one-minute candles, which are the venue's own klines; `derived` for every longer period, rolled up from them. A rolled-up period exists only when every base minute of it exists."
          },
          "retention_from": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "The earliest instant candles are kept for this listing."
          },
          "units": {
            "required": [
              "price",
              "volume"
            ],
            "type": "object",
            "properties": {
              "price": {
                "type": [
                  "null",
                  "string"
                ],
                "description": "The unit of open, high, low and close."
              },
              "volume": {
                "type": [
                  "null",
                  "string"
                ],
                "description": "The unit of volume."
              }
            },
            "additionalProperties": false,
            "description": "What the numbers count."
          },
          "reasons": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/NullReason"
            },
            "description": "Why a field is null throughout. Present only when one is."
          },
          "candles": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/Candle"
                },
                {
                  "$ref": "#/components/schemas/CandleGap"
                }
              ]
            },
            "description": "Ascending by open time, gaps included."
          }
        },
        "additionalProperties": false,
        "description": "One listing's candles over the window asked for."
      },
      "CandlesRequest": {
        "required": [
          "timeframe",
          "from",
          "to"
        ],
        "type": "object",
        "properties": {
          "where": {
            "$ref": "#/components/schemas/Selection"
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "What quantities are expressed in.",
            "default": "published"
          },
          "number_format": {
            "enum": [
              "json",
              "string"
            ],
            "type": "string",
            "description": "`string` returns every number as a string with the same digits.",
            "default": "json"
          },
          "include_synthetic": {
            "type": "boolean",
            "description": "Include venues that exist in the registry but are not published. For the platform's own use; a public key sees nothing extra.",
            "default": false
          },
          "timeframe": {
            "examples": [
              "15m"
            ],
            "type": "string",
            "description": "The period. `1m` comes from the venue's own klines; every longer period is rolled up from them."
          },
          "price_type": {
            "enum": [
              "trade",
              "mark",
              "index"
            ],
            "type": "string",
            "description": "Which price.",
            "default": "trade"
          },
          "from": {
            "$ref": "#/components/schemas/Instant"
          },
          "to": {
            "$ref": "#/components/schemas/Instant"
          },
          "include_gaps": {
            "type": "boolean",
            "description": "Keep the periods with no candle, as gap rows.",
            "default": true
          },
          "closed_only": {
            "type": "boolean",
            "description": "Accepted and has no effect: only closed minutes are stored, so there is never a forming candle to return.",
            "default": true
          },
          "trade": {
            "type": "boolean",
            "description": "Reserved."
          }
        },
        "additionalProperties": false,
        "description": "Completed candles for the selected listings."
      },
      "CandlesResponse": {
        "required": [
          "evaluated_at",
          "settled",
          "items_sha256",
          "timeframe",
          "price_type",
          "from",
          "to",
          "units",
          "items"
        ],
        "type": "object",
        "properties": {
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          },
          "settled": {
            "type": "boolean",
            "description": "Whether the window is far enough in the past that a late arrival can no longer change it."
          },
          "items_sha256": {
            "pattern": "^[0-9a-f]{64}$",
            "type": "string",
            "description": "SHA-256 of `items` as serialised. Two answers with the same hash are the same answer, which is how a client can skip work rather than re-parse."
          },
          "timeframe": {
            "type": "string",
            "description": "The period returned."
          },
          "price_type": {
            "enum": [
              "trade",
              "mark",
              "index"
            ],
            "type": "string",
            "description": "Which price the candles are of."
          },
          "from": {
            "$ref": "#/components/schemas/Instant"
          },
          "to": {
            "$ref": "#/components/schemas/Instant"
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "The unit mode applied."
          },
          "listings_as_of": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "capabilities_as_of": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CandleItem"
            },
            "description": "One object per listing."
          }
        },
        "additionalProperties": false,
        "description": "Completed candles for the selected listings."
      },
      "CatalogueEndpointLimits": {
        "required": [
          "snapshots_listings",
          "history_listings",
          "history_rows_per_layer",
          "history_raw_rows",
          "candles_listings",
          "candles_per_listing",
          "books_listings",
          "book_depth",
          "stream_listings",
          "response_bytes"
        ],
        "type": "object",
        "properties": {
          "snapshots_listings": {
            "type": "integer"
          },
          "history_listings": {
            "type": "integer"
          },
          "history_rows_per_layer": {
            "type": "integer"
          },
          "history_raw_rows": {
            "type": "integer"
          },
          "candles_listings": {
            "type": "integer"
          },
          "candles_per_listing": {
            "type": "integer"
          },
          "books_listings": {
            "type": "integer"
          },
          "book_depth": {
            "type": "integer"
          },
          "stream_listings": {
            "type": "integer"
          },
          "response_bytes": {
            "type": "integer"
          }
        },
        "additionalProperties": false,
        "description": "What each data endpoint will accept in one request."
      },
      "CatalogueField": {
        "required": [
          "name",
          "type",
          "scope",
          "layer",
          "unit",
          "description",
          "sampleable",
          "additive",
          "not_published_on"
        ],
        "type": "object",
        "properties": {
          "name": {
            "examples": [
              "funding"
            ],
            "type": "string",
            "description": "As written in a query."
          },
          "type": {
            "examples": [
              "number",
              "code",
              "duration",
              "timestamp"
            ],
            "type": "string",
            "description": "The kind of value it has."
          },
          "scope": {
            "enum": [
              "instrument",
              "venue"
            ],
            "type": "string",
            "description": "Whether the name belongs to the instrument or to one venue's listing of it. A venue-scoped name must sit inside any(…), all(…), count(…) or an aggregate."
          },
          "layer": {
            "examples": [
              "funding",
              "mark",
              "book"
            ],
            "type": "string",
            "description": "The layer it is read from; its freshness bound is this layer's."
          },
          "unit": {
            "enum": [
              "quantity",
              "quote",
              "fraction",
              "ms",
              "count",
              "code",
              "none"
            ],
            "type": "string",
            "description": "What the value counts."
          },
          "description": {
            "type": "string",
            "description": "One sentence of what it is."
          },
          "sampleable": {
            "type": "boolean",
            "description": "Whether it can be read as a series once a period, not only as the latest reading."
          },
          "additive": {
            "type": "boolean",
            "description": "Whether summing it across venues means anything. `sum` refuses a field that is not additive — adding prices is a category error, not a small inaccuracy."
          },
          "not_published_on": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The venues that do not publish it — from what each venue documents, not from whether data happened to arrive. Asking for it there gives null with reason `venue_capability`, never a guess."
          }
        },
        "additionalProperties": false,
        "description": "One field a query may name."
      },
      "CatalogueFunction": {
        "required": [
          "name",
          "signature",
          "type",
          "scope",
          "layer",
          "unit",
          "description"
        ],
        "type": "object",
        "properties": {
          "name": {
            "examples": [
              "rsi",
              "depth_bid_value"
            ],
            "type": "string",
            "description": "As written in a query."
          },
          "signature": {
            "examples": [
              "rsi(source, n[, timeframe])"
            ],
            "type": "string",
            "description": "Its arguments, in order."
          },
          "type": {
            "type": "string",
            "description": "The kind of value it returns."
          },
          "scope": {
            "enum": [
              "instrument",
              "venue"
            ],
            "type": "string",
            "description": "Whether the name belongs to the instrument or to one venue's listing of it. A venue-scoped name must sit inside any(…), all(…), count(…) or an aggregate."
          },
          "layer": {
            "type": "string",
            "description": "The layer it reads, where it reads one: `candles` for a series function, `book` for a depth function, empty otherwise."
          },
          "unit": {
            "enum": [
              "quantity",
              "quote",
              "fraction",
              "ms",
              "count",
              "code",
              "none"
            ],
            "type": "string",
            "description": "What the value counts."
          },
          "description": {
            "type": "string",
            "description": "One sentence of what it computes."
          },
          "not_published_on": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The venues that do not publish it — from what each venue documents, not from whether data happened to arrive. Asking for it there gives null with reason `venue_capability`, never a guess."
          }
        },
        "additionalProperties": false,
        "description": "One function a query may call."
      },
      "CatalogueLimits": {
        "required": [
          "source_bytes",
          "nodes",
          "depth",
          "quantifiers_and_aggregates",
          "series_calls",
          "timeframes",
          "window",
          "bars_per_atom",
          "cost",
          "in_list",
          "select",
          "order_by",
          "freshness_min",
          "freshness_max",
          "screen_limit",
          "endpoints"
        ],
        "type": "object",
        "properties": {
          "source_bytes": {
            "type": "integer",
            "description": "The longest query text accepted."
          },
          "nodes": {
            "type": "integer",
            "description": "The most nodes the parsed query may have."
          },
          "depth": {
            "type": "integer",
            "description": "The deepest the expression may nest."
          },
          "quantifiers_and_aggregates": {
            "type": "integer",
            "description": "How many any/all/count/max/min/sum one query may hold."
          },
          "series_calls": {
            "type": "integer",
            "description": "How many series functions one query may call."
          },
          "timeframes": {
            "type": "integer",
            "description": "How many different periods one query may read."
          },
          "window": {
            "type": "integer",
            "description": "The largest window a series function may ask for, in periods."
          },
          "bars_per_atom": {
            "type": "integer",
            "description": "The most bars one series read may cost."
          },
          "cost": {
            "type": "integer",
            "description": "The total the query may cost. The parse endpoint tells you a query's cost before you run it."
          },
          "in_list": {
            "type": "integer",
            "description": "The longest `in (…)` list."
          },
          "select": {
            "type": "integer",
            "description": "How many values one `select` may return."
          },
          "order_by": {
            "type": "integer",
            "description": "How many keys one `order by` may have."
          },
          "freshness_min": {
            "examples": [
              "1s"
            ],
            "type": "string",
            "description": "The shortest freshness bound a query may set."
          },
          "freshness_max": {
            "examples": [
              "3600s"
            ],
            "type": "string",
            "description": "The longest freshness bound a query may set."
          },
          "screen_limit": {
            "type": "integer",
            "description": "The largest page /v2/screen will return."
          },
          "endpoints": {
            "$ref": "#/components/schemas/CatalogueEndpointLimits"
          }
        },
        "additionalProperties": false,
        "description": "Every ceiling a query meets, as numbers rather than as prose. Read them; do not hard-code them."
      },
      "CatalogueResponse": {
        "required": [
          "dql",
          "catalogue",
          "evaluated_at",
          "fields",
          "sources",
          "functions",
          "venues",
          "currencies",
          "assets",
          "instruments",
          "timeframes",
          "bands",
          "freshness_defaults",
          "limits",
          "settle_after",
          "earliest_retained",
          "units",
          "number_formats"
        ],
        "type": "object",
        "properties": {
          "dql": {
            "const": "1",
            "type": "string",
            "description": "The language version this catalogue describes."
          },
          "catalogue": {
            "type": "string",
            "description": "A version that changes whenever the catalogue's content does. Cache against it."
          },
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogueField"
            },
            "description": "Every field."
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogueSource"
            },
            "description": "Every candle source."
          },
          "functions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogueFunction"
            },
            "description": "Every function."
          },
          "venues": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every venue code a query may name."
          },
          "currencies": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every quote currency. DQL never converts between them."
          },
          "assets": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every base asset."
          },
          "instruments": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every instrument code."
          },
          "timeframes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every period a series may be read at."
          },
          "bands": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every price band the depth functions accept."
          },
          "freshness_defaults": {
            "type": "object",
            "additionalProperties": {
              "examples": [
                "5s",
                "300s"
              ],
              "type": "string",
              "description": "A duration in seconds."
            },
            "description": "The default freshness bound per layer. A reading older than its bound is stale and compares as unknown."
          },
          "limits": {
            "$ref": "#/components/schemas/CatalogueLimits"
          },
          "settle_after": {
            "type": "integer",
            "description": "Seconds after which an instant is settled: late arrivals can no longer change an answer about it."
          },
          "earliest_retained": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "The earliest instant any query may ask about."
          },
          "units": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The unit modes a request may ask for."
          },
          "number_formats": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The number formats a request may ask for."
          }
        },
        "additionalProperties": false,
        "description": "What a query may ask for, as data. Generated from the registry and the policy the collectors run on, so it changes the moment the platform does — which is why a client should read it rather than carry a copy."
      },
      "CatalogueSource": {
        "required": [
          "name",
          "type",
          "scope",
          "layer",
          "price_type",
          "unit",
          "description",
          "not_published_on"
        ],
        "type": "object",
        "properties": {
          "name": {
            "examples": [
              "close",
              "mark_close",
              "index_high"
            ],
            "type": "string",
            "description": "As written in a query."
          },
          "type": {
            "const": "series",
            "type": "string",
            "description": "Always `series`."
          },
          "scope": {
            "enum": [
              "instrument",
              "venue"
            ],
            "type": "string",
            "description": "Whether the name belongs to the instrument or to one venue's listing of it. A venue-scoped name must sit inside any(…), all(…), count(…) or an aggregate."
          },
          "layer": {
            "const": "candles",
            "type": "string",
            "description": "Always `candles`."
          },
          "price_type": {
            "enum": [
              "trade",
              "mark",
              "index"
            ],
            "type": "string",
            "description": "Which price the candles are of."
          },
          "unit": {
            "enum": [
              "quantity",
              "quote",
              "fraction",
              "ms",
              "count",
              "code",
              "none"
            ],
            "type": "string",
            "description": "What the value counts."
          },
          "description": {
            "type": "string",
            "description": "One sentence of what it is."
          },
          "not_published_on": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The venues that do not publish it — from what each venue documents, not from whether data happened to arrive. Asking for it there gives null with reason `venue_capability`, never a guess."
          }
        },
        "additionalProperties": false,
        "description": "One candle source a series function may read."
      },
      "CollectedVenue": {
        "required": [
          "venue",
          "name",
          "kind",
          "listings",
          "listings_collected",
          "since"
        ],
        "type": "object",
        "properties": {
          "venue": {
            "examples": [
              "KRAKEN-FUTURES"
            ],
            "type": "string",
            "description": "The public code to use in a query."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "The venue's own name, when it has told us one."
          },
          "kind": {
            "examples": [
              "cex",
              "dex"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "What sort of venue it is."
          },
          "listings": {
            "type": "integer",
            "description": "How many of its listings are live — everything it lists, whether or not the platform collects it."
          },
          "listings_collected": {
            "type": "integer",
            "description": "How many of those the platform actually collects. The difference is coverage, and it is stated rather than implied."
          },
          "since": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "When the platform first saw any listing of this venue. Null before the first sighting is recorded."
          }
        },
        "additionalProperties": false,
        "description": "One venue the platform collects."
      },
      "ContractUnits": {
        "required": [
          "tick_size",
          "lot_size",
          "min_qty",
          "min_notional"
        ],
        "type": "object",
        "properties": {
          "tick_size": {
            "examples": [
              "base",
              "quote",
              "contracts"
            ],
            "type": "string",
            "description": "The unit of that rule."
          },
          "lot_size": {
            "examples": [
              "base",
              "quote",
              "contracts"
            ],
            "type": "string",
            "description": "The unit of that rule."
          },
          "min_qty": {
            "examples": [
              "base",
              "quote",
              "contracts"
            ],
            "type": "string",
            "description": "The unit of that rule."
          },
          "min_notional": {
            "examples": [
              "base",
              "quote",
              "contracts"
            ],
            "type": "string",
            "description": "The unit of that rule."
          }
        },
        "additionalProperties": false,
        "description": "What each contract rule above is expressed in, after any unit conversion the request asked for."
      },
      "DatasetPolicyView": {
        "required": [
          "dataset",
          "live",
          "hot",
          "cold",
          "ruleNumber"
        ],
        "type": "object",
        "properties": {
          "dataset": {
            "type": "string"
          },
          "live": {
            "type": "string"
          },
          "hot": {
            "type": "string"
          },
          "cold": {
            "type": "string"
          },
          "ruleNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          }
        }
      },
      "DerivedValue": {
        "required": [
          "value",
          "derived",
          "atoms"
        ],
        "type": "object",
        "properties": {
          "value": {
            "$ref": "#/components/schemas/Number"
          },
          "unit": {
            "$ref": "#/components/schemas/Unit"
          },
          "derived": {
            "const": "True",
            "type": "boolean"
          },
          "atoms": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/Value"
            },
            "description": "The values this one was computed from, by name."
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          }
        },
        "additionalProperties": false,
        "description": "A value computed from others — a spread, a basis, a ratio. `atoms` holds the values it was computed from, each with its own provenance, so the result can be checked rather than believed."
      },
      "ErrorPosition": {
        "required": [
          "line",
          "column",
          "offset",
          "length"
        ],
        "type": "object",
        "properties": {
          "line": {
            "type": "integer",
            "description": "1-based."
          },
          "column": {
            "type": "integer",
            "description": "1-based."
          },
          "offset": {
            "type": "integer",
            "description": "0-based, in characters."
          },
          "length": {
            "type": "integer"
          }
        },
        "additionalProperties": false,
        "description": "Where in the query text the problem is, so an editor can underline it."
      },
      "ErrorResponse": {
        "required": [
          "errors"
        ],
        "type": "object",
        "properties": {
          "errors": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        },
        "additionalProperties": false,
        "description": "Every fault answers in this shape, whatever the status code. More than one error is reported where the platform can find more than one."
      },
      "HistoryItem": {
        "required": [
          "instrument",
          "venue",
          "venue_symbol",
          "quote",
          "layers"
        ],
        "type": "object",
        "properties": {
          "instrument": {
            "type": [
              "null",
              "string"
            ],
            "description": "The platform's code, or null when this listing maps to no instrument."
          },
          "reason": {
            "type": "string",
            "description": "Why the listing maps to no instrument. Present only when `instrument` is null."
          },
          "venue": {
            "type": "string",
            "description": "The venue's public code."
          },
          "venue_symbol": {
            "type": "string",
            "description": "The venue's own symbol."
          },
          "quote": {
            "type": [
              "null",
              "string"
            ],
            "description": "What the listing is quoted in."
          },
          "layers": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/HistoryLayer"
            },
            "description": "Each layer asked for, by name."
          }
        },
        "additionalProperties": false,
        "description": "One listing's history, layer by layer."
      },
      "HistoryLayer": {
        "required": [
          "retention_from",
          "units",
          "rows"
        ],
        "type": "object",
        "properties": {
          "retention_from": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "The earliest instant this layer is kept for this listing. A question about anything earlier answers `not_retained`."
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Status"
              }
            ],
            "description": "Present only when the layer is `off` or `not_published` throughout — then there are no rows to look at."
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "What each field counts."
          },
          "rows": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/HistoryRow"
                },
                {
                  "$ref": "#/components/schemas/HistoryRawRow"
                }
              ]
            },
            "description": "Ascending in time."
          },
          "liquidity_rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HistoryRawRow"
            },
            "description": "In `raw` mode, the book layer's band observations — a separate stream from the rows above, because the depth is measured separately from the ticker and dating one by the other would overstate it."
          }
        },
        "additionalProperties": false,
        "description": "One layer's history for one listing."
      },
      "HistoryRawRow": {
        "required": [
          "received_at",
          "venue_ts",
          "values"
        ],
        "type": "object",
        "properties": {
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "venue_ts": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "values": {
            "type": "object",
            "additionalProperties": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/Number"
                },
                {
                  "$ref": "#/components/schemas/Liquidity"
                }
              ]
            },
            "description": "The layer's fields at that point. The book layer also carries `liquidity`."
          },
          "reasons": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/NullReason"
            },
            "description": "Why a value is null, by field."
          }
        },
        "additionalProperties": false,
        "description": "One row exactly as it arrived, in `raw` mode: no sampling, no bucketing, one object per message received."
      },
      "HistoryRequest": {
        "required": [
          "from",
          "to"
        ],
        "type": "object",
        "properties": {
          "where": {
            "$ref": "#/components/schemas/Selection"
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "What quantities are expressed in.",
            "default": "published"
          },
          "number_format": {
            "enum": [
              "json",
              "string"
            ],
            "type": "string",
            "description": "`string` returns every number as a string with the same digits.",
            "default": "json"
          },
          "include_synthetic": {
            "type": "boolean",
            "description": "Include venues that exist in the registry but are not published. For the platform's own use; a public key sees nothing extra.",
            "default": false
          },
          "layers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Which layers to read."
          },
          "interval": {
            "examples": [
              "1m",
              "1h"
            ],
            "type": "string",
            "description": "One row per period of this length, each holding the last reading in it."
          },
          "at": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "An ISO-8601 UTC instant."
            },
            "description": "One row per instant, strictly ascending. `from` and `to` do not apply here — the instants are the rows."
          },
          "raw": {
            "type": "boolean",
            "description": "Every row as it arrived, unsampled.",
            "default": false
          },
          "from": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Instant"
              }
            ],
            "description": "Start of the window. Required for `interval` and `raw`."
          },
          "to": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Instant"
              }
            ],
            "description": "End of the window. Required for `interval` and `raw`."
          },
          "include_gaps": {
            "type": "boolean",
            "description": "Keep the rows that have no reading. Keeping them is the default because dropping them turns a gap into a shorter series.",
            "default": true
          },
          "freshness": {
            "examples": [
              "30s"
            ],
            "type": "string",
            "description": "Override the freshness bound for every layer asked for."
          }
        },
        "additionalProperties": false,
        "description": "The same snapshot as it stood in the past. Exactly one of `interval`, `at` and `raw: true` — they are three different questions: one row per period, one row per named instant, or every row as it arrived."
      },
      "HistoryResponse": {
        "required": [
          "evaluated_at",
          "settled",
          "items_sha256",
          "mode",
          "units",
          "freshness",
          "items"
        ],
        "type": "object",
        "properties": {
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          },
          "settled": {
            "type": "boolean",
            "description": "Whether the window is far enough in the past that a late arrival can no longer change it."
          },
          "items_sha256": {
            "pattern": "^[0-9a-f]{64}$",
            "type": "string",
            "description": "SHA-256 of `items` as serialised."
          },
          "mode": {
            "enum": [
              "interval",
              "at",
              "raw"
            ],
            "type": "string",
            "description": "Which question was asked."
          },
          "interval": {
            "type": "string",
            "description": "The period, in `interval` mode."
          },
          "from": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "The window, in `interval` and `raw` modes. Absent in `at` mode."
          },
          "to": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "The unit mode applied."
          },
          "freshness": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The bound applied per layer."
          },
          "listings_as_of": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "capabilities_as_of": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HistoryItem"
            },
            "description": "One object per listing."
          }
        },
        "additionalProperties": false,
        "description": "The snapshot as it stood in the past. `mode` says which of the three questions was asked, and the rows carry `bucket_end`, `at` or neither to match."
      },
      "HistoryRow": {
        "required": [
          "status"
        ],
        "type": "object",
        "properties": {
          "bucket_end": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Instant"
              }
            ],
            "description": "The end of the period. Present in `interval` mode."
          },
          "at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Instant"
              }
            ],
            "description": "The instant asked for. Present in `at` mode."
          },
          "status": {
            "enum": [
              "present",
              "gap"
            ],
            "type": "string",
            "description": "`present` when there is a reading, `gap` when there is none."
          },
          "reason": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullReason"
              }
            ],
            "description": "Why the point is a gap. Present only then."
          },
          "venue_ts": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "values": {
            "type": "object",
            "additionalProperties": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/Number"
                },
                {
                  "$ref": "#/components/schemas/Liquidity"
                }
              ]
            },
            "description": "The layer's fields at that point. The book layer also carries `liquidity`."
          },
          "reasons": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/NullReason"
            },
            "description": "Why a value is null, by field."
          }
        },
        "additionalProperties": false,
        "description": "One point of one layer's history. A point with no reading is a gap with its reason — never the previous value carried forward, which would invent a measurement that was not taken."
      },
      "Instant": {
        "examples": [
          "2026-09-23T12:00:05Z",
          "2026-09-23T12:00:05.250Z"
        ],
        "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{3})?Z$",
        "type": "string",
        "description": "An instant, ISO-8601, always UTC, with milliseconds only when they are not zero. Every instant the platform prints has this shape."
      },
      "InstrumentsResponse": {
        "required": [
          "evaluated_at",
          "as_of",
          "catalogue",
          "units",
          "items"
        ],
        "type": "object",
        "properties": {
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          },
          "as_of": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Instant"
              }
            ],
            "description": "The instant the answer describes: the moment of the request, or the `as_of` it asked for."
          },
          "catalogue": {
            "type": "string",
            "description": "The catalogue version the answer was built against."
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "The unit mode applied."
          },
          "listings_as_of": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "When the listing set itself was last known to change. Present when asking about the past."
          },
          "capabilities_as_of": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "When what each venue publishes was last known to change."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Listing"
            },
            "description": "The listings, one object each."
          }
        },
        "additionalProperties": false,
        "description": "Every selected listing at the instant asked about — mapped or not. No key: what exists is not a paid fact."
      },
      "LayerPolicy": {
        "required": [
          "policy",
          "cadence"
        ],
        "type": "object",
        "properties": {
          "policy": {
            "enum": [
              "on",
              "off",
              "not_published"
            ],
            "type": "string",
            "description": "`on` when collected, `off` when the listing's group does not collect it, `not_published` when the venue does not publish it at all. `off` is a choice and can change; `not_published` is a fact about the venue."
          },
          "cadence": {
            "examples": [
              "1s",
              "8h"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "How often the venue publishes it, when it says."
          }
        },
        "additionalProperties": false,
        "description": "Whether the platform collects a layer for this listing, and how often the venue publishes it."
      },
      "LayerReading": {
        "required": [
          "status",
          "venue_ts",
          "received_at",
          "values"
        ],
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          },
          "venue_ts": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "age_ms": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Milliseconds between `received_at` and the instant asked about."
          },
          "values": {
            "type": "object",
            "additionalProperties": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/Number"
                },
                {
                  "$ref": "#/components/schemas/Liquidity"
                }
              ]
            },
            "description": "The layer's fields. The book layer also carries `liquidity`."
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "What each value counts. Present only where a value has a unit."
          },
          "reasons": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/NullReason"
            },
            "description": "Why a value is null, by field. Present only where one is."
          },
          "raw": {
            "type": "object",
            "description": "The venue's message as received, when the request asked for `include_raw`."
          }
        },
        "additionalProperties": false,
        "description": "One layer as it stood at the instant asked about: what was received, when, how old it was, and whether that made it usable."
      },
      "Liquidity": {
        "required": [
          "reference",
          "status",
          "venue_ts",
          "received_at",
          "bands",
          "levels_received",
          "units"
        ],
        "type": "object",
        "properties": {
          "reference": {
            "const": "mid",
            "type": "string",
            "description": "The price the bands are measured from."
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          },
          "venue_ts": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "age_ms": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Milliseconds since it was received."
          },
          "bands": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/Band"
            },
            "description": "One entry per band of the platform's set, keyed by the band."
          },
          "levels_received": {
            "required": [
              "bid",
              "ask"
            ],
            "type": "object",
            "properties": {
              "bid": {
                "type": [
                  "null",
                  "integer"
                ],
                "description": "Bid levels received."
              },
              "ask": {
                "type": [
                  "null",
                  "integer"
                ],
                "description": "Ask levels received."
              }
            },
            "additionalProperties": false,
            "description": "How many levels the received book had, before any band was measured."
          },
          "units": {
            "required": [
              "qty",
              "value"
            ],
            "type": "object",
            "properties": {
              "qty": {
                "type": [
                  "null",
                  "string"
                ],
                "description": "The unit of every `*_qty`."
              },
              "value": {
                "const": "quote",
                "type": "string",
                "description": "The unit of every `*_value`."
              }
            },
            "additionalProperties": false,
            "description": "What the band figures count."
          }
        },
        "additionalProperties": false,
        "description": "Depth in bands around the mid, dated by its own observation rather than by the ticker's — the two arrive separately and pretending otherwise would overstate how fresh the depth is."
      },
      "Listing": {
        "required": [
          "instrument",
          "venue",
          "venue_symbol",
          "base",
          "base_venue_alias",
          "quote",
          "kind",
          "venue_kind",
          "pair",
          "status",
          "post_only",
          "contract_size",
          "multiplier",
          "tick_size",
          "lot_size",
          "min_qty",
          "min_notional",
          "price_decimals",
          "qty_decimals",
          "units",
          "funding_interval",
          "funding_normalisation",
          "rules_normalisation",
          "candles",
          "layers",
          "not_published",
          "bands",
          "listed_at",
          "first_seen_at",
          "delisted_at",
          "venue_ts",
          "received_at",
          "age_ms"
        ],
        "type": "object",
        "properties": {
          "instrument": {
            "type": [
              "null",
              "string"
            ],
            "description": "The platform's code for what this listing is. Null when the listing is mapped to no instrument, and then `reason` says why — an unmapped listing is shown rather than hidden."
          },
          "reason": {
            "type": "string",
            "description": "Why the listing is mapped to no instrument. Present only when `instrument` is null."
          },
          "venue": {
            "type": "string",
            "description": "The venue's public code."
          },
          "venue_symbol": {
            "examples": [
              "PF_XBTUSD",
              "BTC-USDT-SWAP"
            ],
            "type": "string",
            "description": "The venue's own symbol, spelled as the venue spells it. This is what you send to the venue; `instrument` is what you send to DQL."
          },
          "base": {
            "type": [
              "null",
              "string"
            ],
            "description": "The base asset."
          },
          "base_venue_alias": {
            "type": [
              "null",
              "string"
            ],
            "description": "The venue's own name for the base asset, when it differs from the platform's."
          },
          "quote": {
            "type": [
              "null",
              "string"
            ],
            "description": "What the listing is quoted in."
          },
          "kind": {
            "examples": [
              "perpetual"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "What the platform treats it as."
          },
          "venue_kind": {
            "type": [
              "null",
              "string"
            ],
            "description": "What the venue calls it."
          },
          "pair": {
            "type": [
              "null",
              "string"
            ],
            "description": "The venue's pair name, where it has one apart from the symbol."
          },
          "status": {
            "enum": [
              "tradeable",
              "halted",
              "delisted"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "`tradeable`, `halted` when the venue says it is not tradeable, `delisted` after it goes. Null when the venue does not say."
          },
          "post_only": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether the venue accepts only post-only orders here."
          },
          "contract_size": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "How much of the base one contract is."
          },
          "multiplier": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "The venue's price multiplier, where it has one."
          },
          "tick_size": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "The smallest price step. Null when it cannot be expressed in the units asked for."
          },
          "lot_size": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "The smallest quantity step."
          },
          "min_qty": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "The smallest order quantity."
          },
          "min_notional": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Number"
              }
            ],
            "description": "The smallest order value, in the quote currency."
          },
          "price_decimals": {
            "type": [
              "null",
              "integer"
            ],
            "description": "How many decimals the venue prints prices to."
          },
          "qty_decimals": {
            "type": [
              "null",
              "integer"
            ],
            "description": "How many decimals the venue prints quantities to."
          },
          "units": {
            "$ref": "#/components/schemas/ContractUnits"
          },
          "funding_interval": {
            "examples": [
              "1h",
              "8h"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "How often funding settles here."
          },
          "funding_interval_reason": {
            "examples": [
              "venue_capability"
            ],
            "type": "string",
            "description": "Why the interval is unknown. Present only when it is."
          },
          "funding_interval_source": {
            "type": "string",
            "description": "Where the interval came from when the venue does not publish it in its data — its documentation, for instance. Present only then, because a documented constant is a weaker fact than a measured one and should not pass for it."
          },
          "funding_normalisation": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Normalisation"
              },
              {
                "type": "null"
              }
            ],
            "description": "How the venue's funding figure became the platform's. Null when none was needed."
          },
          "rules_normalisation": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/Normalisation"
            },
            "description": "The same, per contract rule."
          },
          "candles": {
            "$ref": "#/components/schemas/ListingCandles"
          },
          "layers": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/LayerPolicy"
            },
            "description": "What is collected for this listing, layer by layer, plus `book_bands`."
          },
          "not_published": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every field this venue does not publish. Asking for one gives null with reason `venue_capability`."
          },
          "bands": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The price bands the depth functions can be asked for here."
          },
          "listed_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "first_seen_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "When the platform first saw this listing."
          },
          "delisted_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "When it went, if it has. Null while it is live."
          },
          "venue_ts": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "The venue's own timestamp on the instrument record."
          },
          "received_at": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NullableInstant"
              }
            ],
            "description": "When the platform received it."
          },
          "age_ms": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Milliseconds between `received_at` and the instant asked about."
          },
          "raw": {
            "type": [
              "null",
              "object"
            ],
            "description": "The venue's instrument object exactly as received. Present only when the request asked for `include_raw`; null when nothing was stored."
          }
        },
        "additionalProperties": false,
        "description": "One venue's listing of one instrument: how the venue names it, the rules it trades under, what the platform collects for it, and when it was last heard from."
      },
      "ListingCandles": {
        "required": [
          "base_timeframe",
          "price_types",
          "timeframes"
        ],
        "type": "object",
        "properties": {
          "base_timeframe": {
            "const": "1m",
            "type": "string",
            "description": "The period the platform stores and rolls every other period up from."
          },
          "price_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Which prices this venue publishes candles of. A venue missing from a price type here answers `not_published`, not zero."
          },
          "timeframes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every period that can be asked for."
          }
        },
        "additionalProperties": false,
        "description": "What candles exist for this listing."
      },
      "MarketListingView": {
        "required": [
          "segment",
          "symbol",
          "quote",
          "multiplier",
          "mappingStatus",
          "mappingSource"
        ],
        "type": "object",
        "properties": {
          "segment": {
            "type": "string"
          },
          "symbol": {
            "type": "string"
          },
          "quote": {
            "type": [
              "null",
              "string"
            ]
          },
          "multiplier": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "mappingStatus": {
            "type": [
              "null",
              "string"
            ]
          },
          "mappingSource": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "MarketView": {
        "required": [
          "code",
          "assetCode",
          "listings"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "assetCode": {
            "type": "string"
          },
          "listings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MarketListingView"
            }
          }
        }
      },
      "Normalisation": {
        "required": [
          "venue_field",
          "transform"
        ],
        "type": "object",
        "properties": {
          "venue_field": {
            "type": "string",
            "description": "The venue's own field name."
          },
          "transform": {
            "examples": [
              "identity",
              "rate / interval_hours * 8"
            ],
            "type": "string",
            "description": "What was done to it."
          }
        },
        "additionalProperties": false,
        "description": "How a venue's own field was turned into the platform's. Published so a reader can check the arithmetic rather than trust it — and so a number that looks wrong can be traced back to what the venue actually sent."
      },
      "NotListed": {
        "required": [
          "instrument",
          "venue",
          "reason"
        ],
        "type": "object",
        "properties": {
          "instrument": {
            "type": "string",
            "description": "The instrument asked for."
          },
          "venue": {
            "type": "string",
            "description": "The venue asked for."
          },
          "reason": {
            "const": "not_listed",
            "type": "string",
            "description": "Why there is nothing."
          }
        },
        "additionalProperties": false,
        "description": "An instrument and venue that were asked for and do not exist together. Returned rather than dropped: a client that asked for a pair it will never get should be told so, not left to infer it from a short answer."
      },
      "NullReason": {
        "enum": [
          "not_retained",
          "gap",
          "insufficient_history",
          "policy_off",
          "venue_capability",
          "no_value",
          "band_truncated",
          "unit_unknown",
          "unmapped"
        ],
        "type": "string",
        "description": "Why the value is null. Informative, never queryable: a query cannot branch on a reason."
      },
      "NullableInstant": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/Instant"
          },
          {
            "type": "null"
          }
        ],
        "description": "An instant, or null when there is none to state."
      },
      "Number": {
        "type": [
          "null",
          "boolean",
          "number",
          "string"
        ],
        "description": "A measured or computed value. A number by default; a string with the same digits when the request asked for `number_format: string`, which is how a client keeps digits a double would round. Booleans occur where the language's value is a truth, null where there is no value — and then the object carries a `reason`."
      },
      "Page": {
        "required": [
          "limit",
          "returned",
          "next_cursor"
        ],
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "description": "The page size that was applied."
          },
          "returned": {
            "type": "integer",
            "description": "How many instruments this page holds."
          },
          "next_cursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Pass it back to continue. Null on the last page. A cursor pins the instant, so a page taken later sees the same world as the first."
          }
        },
        "additionalProperties": false
      },
      "ParseRequest": {
        "required": [
          "query"
        ],
        "type": "object",
        "properties": {
          "query": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "object"
              }
            ],
            "description": "The query, as text or as the machine form of specification §3.1."
          },
          "dql": {
            "const": "1",
            "type": "string",
            "description": "The language version. Only `1` exists."
          },
          "context": {
            "const": "screen",
            "type": "string",
            "description": "What the query is for. Only `screen` exists."
          }
        },
        "additionalProperties": false,
        "description": "A query to check. Nothing is read and nothing is charged; an editor may call this on every keystroke."
      },
      "ParseResponse": {
        "required": [
          "dql",
          "query",
          "atoms",
          "timeframes",
          "complexity"
        ],
        "type": "object",
        "properties": {
          "dql": {
            "const": "1",
            "type": "string",
            "description": "The language version."
          },
          "query": {
            "required": [
              "string",
              "json"
            ],
            "type": "object",
            "properties": {
              "string": {
                "type": "string",
                "description": "The canonical text — what the platform understood."
              },
              "json": {
                "type": "object",
                "description": "The canonical machine form."
              }
            },
            "additionalProperties": false,
            "description": "The query in both forms, canonical."
          },
          "atoms": {
            "required": [
              "instrument",
              "venue"
            ],
            "type": "object",
            "properties": {
              "instrument": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Instrument-scoped names it reads."
              },
              "venue": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Venue-scoped names it reads."
              }
            },
            "additionalProperties": false,
            "description": "What the query reads, by scope. Useful for showing a reader which data a query depends on."
          },
          "timeframes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every period the query reads."
          },
          "complexity": {
            "required": [
              "nodes",
              "bars",
              "cost"
            ],
            "type": "object",
            "properties": {
              "nodes": {
                "type": "integer",
                "description": "Nodes in the parsed query."
              },
              "bars": {
                "type": "integer",
                "description": "Bars of history it will read."
              },
              "cost": {
                "type": "integer",
                "description": "Its total cost. Compare with `limits.cost` in the catalogue."
              }
            },
            "additionalProperties": false,
            "description": "What the query costs, against the catalogue's limits."
          }
        },
        "additionalProperties": false,
        "description": "A query checked but not run: what it means, what it will read, and what it will cost. An editor calls this on every keystroke; it touches no market data and needs no key."
      },
      "PolicyView": {
        "required": [
          "revision",
          "venue",
          "symbol",
          "group",
          "datasets"
        ],
        "type": "object",
        "properties": {
          "revision": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "uint64"
          },
          "venue": {
            "type": "string"
          },
          "symbol": {
            "type": "string"
          },
          "group": {
            "type": "string"
          },
          "datasets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DatasetPolicyView"
            }
          }
        }
      },
      "ReferenceValue": {
        "required": [
          "value",
          "from",
          "as_of"
        ],
        "type": "object",
        "properties": {
          "value": {
            "$ref": "#/components/schemas/Number"
          },
          "unit": {
            "$ref": "#/components/schemas/Unit"
          },
          "from": {
            "const": "reference",
            "type": "string"
          },
          "as_of": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          }
        },
        "additionalProperties": false,
        "description": "A field of the instrument itself rather than of a venue — it has no venue and no age, only the moment the reference data was read."
      },
      "ScreenInstrument": {
        "required": [
          "instrument",
          "result",
          "values",
          "venues"
        ],
        "type": "object",
        "properties": {
          "instrument": {
            "examples": [
              "BTC-PERP"
            ],
            "type": "string",
            "description": "The platform's code for the instrument."
          },
          "result": {
            "enum": [
              "true",
              "false",
              "unknown"
            ],
            "type": "string",
            "description": "What the condition came to for this instrument. `unknown` is its own answer, not a failure: it means the data needed to decide was missing or stale. Only instruments that came to `true` are returned unless the request asked for the others."
          },
          "values": {
            "$ref": "#/components/schemas/ValueMap"
          },
          "venues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScreenVenue"
            }
          }
        },
        "additionalProperties": false
      },
      "ScreenRequest": {
        "type": "object",
        "properties": {
          "query": {
            "examples": [
              "any(venues where funding > 0)"
            ],
            "type": "string",
            "description": "The query in DQL."
          },
          "query_object": {
            "type": "object",
            "description": "The same query in the machine form of specification §3.1."
          },
          "limit": {
            "minimum": 1,
            "type": "integer",
            "description": "How many instruments to return in one page. The catalogue states the ceiling your plan allows.",
            "default": 100
          },
          "cursor": {
            "type": "string",
            "description": "A cursor from a previous answer's `page.next_cursor`. It pins the instant, so page two sees the world page one saw."
          },
          "include_unknown": {
            "type": "boolean",
            "description": "Also return the instruments the data could not decide, with `result: unknown`, instead of dropping them. Ask for this whenever coverage matters.",
            "default": false
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "What quantities are expressed in. `published` leaves each venue's own unit alone; `base` and `quote` convert, and give null with `unit_unknown` where a contract size is not known.",
            "default": "published"
          },
          "number_format": {
            "enum": [
              "json",
              "string"
            ],
            "type": "string",
            "description": "`string` returns every number as a string with the same digits, for a client whose JSON parser would round them.",
            "default": "json"
          }
        },
        "additionalProperties": false,
        "description": "A query to run. Send exactly one of `query` (the text form) and `query_object` (the machine form); an editor that builds queries structurally sends the second and never has to quote."
      },
      "ScreenResponse": {
        "required": [
          "dql",
          "query",
          "evaluated_at",
          "as_of",
          "settled",
          "freshness",
          "instruments",
          "page"
        ],
        "type": "object",
        "properties": {
          "dql": {
            "type": "string",
            "description": "The query in canonical form — what the platform understood, which may differ in spacing and clause order from what was sent."
          },
          "query": {
            "required": [
              "string",
              "json"
            ],
            "type": "object",
            "properties": {
              "string": {
                "type": "string"
              },
              "json": {
                "type": "object",
                "description": "The parsed query. Its shape is the language's abstract syntax, given in the specification."
              }
            },
            "additionalProperties": false,
            "description": "The query echoed in both forms, so a client that sent text can keep the machine form and a client that sent the machine form can show the text."
          },
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          },
          "as_of": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "settled": {
            "type": "boolean",
            "description": "Whether the instant is far enough in the past that late arrivals can no longer change the answer. A false here means the same query may answer differently in two minutes; that is the honest state, not an error."
          },
          "timeframe": {
            "type": "string",
            "description": "The period the query's series were read at, when it asked for one."
          },
          "freshness": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "description": "A duration, e.g. `5s`, `300s`."
            },
            "description": "The bound applied to each layer: a reading older than this is stale and compares as unknown. Stated per answer because a request may override it."
          },
          "listings_as_of": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "capabilities_as_of": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "instruments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScreenInstrument"
            }
          },
          "page": {
            "$ref": "#/components/schemas/Page"
          }
        },
        "additionalProperties": false,
        "description": "The answer to a DQL query: the query as the platform read it, the instant it was answered at, and what matched."
      },
      "ScreenVenue": {
        "required": [
          "venue",
          "symbol",
          "quote",
          "values"
        ],
        "type": "object",
        "properties": {
          "venue": {
            "examples": [
              "BYBIT-PERP"
            ],
            "type": "string"
          },
          "symbol": {
            "examples": [
              "BTCUSDT"
            ],
            "type": "string",
            "description": "The venue's own symbol for the listing, as the venue spells it."
          },
          "quote": {
            "examples": [
              "USDT"
            ],
            "type": "string",
            "description": "What the listing is quoted in."
          },
          "values": {
            "$ref": "#/components/schemas/ValueMap"
          }
        },
        "additionalProperties": false,
        "description": "One venue's listing of the instrument, and the values read from it."
      },
      "SegmentBudgetView": {
        "required": [
          "segment",
          "budget"
        ],
        "type": "object",
        "properties": {
          "segment": {
            "type": "string"
          },
          "budget": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/BudgetView"
              }
            ]
          }
        }
      },
      "SegmentView": {
        "required": [
          "segment",
          "synthetic",
          "isLive"
        ],
        "type": "object",
        "properties": {
          "segment": {
            "type": "string"
          },
          "synthetic": {
            "type": "boolean"
          },
          "isLive": {
            "type": "boolean"
          }
        }
      },
      "Selection": {
        "examples": [
          "venue = BYBIT-PERP and base in (BTC, ETH)"
        ],
        "oneOf": [
          {
            "type": "string"
          },
          {
            "type": "object"
          }
        ],
        "description": "Which listings to answer for, in the DQL selection grammar — `venue = HYPERLIQUID and base = BTC`, with or without the leading `where`. The machine form of the same node is accepted as an object. Omit it and every listing is selected, which the endpoint's limits will usually refuse.\n\nUnmapped listings are selected too and come back with `instrument: null`; `instrument = X` never matches one."
      },
      "SeriesValue": {
        "required": [
          "value",
          "venue",
          "layer",
          "timeframe",
          "venue_ts",
          "received_at",
          "age_ms",
          "status"
        ],
        "type": "object",
        "properties": {
          "value": {
            "$ref": "#/components/schemas/Number"
          },
          "unit": {
            "$ref": "#/components/schemas/Unit"
          },
          "venue": {
            "type": "string"
          },
          "layer": {
            "type": "string"
          },
          "price_type": {
            "enum": [
              "trade",
              "mark",
              "index"
            ],
            "type": "string"
          },
          "timeframe": {
            "examples": [
              "1m",
              "15m",
              "1h",
              "1d"
            ],
            "type": "string",
            "description": "The period of the series."
          },
          "bars": {
            "type": "integer",
            "description": "How many periods the function read. A window that could not be filled gives null with `insufficient_history`."
          },
          "candle_end": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "sample_end": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "band": {
            "type": "string"
          },
          "reference": {
            "type": "string"
          },
          "levels": {
            "type": [
              "null",
              "integer"
            ]
          },
          "venue_ts": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "age_ms": {
            "type": [
              "null",
              "integer"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          }
        },
        "additionalProperties": false,
        "description": "A reading taken from a series — candles, or the snapshot layers sampled once a period. It carries the period it belongs to and how many bars the function needed."
      },
      "SnapshotItem": {
        "required": [
          "instrument",
          "venue",
          "venue_symbol",
          "quote",
          "layers"
        ],
        "type": "object",
        "properties": {
          "instrument": {
            "type": [
              "null",
              "string"
            ],
            "description": "The platform's code, or null when this listing maps to no instrument — and then `reason` says why."
          },
          "reason": {
            "type": "string",
            "description": "Why the listing maps to no instrument. Present only when `instrument` is null."
          },
          "venue": {
            "type": "string",
            "description": "The venue's public code."
          },
          "venue_symbol": {
            "type": "string",
            "description": "The venue's own symbol."
          },
          "quote": {
            "type": [
              "null",
              "string"
            ],
            "description": "What the listing is quoted in."
          },
          "layers": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/LayerReading"
            },
            "description": "Each layer asked for, by name."
          }
        },
        "additionalProperties": false,
        "description": "One listing, layer by layer."
      },
      "SnapshotRow": {
        "required": [
          "segment",
          "symbol",
          "bid",
          "ask",
          "last",
          "ageSeconds",
          "transport",
          "generation",
          "sequence",
          "markPrice",
          "markIndex",
          "markPremium",
          "fundingRate",
          "fundingRelativeRate",
          "fundingPredictedRate",
          "fundingPredictedRelativeRate",
          "nextFundingAt",
          "openInterest",
          "bidSize",
          "askSize",
          "volume24h"
        ],
        "type": "object",
        "properties": {
          "segment": {
            "type": "string"
          },
          "symbol": {
            "type": "string"
          },
          "bid": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "ask": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "last": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "ageSeconds": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "transport": {
            "type": "string"
          },
          "generation": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "sequence": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "markPrice": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "markIndex": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "markPremium": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "fundingRate": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "fundingRelativeRate": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "fundingPredictedRate": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "fundingPredictedRelativeRate": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "nextFundingAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "openInterest": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "bidSize": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "askSize": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "volume24h": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          }
        }
      },
      "SnapshotValue": {
        "required": [
          "value",
          "venue",
          "layer",
          "venue_ts",
          "received_at",
          "age_ms",
          "status"
        ],
        "type": "object",
        "properties": {
          "value": {
            "$ref": "#/components/schemas/Number"
          },
          "unit": {
            "$ref": "#/components/schemas/Unit"
          },
          "venue": {
            "examples": [
              "KRAKEN-FUTURES"
            ],
            "type": "string",
            "description": "The public code of the venue that published it."
          },
          "layer": {
            "examples": [
              "mark",
              "funding",
              "book",
              "oi",
              "stats",
              "reference"
            ],
            "type": "string",
            "description": "The layer it was read from."
          },
          "price_type": {
            "enum": [
              "trade",
              "mark",
              "index"
            ],
            "type": "string",
            "description": "Which price the reading is of, where a layer publishes more than one."
          },
          "band": {
            "examples": [
              "0.001"
            ],
            "type": "string",
            "description": "The band this depth figure covers, as a fraction of the reference price."
          },
          "reference": {
            "examples": [
              "mid",
              "mark"
            ],
            "type": "string",
            "description": "The price the band is measured from."
          },
          "levels": {
            "type": [
              "null",
              "integer"
            ],
            "description": "How many book levels fell inside the band; null when the book did not reach its edge, and then `reason` is `band_truncated`."
          },
          "venue_ts": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "age_ms": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Milliseconds between `received_at` and the instant of the query. Null when nothing was received."
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          }
        },
        "additionalProperties": false,
        "description": "The latest reading of one field on one venue at the instant of the query."
      },
      "SnapshotsRequest": {
        "type": "object",
        "properties": {
          "where": {
            "$ref": "#/components/schemas/Selection"
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "What quantities are expressed in.",
            "default": "published"
          },
          "number_format": {
            "enum": [
              "json",
              "string"
            ],
            "type": "string",
            "description": "`string` returns every number as a string with the same digits.",
            "default": "json"
          },
          "include_synthetic": {
            "type": "boolean",
            "description": "Include venues that exist in the registry but are not published. For the platform's own use; a public key sees nothing extra.",
            "default": false
          },
          "layers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Which layers to read. Every layer when omitted."
          },
          "include_raw": {
            "type": "boolean",
            "description": "Also return each layer's message as the venue sent it.",
            "default": false
          }
        },
        "additionalProperties": false,
        "description": "Which listings and which layers to read now."
      },
      "SnapshotsResponse": {
        "required": [
          "evaluated_at",
          "units",
          "freshness",
          "items",
          "missing"
        ],
        "type": "object",
        "properties": {
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          },
          "units": {
            "enum": [
              "published",
              "base",
              "quote"
            ],
            "type": "string",
            "description": "The unit mode applied."
          },
          "freshness": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The bound applied to each layer."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SnapshotItem"
            },
            "description": "One object per listing."
          },
          "missing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NotListed"
            },
            "description": "The instrument-venue pairs that do not exist."
          }
        },
        "additionalProperties": false,
        "description": "The latest reading of each layer for the selected listings."
      },
      "Status": {
        "enum": [
          "present",
          "stale",
          "missing",
          "not_published",
          "off"
        ],
        "type": "string",
        "description": "How the platform stands to this value at the instant of the query. `present`: received within the layer's freshness bound. `stale`: received, but older than the bound — it compares as unknown. `missing`: nothing received. `not_published`: the venue does not publish it. `off`: the platform does not collect it for this listing's group."
      },
      "StreamEvent": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/StreamUpdate"
          },
          {
            "$ref": "#/components/schemas/StreamHeartbeat"
          }
        ],
        "description": "The `data:` of one event. `snapshot` and `update` carry a layer of one listing; `heartbeat` carries only the instant. The event name is in the `event:` line, not in the payload."
      },
      "StreamHeartbeat": {
        "required": [
          "evaluated_at"
        ],
        "type": "object",
        "properties": {
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          }
        },
        "additionalProperties": false,
        "description": "The payload of a `heartbeat` event, every fifteen seconds. It proves the connection is alive when nothing is changing, so silence can be read as a broken connection rather than as a quiet market."
      },
      "StreamUpdate": {
        "required": [
          "evaluated_at",
          "instrument",
          "venue",
          "symbol",
          "quote",
          "layer",
          "status",
          "venue_ts",
          "received_at",
          "values"
        ],
        "type": "object",
        "properties": {
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          },
          "instrument": {
            "type": [
              "null",
              "string"
            ],
            "description": "The platform's code, or null when the listing maps to none."
          },
          "instrument_reason": {
            "type": "string",
            "description": "Why it maps to none. Present only when `instrument` is null."
          },
          "venue": {
            "type": "string",
            "description": "The venue's public code."
          },
          "symbol": {
            "type": "string",
            "description": "The venue's own symbol."
          },
          "quote": {
            "type": [
              "null",
              "string"
            ],
            "description": "What the listing is quoted in."
          },
          "layer": {
            "type": "string",
            "description": "Which layer changed."
          },
          "status": {
            "$ref": "#/components/schemas/Status"
          },
          "reason": {
            "$ref": "#/components/schemas/NullReason"
          },
          "venue_ts": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "received_at": {
            "$ref": "#/components/schemas/NullableInstant"
          },
          "age_ms": {
            "type": [
              "null",
              "integer"
            ],
            "description": "Milliseconds since it was received."
          },
          "values": {
            "type": "object",
            "additionalProperties": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/Number"
                },
                {
                  "$ref": "#/components/schemas/Liquidity"
                }
              ]
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "reasons": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/NullReason"
            }
          },
          "resumed": {
            "type": "boolean",
            "description": "True on the first events after a reconnect. A reconnect is answered with a fresh snapshot, never a replay: a replayed price is a lie about when it was true."
          }
        },
        "additionalProperties": false,
        "description": "The payload of a `snapshot` or an `update` event: one layer of one listing, in the shape a layer takes in `POST /v2/snapshots`.\n\nA status change is an update too. A listing going stale sends an event with the same value and a new status — it never sends a zero, because a client that received a zero would trade on it."
      },
      "TradeRow": {
        "required": [
          "segment",
          "symbol",
          "eventTime",
          "price",
          "size",
          "side"
        ],
        "type": "object",
        "properties": {
          "segment": {
            "type": "string"
          },
          "symbol": {
            "type": "string"
          },
          "eventTime": {
            "type": "string",
            "format": "date-time"
          },
          "price": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "size": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "side": {
            "type": "string"
          }
        }
      },
      "Unit": {
        "examples": [
          "base",
          "quote",
          "ratio"
        ],
        "type": "string",
        "description": "What the number counts: `base` for the base asset, `quote` for the quote currency, `contracts` for the venue's own contract, `ratio`, `bps`, `percent`, `ms`. Absent where the value is not a quantity."
      },
      "Value": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/SnapshotValue"
          },
          {
            "$ref": "#/components/schemas/SeriesValue"
          },
          {
            "$ref": "#/components/schemas/ReferenceValue"
          },
          {
            "$ref": "#/components/schemas/AggregateValue"
          },
          {
            "$ref": "#/components/schemas/DerivedValue"
          }
        ],
        "description": "One value with everything needed to judge it: what it is, which venue published it, when it arrived, how old it was, and whether that made it usable. Every number the platform returns is wrapped this way — a bare number cannot say whether it is three seconds or three hours old.\n\nFive variants, told apart by their own properties: a snapshot reading, a series reading, an instrument's reference field, an aggregate across venues, and a value derived from others."
      },
      "ValueMap": {
        "type": "object",
        "additionalProperties": {
          "$ref": "#/components/schemas/Value"
        },
        "description": "The values a `select` asked for, by the name it asked for them under."
      },
      "VenuesResponse": {
        "required": [
          "evaluated_at",
          "items"
        ],
        "type": "object",
        "properties": {
          "evaluated_at": {
            "$ref": "#/components/schemas/Instant"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CollectedVenue"
            },
            "description": "The venues, by public code."
          }
        },
        "additionalProperties": false,
        "description": "Every venue in DQL. No key: a reader must be able to see what exists before deciding to pay for it."
      }
    },
    "securitySchemes": {
      "key": {
        "type": "http",
        "description": "A key from studio.debyko.com/account, as `Authorization: Bearer <key>`. Never in a URL.",
        "scheme": "bearer"
      }
    }
  },
  "tags": [
    {
      "name": "Coverage",
      "description": "What exists and what may be asked — free to read, no key.\n\nThese endpoints describe the platform: which venues and instruments are collected, what a query may\nask for and within which limits, and whether a query you have written is valid. None of them returns a\nvenue's figure, so none of them needs a key — you can see what exists, and check your query against the\nreal grammar, before deciding to buy an answer.\n\nThe same coverage is published as a page on [debyko.com](https://debyko.com/data/coverage/); this is\nthe machine-readable form of it, and it is generated from the same registry the collectors work from,\nso the two cannot drift apart.\n"
    },
    {
      "name": "Measurements",
      "description": "What the venues published. Every one of these needs a key.\n\nEvery `/v2` endpoint that returns a measurement needs a key:\n\n```\nAuthorization: Bearer dbk_…\n```\n\nA key is issued at [studio.debyko.com/account](https://studio.debyko.com/account). The Free plan is\nissued without a card; paid plans start with a seven-day trial. One key covers Studio, the API and\nAgent — whatever a plan includes in Studio, it includes here.\n\n**Never in a URL.** A key in a query string is written into server logs, proxy logs and browser\nhistory. A request that carries one is refused with `KEY_IN_URL` and the key should be replaced from\nyour account.\n\n## What a plan changes\n\nA plan narrows what a key sees, and the answer says so rather than quietly shrinking:\n\n- **venues and instruments**: a plan that includes two venues sees two venues in the registry it is\n  answered from, and a `where` that names another matches nothing;\n- **history**: asking further back than a plan reaches is refused with `PLAN_LIMIT`, naming the date\n  the plan reaches and what it would take to go further — never a shortened answer that looks whole;\n- **rate**: requests per second and per day, and the number of live streams, are counted per key.\n  Exceeding one is a `429` with `Retry-After` and the name of the limit that stopped you.\n\nUsage is counted per key, per hour and per endpoint class, and is visible in your account. No\nper-request log of what you asked is kept.\n"
    }
  ]
}
