Skip to content

Real-Time Data

Every state change in the CLOB is published once, as a JSON document, to a single Redis stream. On-chain activity is published separately as Anchor events.

The Ledger writes every order and trade state change to the Redis notifications stream with XADD. One producer, one stream; consumers subscribe and filter by the message type.

typeFires on
orderOrder created, updated, filled, cancelled
order_live_activityOrder-book activity for live feeds
price_changeA price level moved
tradeA trade was posted or its status changed
last_trade_priceThe market’s last traded price changed
trade_notificationsUser-facing trade notifications
Terminal window
redis-cli XREAD COUNT 10 BLOCK 5000 STREAMS notifications $

Design notes that matter when you build on it:

  • One stream, not one per topic. Filter client-side on type. Adding a consumer never requires a producer change.
  • Publishing is fire-and-forget. A Redis failure does not fail the underlying write. The stream is a fan-out convenience, not the source of truth — the PostgreSQL ledger is.
  • Use a consumer group if you need at-least-once delivery across restarts. A bare XREAD $ starts from now and silently drops anything that happened while you were away.

The stream is not a replayable log of record. After a disconnect, re-sync from the REST surfaces rather than trying to backfill:

Terminal window
curl -s "http://127.0.0.1:8080/v1/open-orders" -H "Authorization: Bearer $CLOB_TOKEN"
curl -s "http://127.0.0.1:8080/v1/trades?after=$CURSOR" -H "Authorization: Bearer $CLOB_TOKEN"

Then resume the stream.

The OrderBookSummary carries a hash — SHA-256 over the canonical JSON of the market, asset, bids and asks, recomputed on every change.

{
"market": "0xdemo-condition",
"asset_id": "100",
"bids": [{ "price": "0.48", "size": "1200" }],
"asks": [{ "price": "0.52", "size": "900" }],
"hash": "9f2c7a…"
}

Two uses: compare hashes instead of diffing levels to detect change, and confirm a cached snapshot matches what a stream event describes.

Settlement emits an Anchor event, written to the transaction log as a base64 Program data: line prefixed with the 8-byte event discriminator.

#[event]
pub struct TradeSettled {
pub market_id: u64,
pub side: Side,
pub making: u64,
pub taking: u64,
pub fee: u64,
pub maker: Pubkey,
pub taker: Pubkey,
pub signer: Pubkey,
pub outcome_mint: Pubkey, // which leg — YES or NO
pub order_hash: [u8; 32], // joins to the off-chain order
}

order_hash is the join key between on-chain settlements and off-chain orders. outcome_mint tells you which side of the market moved.

The parlay program emits its own set — ParlayCreated, LegSettled, ParlayClaimed, ParlayVoided, plus config and vault events. → Parlays API

Solana ──▶ Helius webhook ──▶ Platform API (Django) ──▶ PostgreSQL ──▶ REST

The Platform API decodes both programs’ events and mirrors them into relational tables. Out-of-order delivery is handled explicitly: a LegSettled arriving before its parent ParlayCreated row raises DeferredParlayEvent, the webhook answers 503, and Helius retries.

That pattern is worth copying if you index these programs yourself — Solana webhook delivery is not ordered, and a parlay’s create and settle events can easily arrive backwards.

You wantUse
Your fills, low latencynotifications stream, type: trade
Book changesnotifications stream, type: price_change + snapshot hash
Authoritative settlement stateGET /v1/trades — CONFIRMED means finalized
Raw on-chain truthSolana logs / TradeSettled events
Product data (questions, charts)Platform API REST
Parlay statePlatform API /api/parlays/
StageTypical
Insert → match decisionIn-process, sub-millisecond
Match → transaction sentOne gRPC hop plus simulation
Sent → finalizedSolana’s finality, a few hundred ms to a couple of seconds
Finalized → CONFIRMED in the ledgerOne confirmation-worker tick
Ledger write → streamImmediate, fire-and-forget

The book updates the moment a match is decided. Money is final at CONFIRMED. A trading system should treat those as two distinct events — quote off the first, account off the second.