Skip to Content
Symmio Trading-SDK — the SDK surface for builders on Arbitrum
ReactOrderbook hooks

Orderbook hooks

React bindings over the orderbook slice. The hooks own the source’s memoization, the subscription lifecycle, and error normalization; everything about how a book is kept correct lives in core.

All reads.

Import

import { useBinanceOrderbookSource, useLiveOrderbook, useOrderbook, useOrderbookStream, type UseBinanceOrderbookSourceParameters, type UseLiveOrderbookParameters, type UseLiveOrderbookReturnType, type UseOrderbookParameters, type UseOrderbookReturnType, type UseOrderbookStreamParameters, type UseOrderbookStreamReturnType, } from "@symmio/trading-react";

Value types (Orderbook, OrderbookLevel, OrderbookSource, OrderbookSpread) come from @symmio/trading-core.

Choosing a hook

You wantUse
A one-off snapshot — sizing a single order, a preflight checkuseOrderbook
The raw synchronized book, to do your own aggregationuseOrderbookStream
A ladder: grouped, accumulated, with the spreaduseLiveOrderbook

All three need a source. Build it once with useBinanceOrderbookSource.

useBinanceOrderbookSource

Creates a memoized Binance OrderbookSource.

A source caches the venue’s exchangeInfo for its lifetime, so recreating it per render refetches that on every symbol resolve — and, worse, a new source identity tears down and re-dials any live subscription built on it.

const source = useBinanceOrderbookSource();

Parameters

Takes the same options as createBinanceOrderbookSource.

NameTypeDefaultNotes
market?"usd-m-futures" | "spot""usd-m-futures"Futures symbols are perpetual contracts, matching what a SYMMIO market is.
restUrl?stringvenue defaultA regional mirror or your own caching proxy.
wsUrl?stringvenue defaultKeep the route class — futures depth is only served on /public.
updateSpeed?number500 futures, 1000 spotFutures serves 100 | 250 | 500; spot serves 100 | 1000.
resolveSymbol?(marketName: string) => string | undefinedupper-case identityPass a stable reference — it participates in the memo.
webSocketConstructor?WebSocketConstructorglobalThis.WebSocketPass the ws package in Node.

Return type

An OrderbookSource, stable for as long as its options are unchanged.

useLiveOrderbook

The hook most ladders want. It resolves the market’s symbol metadata, holds one synchronized subscription, collapses the book onto the requested tick, attaches cumulative depth to every row, and reports the spread.

const source = useBinanceOrderbookSource(); const { bids, asks, spread, symbol, tickSizeOptions, isResyncing } = useLiveOrderbook({ source, marketName: "BTCUSDT", tickSize: 0.1, rows: 15, });

Parameters

NameTypeDefaultNotes
sourceOrderbookSourceFrom useBinanceOrderbookSource, or your own.
marketNamestringMarket name as SYMMIO names it.
limit?numbersource defaultSnapshot depth the live book is built on.
levels?numberderivedRaw levels streamed before grouping. Derived from rows and the grouping; set it only to cap per-update cost.
rows?number15Rows per side after grouping. rows: 5 yields five bids and five asks.
tickSize?numbervenue tickPrice grouping. Pick from tickSizeOptions.
enabled?booleantrueSubscribe only when true.

Return type

FieldTypeNotes
bids / asksOrderbookDepthLevel[]Grouped rows with inclusive cumulative totals, best price first.
spreadOrderbookSpread | undefinedComputed from the ungrouped book.
maxTotalnumberLargest cumulative total across both sides.
symbolOrderbookSymbol | undefinedAssets, precisions, and the venue tick.
tickSizenumber | undefinedThe grouping actually applied.
tickSizeOptionsnumber[]Groupings worth offering, ascending from the venue tick.
orderbookOrderbook | nullThe raw ungrouped book.
isResyncingbooleantrue while rebuilding; the returned rows are the last good ones.
resyncReasonOrderbookResyncReason | nullWhy the current or most recent rebuild happened.
isLoadingbooleantrue until the first book arrives.
statusSocketStatusLive connection status.
errorSymmioRequestError | nullNormalized transport, parse, or snapshot error.
isUnsupportedbooleantrue when the source does not carry this market.

The spread is deliberately taken from the ungrouped book. Grouping moves the touch prices apart by up to two ticks, so a spread read off the returned rows would overstate it — badly on a coarse grid.

Row count and grouping

rows is per side, so rows: 5 returns five bids and five asks.

Grouping collapses levels, so the number of raw levels needed to fill those rows scales with how coarse the grouping is: at ten times the venue tick each row can swallow ten levels. levels is therefore derived from rows and the active grouping rather than fixed — a fixed budget that fills the ladder at the venue tick starves it at a coarse one, leaving dead space where the missing rows should be.

The derived budget is quantized into a few buckets, because levels is a subscription parameter and recomputing it exactly would re-dial the socket every time the grouping nudged. Pass levels yourself only to cap the per-update cost deliberately, accepting that a coarse grouping may then render fewer than rows rows.

Checking coverage first

isUnsupported is the source’s own answer to “do you carry this market”, and it is the check to run before rendering. Asking a venue for a market it does not list is an HTTP error, not an empty book. The hook waits for that answer before subscribing, so an unlisted market never costs a wasted socket — and fails open if the check itself errors, so a transient metadata failure does not hide a listed market’s depth.

useOrderbookStream

The raw synchronized book, without grouping or accumulation.

const { orderbook, isResyncing, status } = useOrderbookStream({ source, marketName: "BTCUSDT", levels: 50, onOrderbook: (book) => depthChart.update(book), });

Parameters

NameTypeDefaultNotes
sourceOrderbookSourceMust implement watchOrderbook.
marketNamestringChanging it tears down the old subscription and clears the stale book.
limit?numbersource defaultSnapshot depth.
levels?numbersource defaultLevels received per update.
enabled?booleantrueSubscribe only when true.
onOrderbook?(orderbook: Orderbook) => voidCalled ahead of the state update. Read through a ref, so an inline arrow does not re-subscribe.
onResync?(reason: OrderbookResyncReason) => voidAlso read through a ref.

Return type

{ orderbook, isResyncing, resyncReason, status, error } — the same fields useLiveOrderbook re-exposes, without the derived rows.

Use onOrderbook to drive a canvas depth chart imperatively without re-rendering the tree on every tick.

useOrderbook

A point-in-time snapshot through TanStack Query.

const { data, isLoading, error } = useOrderbook({ source, marketName: "BTCUSDT", limit: 20, });

Parameters

NameTypeDefaultNotes
sourceOrderbookSourceIts id is part of the query key, so venues never share a cache entry.
marketNamestringMarket name as SYMMIO names it.
limit?numbersource defaultMust be one of source.supportedLimits.
query?QueryParameterTanStack overrides.

Return type

UseQueryResult<Orderbook, SymmioRequestError>.

Do not poll this to build a live ladder. A synchronized diff stream is fresher than any interval you would pick and costs a fraction of the venue’s rate-limit weight. Reach for useLiveOrderbook instead.

Staying correct

The book behind these hooks is not a stream of deltas applied on faith. The source verifies that every update chains onto the last and rebuilds from a fresh snapshot when one does not — on a missed update, a reconnect, or a snapshot that lands too old to bridge.

That is surfaced as isResyncing and resyncReason. While a rebuild is in flight the last good book is still returned, which is deliberate: it is the most useful thing you can show. Dim the ladder rather than blanking it, and let resyncReason explain the pause if the UI has room for it.

Last updated on