Skip to main content

Order Flow

The order-flow methods feed the chart's microstructure views: the depth ladder, the liquidity heatmap (Bookmap-style), the bid/ask footprint, and the derivatives indicators (CVD, open interest, funding). Every method here is optional and capability-gated — implement the ones your data source can serve and the chart lights up the matching feature.

Order-flow data reaches the chart two ways:

  1. Bar enrichment — attach extra fields to the Bar objects you already return from loadBars / subscribeRealTimeBars. The CVD, Open Interest, and Funding Rate indicators read straight off the bars.
  2. Dedicated methodsgetDepth, getTimeAndSales, getExternalSeries, getBookHistory and their subscriptions.

Adoption stages

Ship one stage at a time. Each row is independently useful; nothing below a stage is required for the stages above it.

StageLights upImplementAdvertise
1. Bar enrichmentCVD, Open Interest, Funding Rate indicatorsExtra Bar fields on existing loadBars / subscribeRealTimeBarsNothing — field presence is enough
2. DepthDepth ladder, live liquidity heatmapgetDepth, subscribeDepthsupportsDepth
3. Tape (time & sales)Footprint bars, market-profile layersgetTimeAndSales, subscribeTimeAndSalessupportsTimeAndSales
4. Derivatives seriesOI/funding independently of bar loadsgetExternalSeriessupportsExternalSeries
5. Book historyHeatmap warm start with real historygetBookHistorysupportsBookHistory

Checkpoint per stage: after wiring a stage, open only its view — for example the depth ladder after stage 2 — and confirm it populates while every other order-flow feature stays inert. A stage that breaks another stage's view means a flag is advertised without its method.

1. Bar enrichment fields

export interface Bar {
time: number; open: number; high: number; low: number; close: number;
volume?: number;
turnover?: number;
/** Volume bought by the taker (aggressor). CVD = 2·takerBuyVolume − volume. */
takerBuyVolume?: number;
/** Futures open interest aligned to this bar. */
openInterest?: number;
/** Funding rate in effect at this bar. */
fundingRate?: number;
}

Populate these and the derivatives pane indicators work with no other wiring. takerBuyVolume is available from most kline endpoints; openInterest and fundingRate are futures-only, so leave them undefined for spot instruments — the indicators then draw nothing, which is the correct result.

2. Depth (getDepth / subscribeDepth)

Drives the depth ladder and the live liquidity heatmap.

getDepth returns a one-shot snapshot; subscribeDepth streams the full book on every change. Each callback payload is a complete book (already merged), not a diff — maintaining the exchange's diff/sequence sync (e.g. dropping stale updates, resyncing on a gap) is the feed's job, so the chart always receives a consistent snapshot.

Depth contracts
interface DepthRequest { symbol: SymbolInfo; levels?: number }
interface DepthSubscription extends DepthRequest { id: string }

interface DepthLevel { price: number; size: number; orderCount?: number; tier?: string }
interface MarketDepth {
symbol: SymbolInfo;
bids: DepthLevel[]; // descending price
asks: DepthLevel[]; // ascending price
timestamp?: number;
}
type DepthCallback = (depth: MarketDepth) => void;

3. Time and sales (getTimeAndSales / subscribeTimeAndSales)

The aggressor-tagged trade tape behind the footprint and market-profile layers.

getTimeAndSales backfills a historical window (footprint ladders for past bars); subscribeTimeAndSales streams live prints. aggressor tags the taker side — for Binance-style buyerIsMaker, a maker buyer means the aggressor hit the bid, i.e. a sell.

Time & sales contracts
interface TimeAndSalesEntry {
time: number; price: number; size: number;
aggressor?: 'buy' | 'sell' | 'between';
sequence?: number;
}
interface TimeAndSalesRequest { symbol: SymbolInfo; limit?: number; startTime?: number; endTime?: number }

interface TimeAndSalesUpdate { symbol: SymbolInfo; prints: readonly TimeAndSalesEntry[]; snapshot: boolean }
type TimeAndSalesCallback = (update: TimeAndSalesUpdate) => void;

4. Derivatives series (getExternalSeries)

Instrument-level series that aren't derivable from OHLCV.

These exist only on futures. Return { kind, points: [] } for instruments that don't have them — consumers treat an empty result as "not available for this instrument", never an error. This is the same data you can instead push via the openInterest / fundingRate bar fields; getExternalSeries is the pull form when you want the series independently of the bar load.

External series contracts
type ExternalSeriesKind = 'open-interest' | 'funding-rate';
interface ExternalSeriesRequest {
symbol: SymbolInfo; kind: ExternalSeriesKind;
interval?: ChartInterval; startTime?: number; endTime?: number; limit?: number;
}
interface ExternalSeriesResult { kind: ExternalSeriesKind; points: { time: number; value: number }[] }

5. Recorded book history (getBookHistory)

Lets the liquidity heatmap warm-start with real history instead of building up from an empty book.

Return periodic L2 snapshots newest-relevant-first over [sinceMs, now]. The heatmap seeds its columns from these so the first paint already shows a populated liquidity band. Omit the method (or return no snapshots) and the heatmap just builds forward from the live book.

Book history contracts
interface BookHistorySnapshot { time: number; bids: DepthLevel[]; asks: DepthLevel[] }
interface BookHistoryRequest { symbol: SymbolInfo; sinceMs?: number; limit?: number }
interface BookHistoryResult { symbol: SymbolInfo; snapshots: BookHistorySnapshot[] }

Sourcing order flow through a backend

Four requirements point the same way — depth diff-sync, one shared exchange connection fanned out to many browsers, a recorder for getBookHistory, and keeping exchange endpoints off the client. Serve order flow from your own backend, not the browser. A depth or trade socket per browser tab multiplies exchange connections and trips per-IP limits; one server-side connection per symbol, fanned out, does not.

A clean pattern, and the one the reference demo uses:

  • One combined WebSocket per exchange venue multiplexes every stream (depth + trades for every symbol) via SUBSCRIBE/UNSUBSCRIBE, rather than a socket per stream.
  • Venue routing on the symbol. A namespaced ticker like SPOT:BINANCE:BTCUSDT or PERP:BINANCE:BTCUSDT carries its venue in the prefix. Route SPOT: to the spot market and PERP: to futures — they differ in REST host, book diff-sync rules, and whether open interest / funding exist at all. Your getDepth / getTimeAndSales / getExternalSeries pick the venue from the symbol so the same feed serves both.
  • A recorder persists periodic book snapshots so getBookHistory can serve the heatmap's warm-load.

Because everything is capability-gated, you can ship this incrementally: bars first, then depth, then the tape, then derivatives — each one lights up its feature the moment the method (and its onReady flag) appears.

Next steps

  • Realtime Bars — the bar stream stages 1–3 build on.
  • Market Events — semantic timeline events alongside microstructure data.