Skip to content

BinanceOrderBook

Maintains a live, local Binance SPOT order book for a configurable set of currency pairs, per Binance's documented local-order-book- maintenance algorithm (not linked here -- its status page returns inconsistent HTTP status codes to automated checks; search Binance's spot API docs for "How to manage a local order book correctly"): bootstrap from a REST depth snapshot, then apply WS update-deltas whose U (first update id) brackets the book's current lastUpdateId, resyncing on any gap.

Property Value
Project Virtufin.Worker.BinanceOrderBook
Base class Virtufin.Worker.Host.WorkerBase<JsonNode, JsonObject>
Engine application/x-dotnet-dll (Managed only)

One instance, many pairs

One worker instance tracks a configurable set of pairs (default: every pair it sees) rather than one instance per pair -- one-worker-per-pair was judged operationally heavy for Binance spot's 50+ actively-traded pairs. Internally, a ConcurrentDictionary<string, L2OrderBook<DecimalAmount, DecimalAmount>> (from Virtufin.Base.OrderBooks) holds one book per pair, with Level2OrderBookUpdater applying snapshots and diffs.

The worker subscribes to three flat, un-suffixed topics -- act.exchange.binance.orderbook.update, .snapshot, and the consolidated act.exchange.binance.instrument.snapshot -- rather than the pubsub-topics spec's per-pair pattern for these input topics. The pair for an update-delta event is parsed from Binance's own combined-stream envelope (payload.stream); the pair for a snapshot event is read from the CloudEvent's currencypair extension attribute (Binance's raw REST response has no symbol field of its own). Prices and sizes are normalized to the instrument's tick/lot precision from instrument.info; a pair's book events are skipped until that metadata arrives. The worker's output -- state key, changed/gap topics -- stays genuinely per-pair, matching the spec.

Snapshot delivery

This worker doesn't call Binance's REST snapshot endpoint itself. HttpGetWorker (workers/HttpGetWorker) is deployed once per tracked pair (Binance's depth endpoint is single-symbol), with config.currencypair=<PAIR>, config.publishtopic=act.exchange.binance.orderbook.snapshot and config.venue=binance (HttpGetWorker 0.4.0+ stamps the market-data envelope from venue), and a platform Trigger (Dapr Jobs, the same primitive the TUI's Triggers page exposes) fires periodically to invoke it. Post-gap recovery latency is therefore bounded by the polling interval (default @every 30s), not instant -- a deliberate tradeoff paired with dropping (not buffering) updates received while the book isn't Live.

State

Key act\|hyp.<name>.exchange.<venue>.orderbook.<pair>
Value { bids, asks, last_update_id, updated_at }

Events published

Action Topic Payload
Book updated ...orderbook.changed.<PAIR> the book as a FlatBuffers image (application/x-virtufin-orderbook+flatbuffers, dataschema urn:virtufin:marketdata:orderbook:v1), up to depthlevels levels per side, best first -- the source of truth for that update
Gap detected ...orderbook.gap.<PAIR> { pair, expected, got }

Configuration

Key Default Purpose
currencypairs required Comma-separated canonical pairs, e.g. BTC_USDT,ETH_USDT (Binance's BTCUSDT cannot be split on its own).
saveintervalms 500 Minimum ms between two saves of one pair's book, newest book written once it has passed; 0 writes as fast as saves complete.
publishintervalms 0 Least ms between two changed events of one pair; 0 announces every applied diff. Latest wins: updates inside the interval are applied but not announced, and the next event carries the newest book. Snapshots are always announced.
depthlevels 20 Levels per side in the changed image and the saved book (both come from the same image); 0 keeps every level.
pairconfig -- Per-pair overrides of the two keys above as a JSON object, e.g. {"BTC_USDT":{"depthlevels":50}}; a pair's entry wins, omitted keys fall back to the worker-wide value.
venue binance Multi-venue future-proofing.
world act act or hyp.<name>.
stateservice workmanager SaveStateRequest.service.
apihost host process's gateway Gateway host:port for SaveState; unset uses VIRTUFIN_API_HOST/VIRTUFIN_API_GRPC_PORT.
marketuniverse ALL marketuniverse envelope extension.
clocktype wall for act, else historical clocktype envelope extension.

See the repo README for the full deploy sequence and known-gaps list.

All topics, keys and subjects come from the naming library: the virtufin.venue.binance fragment of this repo on top of virtufin.market. See Naming; the pair in every payload, topic and key is canonical (BTC_USDT).