Market channel
/ws/market streams the live book and tape. Use
REST market data for the initial snapshot, then
keep it current here. Market data is public: no Authenticate frame is
required on this channel.
What it carries
Section titled “What it carries”Six independent streams, each with its own subscribe verb and its own set of venues. A stream only accepts venues it can actually serve, and a subscribe it cannot honour is refused rather than accepted and left silently blank.
| Stream | Subscribe with | Pushes | Venues |
|---|---|---|---|
| Depth (aggregated levels) | Subscribe-Depth |
Depth-Update |
hyperliquid, aster, lighter, polymarket, kalshi, massive, b3, t4 |
| Order book (per order, L3) | Subscribe-Depth-L3 |
Order-Book-Update |
lighter, b3 |
| Tape (trade prints) | Subscribe-Tape |
Tape-Update |
hyperliquid, aster, massive, b3, t4 |
| Volume at price | Subscribe-VAP |
VAP-Update |
hyperliquid, aster, massive, b3, t4 |
| Inside quote | Subscribe-BBO |
BBO-Update |
hyperliquid, aster, lighter, polymarket, massive, b3, t4 |
| Candles | Subscribe-Candles |
Candle-Update |
hyperliquid, aster, lighter, polymarket, kalshi, massive, b3, t4 |
massive is the venue key for listed futures; the same key is what
GET /api/v1/symbols/{venue} enumerates them under.
Each has a matching Unsubscribe-*; Unsubscribe-All drops the lot. Ping
answers Pong, and every subscribe frame answers Result.
Four different refusals, and they mean different things:
Result error |
Means | What to do |
|---|---|---|
invalid_frame |
The venue is not in this stream’s set at all, or a required field is missing. detail names it. |
Fix the frame; retrying will not help. |
venue_disabled |
The venue is real for this stream but switched off by an admin. | Not yours to fix — a different venue, or ask the operator. |
bbo_disabled |
The inside-quote feed is off platform-wide. | Use Subscribe-Depth and read the top of book. |
subscribe_failed |
The venue accepted, the symbol did not. detail carries the venue’s own complaint. |
Check the symbol against GET /api/v1/symbols/{venue}. |
venue and symbol are separate fields — there is no venue:symbol
string on the wire — and symbol is the venue-suffixed ticker, not the bare
asset:
{ "type": "Subscribe-Depth", "venue": "hyperliquid", "symbol": "BTC.HL" }The suffix is not redundant with venue: it is the platform-canonical symbol,
the same string GET /api/v1/symbols/{venue} returns and the same one the REST
market-data routes take. Sending the bare asset is refused —
subscribe_failed, "invalid HL symbol for depth subscribe: BTC" — because
the venue never sees a symbol it recognises.
Subscribe-Candles and Unsubscribe-Candles additionally require interval,
written as a count plus a unit — s, m, h, d, w, or M (1m, 15m,
4h, 1d, 1w). Custom resolutions are accepted and folded server-side from
a finer base interval where the venue has no native bar. Each interval is its
own subscription: unsubscribing 5m leaves 1h running.
Prices and sizes arrive as decimal strings, and every frame echoes venue and
symbol so one socket can multiplex the whole set.
Batching
Section titled “Batching”High-rate venues can print far faster than any UI can render. The tape is
batched server-side into one frame per flush window: a single Tape-Update
carries a trades array holding every print that landed in the window, in wire
order. Iterate it; do not assume one frame equals one trade.
This matters most on futures venues, where an active session can produce hundreds of prints per second on one symbol.
Encoding
Section titled “Encoding”Like the other channels, ?encoding=msgpack on the upgrade URL switches
server→client frames to MessagePack. On a busy depth subscription this is the
single cheapest performance win available to a client.
Seeding correctly
Section titled “Seeding correctly”- Subscribe first.
- Then fetch the REST snapshot.
- Apply buffered updates on top.
Doing it the other way round leaves a hole between the snapshot and your first frame.