Market Data — Quick Start¶
Get feedd running and consume your first stream.
Install¶
feeddbinarymetadbinary- Venue API credentials for at least one venue
- Shared memory enabled on the host (
/dev/shmon Linux)
See Install + Run for production-oriented installation.
Configure¶
feedd and metad use independent config files. Minimal example:
# /etc/sorcery/feedd.toml
stack = "master"
[control_plane]
bind_host = "127.0.0.1"
bind_port = 5510
[venues.binance]
api_key_env = "BINANCE_API_KEY"
api_secret_env = "BINANCE_API_SECRET"
# Initial instrument set. You can add/remove at runtime via control plane.
subscriptions = [
"perp.binance:BTCUSDT",
]
Credential note: keep API key/secret in environment variables and reference their names in TOML.
Control-plane note: bind_host / bind_port define where clients send UDP subscribe/snapshot commands.
Ring names are derived from stack:
- Market data ring:
/sorcery-{stack}-md - Metadata region:
/sorcery-{stack}-metadata - Snapshot region:
/sorcery-{stack}-snapshot
Run¶
# Start metadata first
metad --config /etc/sorcery/metad.toml &
# Export venue credentials for feedd
export BINANCE_API_KEY="..."
export BINANCE_API_SECRET="..."
# Start market data adapter
feedd --config /etc/sorcery/feedd.toml
Subscribe to an instrument¶
If you configured subscriptions in feedd.toml, streaming starts on boot.
For runtime changes, use your deployment's Control Plane client to add/remove instruments. See Integration Guide and Ordering + Sequencing for recovery semantics when subscriptions change or connections reset.
Consume from SHM¶
#include <sorcery/types.h>
#include <sorcery/ring.h>
#include <sorcery/metadata.h>
auto ring = sorcery::Ring::open("/sorcery-master-md");
sorcery::Consumer consumer{ring};
sorcery::DrainBuffer drain;
sorcery::MetadataStore meta("/sorcery-master-metadata");
while (running) {
for (auto& frame : consumer.drain(drain, 256)) {
if (frame.is_gap()) {
// Invalidate local books and request snapshot recovery.
continue;
}
auto* hdr = frame.header();
auto* body = frame.body();
switch (hdr->msg_type) {
case sorcery::STATUS: {
auto* st = reinterpret_cast<const sorcery::StatusMsg*>(body);
printf("venue=%u conn=%u active=%u\n",
hdr->venue, st->conn_state, st->active_instruments);
break;
}
case sorcery::L1: {
auto* l1 = reinterpret_cast<const sorcery::L1Msg*>(body);
auto* inst = meta.find_instrument(hdr->inst_id);
if (!inst) break;
double bid = inst->to_price(l1->bid_px);
double ask = inst->to_price(l1->ask_px);
printf("inst=%lu bid=%.2f ask=%.2f\n", hdr->inst_id, bid, ask);
break;
}
default:
break;
}
}
}
Verify health¶
Check for periodic STATUS messages (default once per second per venue):
conn_state = 1(CONNECTED)last_rx_age_nsstays boundedactive_instruments > 0for subscribed venues
On any ring gap, follow Ordering + Sequencing before trusting local book state again.
Stop¶
Send SIGTERM and wait for clean shutdown:
For production process control, prefer systemd or container orchestration. See Install + Run.