Market Data
Real-time and historical market data from every connected CEX, DEX, and prediction market. Everything flows through the Central Coordinator's unified symbol resolver, so CEX pairs (BTC-USD), chain-suffixed DEX pairs (ETH-USDC-ARB), Kalshi tickers (KXBTCZ-26DEC31-T99000), and Polymarket slugs or CTF token IDs all work on the same endpoints.
Get NBBO Quote (all symbols)
/v1/quotesConsolidated best bid/offer across every connected venue, for every symbol currently subscribed.
Query Parameters
| Parameter | Default | Description |
|---|---|---|
symbols (alias: symbol) | — | Comma-separated allow-list (e.g. BTC-USD,ETH-USDT). Both plural and singular are accepted. |
max_age_s | 300 | Maximum age in seconds before a symbol's NBBO is excluded as stale. Resolved/dormant markets stop sending ticks; the default 5-minute ceiling prevents serving wildly outdated quotes. Pass a large value (e.g. 86400) to include stale entries; 0 is not "no aging" (it filters everything — see below). |
Response
{
"quotes": [
{
"symbol": "BTC-USD",
"nbbo": { "bid": 73984.12, "ask": 73985.03, "mid": 73984.57, "spread_bps": 1.23 },
"venues": {
"kraken": { "bid": 73984.12, "ask": 73985.03, "bid_size": 1.62, "ask_size": 0.94, "age_ms": 35 },
"coinbase": { "bid": 73983.91, "ask": 73985.40, "bid_size": 0.42, "ask_size": 0.71, "age_ms": 121 }
}
}
]
}| Field | Description |
|---|---|
symbol | Canonical symbol |
nbbo.{bid, ask, mid, spread_bps} | Cross-venue best. mid and spread_bps are zeroed defensively when the consolidated book is crossed (best_bid > best_ask across venues — happens when one venue's book is stale relative to another's). |
venues.{venue}.{bid, ask, bid_size, ask_size, age_ms} | Per-venue snapshot. age_ms is the time since that venue's last tick — the freshness anchor. |
The max_age_s filter applies at the NBBO-level last_update_ns, not per-venue. A symbol whose NBBO last updated > max_age_s ago is excluded entirely. To find resolved/dormant Polymarket markets that aren't in /v1/quotes anymore, hit Polymarket's gamma directly or check /v1/markets?status=closed.
Get Quote (single symbol)
/v1/quotes/{symbol}NBBO + per-venue book for one symbol. Handles cold-start transparently — on a first request the CC dynamically subscribes the edge and can return either a live cache hit or a cold REST snapshot.
Query Parameters
| Parameter | Default | Description |
|---|---|---|
depth | 10 | Book levels per side (1–100) |
nowait | false | Skip the up-to-2 s dynamic-subscribe wait on cold symbols. Use for research scans; leave default for trading hot paths |
instrument_type | auto | spot, perp, or prediction. Auto-detected from the symbol (token_id / Kalshi ticker → prediction, else spot) |
Response
{
"symbol": "BTC-USD",
"nbbo": { "bid": 73984.12, "ask": 73985.03, "mid": 73984.57, "spread_bps": 1.23 },
"venues": { "binance": { "bid": 73984.12, "ask": 73985.03 } },
"book": { "bids": [ ... ], "asks": [ ... ] },
"source": "edge_nbbo"
}The source field
Tells you which path served the quote — useful for cold-path latency debugging and retry logic:
| Value | Meaning |
|---|---|
edge_nbbo | Cache hit — served from the live WebSocket NBBO state. Sub-millisecond. |
edge_rpc_snapshot | Cold-path cache miss — one-shot REST via the edge's authenticated fetcher (uses Polymarket's bulk /books when applicable). 100–300 ms. |
venue_public_api | Fallback — edge RPC failed (unreachable/timeout/unregistered), served from the CC's venue-public-API path. 2 s cache. |
unavailable | No path produced book data. Honest "nothing here right now" — market is empty, 404, or errored everywhere. |
For symbols not in the edge's sticky subscription set, the first call returns edge_rpc_snapshot while a background subscription spins up; subsequent calls within ~5–15 s return edge_nbbo.
Batch Quotes
/v1/quotes_batchFetch many quotes in one HTTP round-trip with server-side fan-out. Per-symbol errors return as partials rather than failing the whole batch — the response is always HTTP 200.
Request Body
{
"symbols": ["BTC-USD", "ETH-USDT", "12345...token_id", "KXBTC-..."],
"depth": 10,
"nowait": true,
"concurrency": 64
}| Field | Default | Description |
|---|---|---|
symbols | — | Up to 2000. Mix CEX pairs, Kalshi tickers, Polymarket token IDs, slugs, URLs freely — each routes automatically |
depth | 10 | Book levels per side (1–100), uniform across the batch |
nowait | false | Skip the 2 s subscribe-wait per cold symbol. Recommended for batches ≥50 — one cold symbol otherwise stalls the whole batch |
concurrency | 64 | Max concurrent upstream fetches. Cap 256 |
instrument_type | auto | Override auto-detection for every symbol |
Response
{
"quotes": [
{ "symbol": "BTC-USD", "nbbo": { "...": "..." }, "source": "edge_nbbo" },
{ "symbol": "12345...", "nbbo": { "...": "..." }, "source": "edge_rpc_snapshot" },
{ "symbol": "bad-symbol", "error": "resolver: unknown symbol" }
],
"count": 3,
"elapsed_ms": 215
}Latency model
| Scenario | Sequential /v1/quotes | Batch with nowait=true |
|---|---|---|
| 800 sticky-subscribed symbols | ~800 × 200 ms ≈ 160 s | ~1–2 s |
| 800 cold prediction-market tokens | ~800 × 2 s ≈ 27 min | ~3–5 s (bulk /books) |
| 10 cold symbols + 3 hot | ~20 s | ~200–300 ms |
Fair Price
Cross-venue Chainlink-style consolidated reference price per underlying asset — BTC, ETH, SOL, etc. Aggregates the latest mid from every reporting (venue, instrument_type) pair into one composite number plus separate spot/perp legs and the signed basis between them.
Use this when you need:
- A single "what is BTC worth right now" number that doesn't depend on any one venue
- The basis between perp and spot (
basis_bps) as a signal - A venue-independent price for quoting, valuation, or hedging triggers
/v1/fair_price/{underlying}Snapshot of the current consolidated reference price for an underlying.
Path Parameters
| Parameter | Description |
|---|---|
underlying | Asset identifier (uppercase): BTC, ETH, SOL, XRP, DOGE, … |
Response
{
"underlying": "BTC",
"fair_mid_1e9": 76405095000000,
"spot_mid_1e9": 76407250000000,
"perp_mid_1e9": 76357950000000,
"basis_bps": -6,
"confidence": 0.665,
"contributors": [
{"venue": "binance", "instrument_type": "spot", "mid_1e9": 76407250000000, "weight": 0.84, "staleness_ms": 96},
{"venue": "binance", "instrument_type": "perp", "mid_1e9": 76357950000000, "weight": 0.81, "staleness_ms": 79},
{"venue": "okx", "instrument_type": "spot", "mid_1e9": 76406500000000, "weight": 0.78, "staleness_ms": 156},
{"venue": "okx", "instrument_type": "perp", "mid_1e9": 76358200000000, "weight": 0.77, "staleness_ms": 201},
{"venue": "bybit", "instrument_type": "spot", "mid_1e9": 76405300000000, "weight": 0.72, "staleness_ms": 134},
{"venue": "bybit", "instrument_type": "perp", "mid_1e9": 76356800000000, "weight": 0.64, "staleness_ms": 219},
{"venue": "hyperliquid", "instrument_type": "perp", "mid_1e9": 76354500000000, "weight": 0.65, "staleness_ms": 226}
],
"cc_ts_ns": 1745979000123456789
}Field semantics
| Field | Meaning |
|---|---|
fair_mid_1e9 | Composite weighted-median across all contributors (spot + perp). Use this when you want one number. |
spot_mid_1e9 | Weighted-median across spot-only contributors. null if no spot venue has reported recently. |
perp_mid_1e9 | Weighted-median across perp-only contributors. null if no perp venue has reported recently. |
basis_bps | Signed perp_mid - spot_mid in basis points. Positive = perps trade above spot (contango / positive funding regime). Negative = perps below spot (backwardation). null when either leg is missing. |
confidence | [0.0, 1.0] — coverage × consistency. Higher = more contributors, tighter cluster, fresher data. < 0.3 typically means thin coverage or wide dispersion. |
contributors[].venue | The venue identifier (matches /v1/edges edge_id minus the venue-edge- prefix; perp variants share their spot venue's id — binance covers both spot and perp legs). |
contributors[].instrument_type | "spot" or "perp". The same venue can appear twice on the list when it streams both. |
contributors[].weight | Final weight after recency decay (500 ms τ), liquidity, and spread. Per-side MAD outlier rejection drops contributors > 3 × MAD from the per-side median. |
contributors[].staleness_ms | Age of this contributor's last update, in milliseconds. |
How it's computed
Per-side weighted median (spot, perp) using:
w_recency = exp(-age_ns / 500_000_000)— 500 ms decay τ; a contributor seen 500 ms ago is weighted at e⁻¹ ≈ 0.37 of an instant-fresh onew_liquidity = clamp(log10(top_size + 1) / 8, 0.1, 1.0)w_spread = 1 / (1 + spread_bps × 0.01)— tighter quotes get higher weight
MAD outlier rejection runs per side (spot independently of perp) — the basis between spot and perp is signal, not noise, so a cross-side filter would falsely reject the perps simply because they trade above/below spot.
The composite fair_mid_1e9 is a third weighted median across the union of surviving contributors.
Streaming the same data
Every recompute is also broadcast on the unified WebSocket as the fair_price:<underlying> topic. See Real-Time Streams → Topic catalog.
# REST snapshot
GET /v1/fair_price/BTC
# WebSocket subscription (~1 ms updates per underlying, coalesced)
{"subscribe": ["fair_price:BTC", "fair_price:ETH"]}List tracked underlyings
/v1/fair_price{"underlyings": ["BTC", "ETH", "SOL", "XRP", "DOGE", ...]}Returns whatever underlyings have reported a (spot or perp) update recently. New underlyings are auto-tracked when their first contribution arrives; capped at 256 to bound the interner.
Known limitations
- USDT, USDC, and USD settlement variants collapse to one underlying (
BTC-USDTandBTC-USDCboth contribute toBTC). Acceptable for Chainlink-style reference; not for basis-point-accurate quoting where the USDT/USDC peg differential matters. - Single-contributor underlyings (e.g. a perp-only obscure asset) emit with a low confidence floor and skip MAD rejection — there's no cluster to validate against.
Price History
/v1/price_history/{symbol}Time series of (ts_ns, price_1e9) points. Works for any symbol — CEX (BTC-USD, ETH-USDT), DEX, and Polymarket slugs (btc-updown-5m-1776537600[:yes|:no]).
Source routing is automatic:
- CEX / DEX → raw event tape (trade prints, downsampled to the requested fidelity)
- Polymarket slug or CTF token → proxies Polymarket's
/prices-history
Query Parameters
| Parameter | Default | Description |
|---|---|---|
range | 1d | 1h, 6h, 1d, 1w, 1m, max |
fidelity_secs | 60 | Point cadence in seconds. 0 switches to tick mode |
limit | 100 | Tick mode only — max points (max 500) |
paginate | false | Prediction markets only — walks 7-day windows to bypass Polymarket's ~4–5 k point per-call cap. Server-capped at 200 k points |
OHLCV candles were removed in favor of raw tape. Compute candles client-side from the point stream if needed.
Tick mode
/v1/price_history/{symbol}?fidelity_secs=0&limit=100Raw trade prints from the live tape. fidelity_secs=0 switches from bar mode to tick mode, returning up to limit most-recent prints with qty_1e8, side, and venue_id populated on each point.
DEX Pools
/v1/market_data/poolsPer-pool BBO for DEX liquidity pools. Returns individual pool prices, fees, and protocol metadata for a trading pair across all chains.
Query Parameters
| Parameter | Description |
|---|---|
symbol | Required. Trading pair (e.g., ETH-USDC-ARB, WBTC-USDC-ETH, or normalized ETH-USD) |
Response
{
"symbol": "ETH-USDC-ARB",
"pools": [
{
"pool_address": "0x6f38e884725a116e8dccbfcab8e2c4491dbead5f",
"pair_index": 0,
"protocol": "uniswap_v3",
"protocol_id": 2,
"chain": "dex-arb",
"fee_bps": 1,
"bid": 3421.50,
"ask": 3421.80,
"bid_size": 10.5,
"ask_size": 8.2,
"sqrt_price_x96": "1234567890123456789",
"tick": -24521,
"liquidity": "85000000000",
"block_number": 198765432,
"gas_context": {
"chain": "arbitrum",
"chain_id": 1,
"base_fee_native": 1,
"priority_fee_native": 0,
"estimated_gas_units": 150000,
"native_price_1e9": 2200000000000,
"estimated_cost_usd": 0.33,
"last_update_ns": 1705420800000000000
},
"updated_ms": 1709510400000
}
]
}Protocol IDs
| ID | Protocol |
|---|---|
| 1 | Uniswap V2 |
| 2 | Uniswap V3 |
| 3 | Curve |
| 4 | Balancer V2 |
| 5 | Aerodrome |
| 6 | Velodrome |
| 7 | Camelot |
| 8 | Raydium CLMM |
| 9 | Orca Whirlpool |
DEX Symbol Format
DEX pairs use a chain-suffixed format: BASE-QUOTE-CHAIN
| Symbol | Meaning |
|---|---|
ETH-USDC-ARB | ETH/USDC on Arbitrum |
WBTC-USDC-ETH | WBTC/USDC on Ethereum |
ETH-USDC-BASE | ETH/USDC on Base |
The normalized form (e.g. ETH-USD) also works and returns pools across all chains.
Token Info
/v1/token-infoToken metadata (CoinGecko-sourced). Public — no auth required.
Funding Rates (perps)
/v1/market/funding-ratesCurrent funding rates across perp venues.
/v1/funding_history/{symbol}Historical funding rates for a perp symbol.
DataEngine Health & Reconciliation
/v1/data/healthPipeline health for the internal DataEngine.
/v1/data/reconReconciliation status between DataEngine and upstream sources.
/v1/data/ticksRecent ticks from the DataEngine stream.
/v1/data/ticks/rangeHistorical range query against the DataEngine tick store.
/v1/data/signalsComputed signals available for a symbol (feeds the SOR cost model).
/v1/data/statsAggregate DataEngine statistics.
Symbols
/v1/symbolsList all tradeable instruments across venues, including instrument type (spot / perp / prediction) and per-venue availability.
Connected Edges
/v1/edgesList connected venue edge servers — local and remote (peer-linked CCs in other regions).
[
{"edge_id": "venue-edge-binance", "connected": true, "region": "ap", "supports_algo_runtime": true, ...},
{"edge_id": "venue-edge-binance-perp", "connected": true, "region": "ap", "supports_algo_runtime": true, ...},
{"edge_id": "venue-edge-bybit", "connected": true, "region": "ap", ...},
{"edge_id": "venue-edge-bybit-perp", "connected": true, "region": "ap", ...},
{"edge_id": "venue-edge-okx", "connected": true, "region": "ap", ...},
{"edge_id": "venue-edge-okx-perp", "connected": true, "region": "ap", ...},
{"edge_id": "venue-edge-coinbase", "connected": true, "region": "na", ...},
{"edge_id": "venue-edge-kraken", "connected": true, "region": "eu", "remote": true, ...},
{"edge_id": "venue-edge-hyperliquid", "connected": true, "region": "na", ...},
{"edge_id": "venue-edge-kalshi", "connected": true, "region": "eu", "remote": true, ...},
{"edge_id": "venue-edge-polymarket", "connected": true, "region": "eu", "remote": true, ...},
{"edge_id": "venue-edge-dex", "connected": true, "region": "na", ...},
{"edge_id": "venue-edge-solana", "connected": true, "region": "na", ...},
{"edge_id": "venue-edge-bitget", "connected": true, "region": "ap", ...},
{"edge_id": "venue-edge-cryptocom", "connected": true, "region": "ap", ...}
]| Field | Description |
|---|---|
region | Geographic region where the edge runs (na, eu, ap) |
remote | true if reached via a peer-linked CC in another region. Omitted for local edges |
Edge identifier convention
venue-edge-<name> where <name> is the venue selector. Spot and perp on the same exchange share a venue identity but run as separate edges:
| Edge ID | Venue | Instrument | Notes |
|---|---|---|---|
venue-edge-binance | binance | spot | stream.binance.com WS |
venue-edge-binance-perp | binance | perp (USD-M) | fstream.binance.com WS, same VenueId::Binance as spot |
venue-edge-bybit | bybit | spot | stream.bybit.com/v5/public/spot |
venue-edge-bybit-perp | bybit | perp (linear) | stream.bybit.com/v5/public/linear |
venue-edge-okx | okx | spot | ws.okx.com:8443 books channel (400 levels) |
venue-edge-okx-perp | okx | perp (SWAP) | same WS, -SWAP instId |
venue-edge-coinbase | coinbase | spot | level2 channel |
venue-edge-kraken | kraken | spot | depth=100 |
venue-edge-hyperliquid | hyperliquid | perp (native) | l2Book channel |
venue-edge-kalshi | kalshi | prediction | per-market YES/NO outcomes |
venue-edge-polymarket | polymarket | prediction | CLOB token IDs |
venue-edge-dex | dex | spot | EVM L1+L2 pools, chain suffix in symbol |
venue-edge-solana | solana | spot | Solana DEX pools |
venue-edge-bitget | bitget | spot | bespoke edge |
venue-edge-cryptocom | cryptocom | spot | bespoke edge |
In market-data and fair-price responses, perp edges report under their commercial venue's venue field (binance, not binance_perp) — differentiate via instrument_type.