Skip to content

Feeds and Books

Family: SDK-crate (atelier-connect::framework) · Min version: atelier-connect 0.0.10

A Feed is a live subscription to one (venue, instrument, datatype) stream. It allocates an identity, walks a lifecycle, and binds to exactly one reconstructed book — a SourcedOrderBook for order data or a SourcedTradeBook for trades — which runs its own lifecycle underneath.

Feed

A Feed names what is being ingested and tracks its subscription state. The book that reconstructs the stream is held by the reconstruction layer, keyed off the feed's id.

Field Type Meaning
id FeedId (UUIDv4) Allocated at creation; stable across every transition
venue Exchange The exchange the feed subscribes to
instrument TradingPair The canonical pair
datatype FeedDatatype Orders (→ SourcedOrderBook) or Trades (→ SourcedTradeBook)
state FeedState Lifecycle state (below)

FeedId is a distinct newtype so it cannot be confused with a wire ArtifactId, TaskId, or SinkId.

Feed lifecycle

State Meaning Terminal
Requested Created from the task spec; FeedId allocated; nothing on the wire no
Subscribing Subscribe frame(s) sent; awaiting first data or seed no
Live Streaming; the bound book is synced no
Resubscribing Recovering from a book gap; re-seeding per the recovery action no
Reconnecting The shared venue connection dropped; awaiting re-establishment no
Draining Task stop; flushing in-flight work within the drain timeout no
Closed Normal end (possibly partial) yes
Rejected Venue or datatype unsupported yes
Failed Connection unrecoverable within the reconnect budget yes
stateDiagram-v2
    [*] --> Requested
    Requested --> Subscribing
    Subscribing --> Live
    Live --> Resubscribing: book gapped
    Resubscribing --> Live
    Live --> Reconnecting: connection dropped
    Reconnecting --> Subscribing
    Live --> Draining: task stop
    Draining --> Closed
    Subscribing --> Rejected: unsupported
    Reconnecting --> Failed: budget exhausted
    Closed --> [*]
    Rejected --> [*]
    Failed --> [*]

Diagram: a Feed walks Requested → Subscribing → Live, loops through Resubscribing on a book gap and Reconnecting on a dropped connection, and ends in one of Closed, Rejected, or Failed.

let mut feed = Feed::new(
    Exchange::Binance,
    TradingPair::new("BTC", "USDT"),
    FeedDatatype::Orders,
);
feed.to_subscribing();
feed.to_live();
assert_eq!(feed.state(), FeedState::Live);

Books

A Book reconstructs a live view from a feed's normalized events. Both book kinds share one FSM: Empty → Synced ⇄ Gapped → Closed. Synced and Gapped interconvert because a continuity break drops the book to Gapped and a successful re-seed returns it to Synced.

State Meaning
Empty No seed applied yet
Synced Current and source-continuity verified
Gapped Continuity broke; applies nothing until re-seeded
Closed Terminal — the bound feed closed or the task drained
stateDiagram-v2
    [*] --> Empty
    Empty --> Synced: seed / first frame
    Synced --> Synced: apply in order
    Synced --> Gapped: continuity broke
    Gapped --> Synced: re-seed
    Synced --> Closed: feed closed
    Gapped --> Closed: feed closed
    Closed --> [*]

Diagram: a Book starts Empty, reaches Synced on its seed, stays Synced while updates apply in order, drops to Gapped on a continuity break, returns to Synced on a re-seed, and ends Closed.

SourcedOrderBook

Reconstructs a live order book from a feed's normalized deltas. Its apply step is source-agnostic and selected by the feed's ReconstructionModel; it either advances Synced or transitions to Gapped and raises ResyncNeeded — it never silently drops an update. apply returns a BookOutput of Snapshot (a full replacement is now current) or Applied (an incremental update landed).

let mut book = SourcedOrderBook::new(pair, model, recovery);
match book.apply(delta) {
    Ok(BookOutput::Applied) => { /* book advanced, still Synced */ }
    Ok(BookOutput::Snapshot) => { /* full book replaced */ }
    Err(resync) => { /* now Gapped; re-seed per resync.action */ }
}

SourcedTradeBook

Reconstructs an ordered, de-duplicated public-trade log. Every print is appended — no head-only drop. Where the venue provides a trade sequence, a duplicate or out-of-order print is deduped and a missed sequence transitions the book to Gapped; where no sequence exists, it is best-effort and never gaps.

let mut trades = SourcedTradeBook::new(pair);
trades.apply(trade, Some(seq))?;

See also