Skip to main content
An Up/Down window is a short-dated crypto market that asks one question: was the asset’s price at the end of this window above the price pinned at its start? A 15-minute BTC window opens at 17:30, closes at 17:45, and resolves Up or Down against a frozen open price the oracle pins seconds after the window starts. Windows are machine-minted, never hand-listed. A series (BTC15M) describes the recurring schedule; a factory materialises one market per window on that grid, and groups a whole UTC day of them under one event.
Everything else is a normal binary market: two outcome tokens, the same orderbook, the same EIP-712 order, the same redemption. outcomeLabels is ["Up", "Down"]Up is outcome index 0 (the YES slot), Down is index 1.

Series on the event

A crypto Up/Down event carries a cryptoSeries block; every other event carries null. It is the entry point — the FE should navigate the series, not the event’s markets[] array, because a day at 15-minute cadence is ~96 markets and the event only nests the currently tradeable ones.
Operator state (enabled / paused / delay counters / grace settings) is deliberately not projected — this is the public surface.

The cryptoWindow block

On a window market, cryptoWindow carries the window facts. It is null on every other market, including long-dated crypto markets.
openPrice is a string and must stay one. At 18 decimals it exceeds Number.MAX_SAFE_INTEGERNumber(openPrice) silently loses precision. Render it as openPrice / 10 ** streamDecimals with a bigint or decimal helper. Same rule for every price on the crypto_price_tick channel.
A window market carries both crypto (with productType: "UP_DOWN_WINDOW") and cryptoWindow. Long-dated crypto markets carry crypto only. cryptoWindow !== null is the reliable “this is an Up/Down window” test.
Each entry is the same MarketSummary shape the markets endpoints return, cryptoWindow included — so one renderer serves the list and the detail page.
hasMore distinguishes a truncated page from end-of-data — a capped chip strip is otherwise indistinguishable from a short day. Buckets are computed from the window bounds against the current time, not from lifecycle status. A window can be CLOSED while its period is still current (settlement lag). current is normally one window but is not guaranteed to be — treat it as a list. Public endpoint, 600 req/min per IP, Cache-Control: public, max-age=5current flips on the minute, so anything longer would serve a stale active window right after a rollover.

Window lifecycle

Settlement latency is decided by the challenge window that applies to the market. By default that is the platform-wide window (2 h on dev today), so a 15-minute window resolves about two hours after it closes. Windows armed for the fast on-chain path carry a per-market window of zero and finalize right after the proposal instead. Read resolution.challengeWindowClosesAt rather than assuming either — it is the exact instant finalize becomes legal. See Settlement flow.

Live data

The chart line and the settlement price are different Chainlink products on a window market: the curve is built from one-minute candlestick data, while the frozen open and the live tick come from Data Streams. They track the same asset but are not byte-identical, so the line can sit a few dollars off the open line at the boundary instant. The curve is a display surface — settlement binds cryptoWindow.openPrice.