Skip to content

AlpacaOrderBook

Maintains live Alpaca crypto order books from the orderbook messages of Alpaca's market-data stream, saves each pair's book to State and announces each save on the pair's changed topic (openspec pubsub-topics, "Order book"). Built on Virtufin.MarketData.DevKit.

Property Value
Project Virtufin.Worker.AlpacaOrderBook
Base class Virtufin.MarketData.DevKit.MarketDataWorkerBase
Engine application/x-dotnet-dll
Input topic act.exchange.alpaca.orderbook.update (raw frames from WebSocketManager)
Output topic <world>.exchange.alpaca.orderbook.changed.<PAIR>
State key <world>.exchange.alpaca.orderbook.<PAIR>
ce-type com.virtufin.exchange.alpaca.orderbook.changed

Behaviour

  • Full book, then changes. After a subscribe Alpaca sends each pair's full book ("r": true), then level changes, where size 0 removes a level. A full book replaces the pair's book; changes before the first full book are skipped.
  • No snapshots, no gaps. Alpaca's stream has no update ids and nothing to resync against. After a reconnect or actor handoff the WebSocketManager's connection handshake logs in and subscribes again, and Alpaca resends the full book.
  • Saved book. { bids, asks, last_update_id, updated_at }, best level first, each level [price, size] as decimal strings: the same shape as BinanceOrderBook's, so readers serve both venues. last_update_id counts the messages applied.
  • Announced, then saved. A changed pair is announced on its changed topic with the book as of that frame; a full book ("r": true) is always announced. Announcements are at most one per publishintervalms per pair (default 0: every change; latest wins when set), and the saved book at most one per saveintervalms (default 500; the writer always keeps the newest). One frame can carry several pairs: one changed event per changed pair.
  • Envelope. exchange=alpaca, marketworld, marketuniverse, clocktype, and eventtime = ce-time = Alpaca's time (t) of the last applied message.
  • Ignored. Status messages (success, subscription), errors, other stream types and untracked pairs.

Config (CreateWorker config, as extension attributes)

Key Default Meaning
currencypairs required Comma-separated canonical pairs, e.g. BTC_USD,ETH_USD (Alpaca's BTC/USD)
pricedecimals 8 Decimals kept for prices (Alpaca's stream has no tick size)
sizedecimals 9 Decimals kept for sizes
saveintervalms 500 Minimum time 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 change. Latest wins: changes inside the interval are applied but not announced, and the next announcement carries the newest book. A full book (r) is 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_USD":{"depthlevels":50}}; a pair's entry wins, omitted keys fall back to the worker-wide value
stateservice workmanager State namespace of the books
world act act or hyp.<name>
venue alpaca Topic segment and exchange
marketuniverse ALL marketuniverse extension
clocktype wall for act, else historical clocktype extension

Deploy

  1. Feed (WebSocketManager 0.7.0+): connect to wss://stream.data.alpaca.markets/v1beta3/crypto/us with auto_reconnect, publish_topic = act.exchange.alpaca.orderbook.update and a handshake whose handler logs in and subscribes to the pairs' orderbooks. Alpaca allows one stream connection per account.
  2. Worker: AlpacaOrderBook/scripts/create_worker.py (one instance for all pairs), then start it.
  3. Consume: subscribe to act.exchange.alpaca.orderbook.changed.BTC_USD and read the book from State.

The alpaca-order-book-live.verso notebook in the examples repo runs all three, including the handshake handler.