Skip to content

Adding a venue: an Alpaca order-book worker

This walkthrough adds an order-book worker for Alpaca. It adds one file to the new worker's repo. No other repo, and no central file, changes.

1. The fragment

naming/virtufin.worker.alpacaorderbook.yaml in the worker's repo:

fragment: virtufin.worker.alpacaorderbook
imports: [virtufin.market]

venues:
  alpaca:
    symbol: "{BASE}/{QUOTE}"          # BTC_USD <-> BTC/USD
    intervals: {1Min: 1m, 1Hour: 1h, 1Day: 1d}

bind:
  # Partial application: the venue-generic order book with venue = alpaca.
  orderbook: {entity: virtufin.market/orderbook, with: {venue: alpaca}}

workers:
  alpacaorderbook:
    consumes: [orderbook.update]
    produces: [orderbook.changed, orderbook.gap]

If a second Alpaca worker appears later, move the venues and bind blocks into a shared virtufin.venue.alpaca fragment and import it from both workers.

2. The names it gets

Name Value
raw feed topic (consumed) act.exchange.alpaca.orderbook.update
changed topic act.exchange.alpaca.orderbook.changed.BTC_USD
gap topic act.exchange.alpaca.orderbook.gap.BTC_USD
state key act.exchange.alpaca.orderbook.BTC_USD
ce-subject currency_pair/BTC_USD
ce-type com.virtufin.exchange.alpaca.orderbook.changed
worker response / error wrk.alpacaorderbook.response / wrk.alpacaorderbook.error
venue symbol of BTC_USD BTC/USD

3. The code

var names = NameRegistry.Load(typeof(AlpacaOrderBookWorker).Assembly);
var book = names.GetEntity("virtufin.worker.alpacaorderbook/orderbook");
var alpaca = names.GetVenue("alpaca");

foreach (var pair in config.Pairs)                       // canonical: BTC_USD
{
    var symbol = alpaca.ToVenueSymbol(pair);             // BTC/USD, for the Alpaca API
    var topic = book.Topic("changed", World.Act, pair);  // act.exchange.alpaca.orderbook.changed.BTC_USD
    var key = book.Key(World.Act, pair);
}

// Incoming venue symbol back to the canonical pair, among the configured pairs.
alpaca.TryFromVenueSymbol("BTC/USD", config.Pairs, out var canonical);

The generic entity can also be bound in code, without a fragment: names.GetEntity("virtufin.market/orderbook").Bind(venue). Only the fragment makes the family visible to the docs and to the conflict check, so a deployed worker always ships one.

4. What protects everyone else

  • The fragment cannot change existing names: composition adds families and never edits them. The conformance suite checks that every Binance name is unchanged after the Alpaca fragment is added.
  • If another repo also declared venue alpaca, or bound the order book to alpaca again, composition would fail with a message naming both fragments, and so would the specs site build.