Appearance
Subscription builder
The per-analytic fluent builder is reached through client.live(), client.historical(start, end), or client.replay(). Each scope exposes the same accessor methods (volatility(), greeks(), gex(), vpin(), ohlcvc(), block_trade(), volume_anomaly(), …); each accessor returns a builder pre-seeded with that analytic's default wire params. The chain terminates with .on_event, which registers a typed callback that fires once per emission.
The builder is macro-generated. Adding analytic #N+1 to the public surface is one line in the kairos crate's public-surface macro expansion; per-analytic cost on the client side is zero hand-written code.
Shape
rust
// Cargo.toml:
// kairos = "0.1"
use kairos::{Client, GreeksRow};
let client = Client::connect(("me@example.com", "secret"))?;
let sub = client
.live()
.greeks(["QQQ"]) // per-analytic accessor; names the universe
.on_event(|row: &GreeksRow| { // terminal verb; fires per emission
println!("delta={} gamma={}", row.delta, row.gamma);
})?;
// … later …
sub.unsubscribe();The accessor argument takes any Into<Targets>: a bare symbol, a list of symbols, an option (root, expiration, right, strike) 4-tuple, or a mixed list of the two. Bare ticker strings expand to the full chain on that symbol plus the underlying stock. Callers identify contracts by symbol (and, for an option, by the 4-tuple), never by an engine-internal contract integer.
Each emission arrives as the analytic's typed <Camel>Row — GreeksRow here, VpinRow for vpin, VolatilityRow for volatility. The row type the callback names determines which analytic's fields are in scope.
Configuring cadence and knobs
Per-analytic knobs — bar size, rolling window, thresholds — are set with chainable per-field setters before the terminal .on_event. Each setter is named for the wire-params field it writes and returns the builder for further chaining:
rust
use kairos::{Client, VpinRow};
let sub = client
.live()
.vpin(["QQQ"])
.bucket_volume(100_000)
.window_size(50)
.min_buckets_for_emit(30)
.on_event(|row: &VpinRow| println!("vpin={}", row.vpin))?;Cadence is orthogonal to delivery: the setters govern how often and over what window the analytic emits; .on_event governs what runs per emission. An analytic with no user knobs (greeks, gex, ohlcvc) takes no setters — the chain is the accessor and .on_event. The setters an analytic exposes are listed on its page; the underlying wire-params fields live under kairos::params::*Request.
The subscription handle
.on_event returns an EventSubscription handle:
| Method | Purpose |
|---|---|
unsubscribe() | Stop delivery and release the engine subscription. Idempotent. |
is_active() | false once unsubscribed or the stream has ended. |
panic_count() | Count of callback panics caught on this subscription. |
Dropping the handle does not stop delivery — bind it and call unsubscribe() to stop. Callbacks across the process share one delivery worker; a panic in a callback is caught, counted, and delivery continues with the next emission. See consuming events for the delivery and panic-isolation model.
Bounded namespaces
.on_event is the same terminal verb on client.historical(start, end) and client.replay(); there it fires the callback once per row over the finite result set. A parquet replay binds the dataset on the chain first:
rust
use kairos::{Client, OhlcvcRow};
let sub = client
.replay()
.ohlcvc(["SPX"])
.from_parquet("ticks.parquet")
.on_event(|bar: &OhlcvcRow| println!("close={}", bar.close))?;Errors (LinkError)
.on_event returns Result<EventSubscription, LinkError>; the error surfaces at subscribe time, before any row is delivered.
| Variant | Meaning |
|---|---|
LinkError::UnknownAnalytic(_) | The analytic id is not registered with the engine. Mirrors KAIROS_ERR_UNKNOWN_ANALYTIC. |
LinkError::NoLiveEntry(_) | The analytic has no live entry point. |
LinkError::Decode { .. } | The engine rejected the encoded params blob. |
LinkError::Engine { .. } | The engine subscribe / run / connect failed with a generic non-OK status. |
LinkError::HistoricalUnwired(_) | The preview historical namespace has no engine-side wiring yet. |
LinkError::Encode(_) | A wire-params encode failed before the call reached the engine. |
The engine validates the wire blob before allocating the subscription state; errors fire fast and never leave the engine in a half-subscribed state.
See also
Clientfor the parent client.- Consuming events for the callback delivery model.
- Tick types for the typed row catalogue.
- Historical builder for the preview bounded-historical shape.
- Replay scope for the preview bounded-replay shape.
- Errors for the full
LinkErrortaxonomy.