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:
- Bar enrichment — attach extra fields to the
Barobjects you already return fromloadBars/subscribeRealTimeBars. The CVD, Open Interest, and Funding Rate indicators read straight off the bars. - Dedicated methods —
getDepth,getTimeAndSales,getExternalSeries,getBookHistoryand 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.
| Stage | Lights up | Implement | Advertise |
|---|---|---|---|
| 1. Bar enrichment | CVD, Open Interest, Funding Rate indicators | Extra Bar fields on existing loadBars / subscribeRealTimeBars | Nothing — field presence is enough |
| 2. Depth | Depth ladder, live liquidity heatmap | getDepth, subscribeDepth | supportsDepth |
| 3. Tape (time & sales) | Footprint bars, market-profile layers | getTimeAndSales, subscribeTimeAndSales | supportsTimeAndSales |
| 4. Derivatives series | OI/funding independently of bar loads | getExternalSeries | supportsExternalSeries |
| 5. Book history | Heatmap warm start with real history | getBookHistory | supportsBookHistory |
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:BTCUSDTorPERP:BINANCE:BTCUSDTcarries its venue in the prefix. RouteSPOT:to the spot market andPERP:to futures — they differ in REST host, book diff-sync rules, and whether open interest / funding exist at all. YourgetDepth/getTimeAndSales/getExternalSeriespick the venue from the symbol so the same feed serves both. - A recorder persists periodic book snapshots so
getBookHistorycan 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.