Appearance
VolumeAnomaly
What it computes
Z-score-based volume-anomaly detector over daily stock volume. The analytic maintains a rolling N-day baseline per symbol; on session rollover it fires one tick carrying:
today_volumerolling_meanrolling_stddevz_score = (today_volume − rolling_mean) / rolling_stddevmultiple = today_volume / rolling_mean
Methodology
Sample z-score against a rolling N-day mean / stddev baseline. The default window is 20 trading days; configurable per spec via VolumeAnomalyParams::window_days. Methodology parity with Bloomberg AVOL / Refinitiv VOL_RATIO.
Inputs
- Stock
TradeTick(accumulates today's volume). - A rolling N-day baseline accumulator seeded from engine daily-close cache at boot.
Output schema (VolumeAnomalyTick)
The field / type / description table below is regenerated from the VolumeAnomalyTick Rust source by docs-site/scripts/inject-doc-tables.ts on every npm run docs:build. Do not hand-edit between the sentinels.
| Field | Type | Description |
|---|---|---|
symbol | Arc<str> | Underlying symbol. |
date | i32 | Session date that just closed (YYYYMMDD). |
today_volume | u64 | Total admitted volume for the just-closed session (shares). |
rolling_mean | f64 | Rolling-window arithmetic mean of daily volumes before today. NaN until the baseline has at least one daily observation. |
rolling_stddev | f64 | Rolling-window sample standard deviation of daily volumes. NaN until the baseline has at least two observations. |
z_score | f64 | (today_volume - rolling_mean) / rolling_stddev. NaN if either of the baseline components is NaN or stddev == 0. |
multiple | f64 | today_volume / rolling_mean. NaN if baseline mean is NaN or 0. |
is_unusual | bool | z_score >= spec.z_score_threshold. false when z_score is NaN. |
warming | bool | true while the rolling baseline is not yet established — the first session-rollover per symbol has no prior daily observation, so rolling_mean / rolling_stddev / z_score / multiple are NaN. Consumers gate on this flag instead of NaN-probing every statistical field; today_volume is always valid. |
Configuration (VolumeAnomalyRequest)
Regenerated from the VolumeAnomalyRequest Rust source — see the note above.
| Field | Type | Description |
|---|---|---|
contracts | SecurityFilter | Contracts the subscription tracks. Stocks only. |
baseline_days | usize | Daily-baseline window. Default 22 (one month of trading days). |
z_score_threshold | f64 | z_score >= threshold flags the day as unusual. Default 2.0 (≈ 97.5th percentile under a normal-distribution assumption). |
conditions | ConditionPolicy | Trade-condition admission policy. |
venues | ExchangeFilter | Exchange / venue admission policy. |
Operational characteristics
- Per-tick latency. O(1) — single volume accumulator update.
- Allocation discipline. Baseline window is a pre-sized
RollingWindow; no hot-path allocations. - Emission cadence. One emission per
(symbol, session-rollover). - Replay parity. Deterministic given identical input tick order.
Example
rust
// Cargo.toml:
// kairos = "0.1"
use kairos::{Client, VolumeAnomalyRow};
let client = Client::connect(("me@example.com", "secret"))?;
let sub = client
.live()
.volume_anomaly(["QQQ"])
.baseline_days(30)
.z_score_threshold(3.0)
.on_event(|row: &VolumeAnomalyRow| println!("z_score={} multiple={}", row.z_score, row.multiple))?;
// ... later ...
sub.unsubscribe();