Market data & streams
Public market data needs no trading credentials (a Decibel client with just nodeApiKey serves it). Streams normalize both venues into the same callback shapes with reconnect catch-up built in.
Market data
- Name
markets({ venue })- Type
- Promise<MarketInfo[]>
- Description
Listed markets with
sizeDecimals,priceDecimals,tickSize,lotSize,minSize,maxLeverage,isActive.
- Name
ticker({ venue, market })- Type
- Promise<Ticker>
- Description
The cheapest "what's the price?" primitive — single REST round-trip, always fresh. Returns
markPrice,midPrice,oraclePrice,fundingRateBps,openInterest,timestamp.
- Name
orderbook({ venue, market, depth? })- Type
- Promise<OrderBook>
- Description
L2 snapshot, bids descending / asks ascending.
- Name
candles({ venue, market, interval, from?, to? })- Type
- Promise<Candle[]>
- Description
OHLC bars.
interval:1m | 5m | 15m | 1h | 4h | 1d.
- Name
recentTrades({ venue, market, limit? })- Type
- Promise<PublicTrade[]>
- Description
Last N public taker prints.
Decibel orderbook caveat. Decibel exposes the orderbook only over
WebSocket, so the SDK uses a one-shot snapshot that can deliver a stale first
frame on quiet markets. For a price reference, prefer ticker() — it always
returns fresh data.
const md = new TriaClient({
decibel: { nodeApiKey: process.env.TRIA_TRADE_DECIBEL_NODE_API_KEY! },
})
const { markPrice } = await md.ticker({ venue: 'decibel', market: 'BTC/USD' })
const bars = await md.candles({
venue: 'decibel',
market: 'BTC/USD',
interval: '1h',
})
Streams
const off = await client.subscribeFills({ venue: 'hl' }, (fill) => {
console.log(`${fill.market} ${fill.side} ${fill.size} @ ${fill.price}`)
})
off() // stop streaming
- Name
subscribeFills(args, cb)- Type
- Promise<Unsubscribe>
- Description
- Live fills, deduped by venue fill ID, with reconnect catch-up.
- Name
subscribePositions(args, cb)- Type
- Promise<Unsubscribe>
- Description
- Live position snapshots.
- Name
subscribeOrders(args, cb)- Type
- Promise<Unsubscribe>
- Description
- Order lifecycle — one emission per state transition; reconnect catch-up replays missed orders.
- Name
subscribeAccount(args, cb)- Type
- Promise<Unsubscribe>
- Description
- Live
AccountSnapshot, frame-deduped so the callback only fires on real changes.
- Name
onConnection(cb)- Type
- Unsubscribe
- Description
- Global WS lifecycle:
connected/disconnected/reconnectingper venue.
Three guarantees
- Per-fill emission, never batch. Each callback gets one
Fill. Decibel pushes full snapshots; the SDK diffs byfillIdso you only see unseen fills. - Reconnect catch-up. On WS drop + reconnect, the SDK REST-polls fills since the last seen timestamp + 1ms and replays them, deduplicated against the live stream.
- Normalized shape. Both venues emit the same
Fillshape —buy/sell, decimal-string sizes/prices, unix-ms timestamps.
Connection lifecycle
const off = client.onConnection((event) => {
switch (event.status) {
case 'connected':
console.log(`${event.venue} WS up`)
break
case 'disconnected':
console.log(`${event.venue} WS dropped`)
break
case 'reconnecting':
console.log(`${event.venue} reconnecting...`)
break
}
})
The hook fires once per state transition per venue. If you gate critical logic on "stream is live," reset it on disconnected and re-arm on the next connected.