Skip to content

Stream depth and the trade tape

/ws/market is the public half of the platform: no bearer, no handshake token, no tenant header. Open it, send two subscribe frames, and you have the live book and every print for a symbol on one connection.

  1. Nothing precedes the first subscribe. The TypeScript SDK ships no market-data client, so drive this channel with any WebSocket implementation. Append ?encoding=msgpack to switch server frames to MessagePack — on a busy book it is the cheapest win available.

    const ws = new WebSocket('wss://api.troncharts.xyz/ws/market')
    ws.addEventListener('message', (e) => handle(JSON.parse(e.data)))
    ws.addEventListener('open', () => { /* subscribe here */ })
  2. venue and symbol are separate fields; there is no venue:symbol string on the wire. You get Result { ok: true }, and a Depth-Update snapshot immediately after it when the server’s cache is already warm. Depth serves hyperliquid, aster, lighter, polymarket, kalshi, massive and b3.

    { "type": "Subscribe-Depth", "venue": "hyperliquid", "symbol": "BTC.HL" }

    Every level is { px, sz } as decimal strings, plus ct — the resting-order count — on the venues that expose one.

    { "type": "Depth-Update", "venue": "hyperliquid", "symbol": "BTC.HL",
    "bids": [{ "px": "64210.0", "sz": "1.842" }],
    "asks": [{ "px": "64211.5", "sz": "0.311" }],
    "source": "be_canonical", "ts": "2026-08-04T12:00:00.000Z" }
  3. The tape’s venue set is narrower than depth’s — hyperliquid, aster, massive, b3, the four with a trade-print producer. Asking for any other venue is rejected as invalid_frame rather than accepted and left silently blank.

    { "type": "Subscribe-Tape", "venue": "hyperliquid", "symbol": "BTC.HL" }

    Handle both wire shapes. Prints are batched into a trades array — one frame per flush window, not per print, because B3 alone was measured at 612 prints per second — while the legacy flattened single-print frame is still part of the contract.

    function onTape(f) {
    const prints = 'trades' in f ? f.trades : [f]
    for (const p of prints) console.log(p.side, p.px, p.sz, p.ts)
    }
  4. The same socket multiplexes Subscribe-Depth-L3 for the per-order book (lighter and b3 only) → Order-Book-Update, Subscribe-BBOBBO-Update, Subscribe-VAPVAP-Update, and Subscribe-Candles with an interval written as a count plus s, m, h, d, w or M (1m, 4h, 1d) → Candle-Update. Each has a matching Unsubscribe-*, Unsubscribe-All drops everything, and Ping answers Pong. Past the per-socket subscription cap you get Result { ok: false, error: "subscription_limit" }.

Next: Market channel · Market data · Stream account and position updates