Skip to content

KB / operations

Event Feed

Last verified

The Event Feed is the platform’s append-only history of “something changed”. Every cycle, the capture stage diffs the current classifier state against the previous snapshot and writes a row for each flip into signal_transitions. The dashboard’s Event Feed and the JSON API’s /api/v1/events/feed compose these alongside fired alerts, news items, and source failures into one unified stream.

The 18 classifiers

KNOWN_SIGNALS in app/signals/transitions.py is the canonical list. Adding a 19th means adding the emit logic, the classifier, and the entry to this set.

SignalWhat it tracks
zgl_crossSPY above / below the Zero Gamma Level
gex_signGEX regime band: deep_positive / positive / neutral / negative / deep_negative
pcr_0dte_band0DTE put/call ratio band: bullish_skew / neutral / bearish_skew
regimeMarket regime change (PANIC / RISK-OFF / CAUTIOUS / TRANSITIONAL / RISK-ON)
energy_regimeEnergy regime change (STABLE / ELEVATED / SHOCK / CRISIS / SHOCK_UP / FALLING / SHOCK_DOWN / RISING)
alignment_severitySignal alignment severity (STRONG_ALIGNMENT / MIXED / MODERATE_DIVERGENCE / STRONG_DIVERGENCE)
wall_proximitySPY approaching the gamma call or put wall
dix_bandDIX classifier band (Favorable / Leaning / Neutral / Cautionary / Adverse)
volatility_regimeVIX term-structure regime flip (CONTANGO / BACKWARDATION / FLAT)
vix_bandVIX level band change (Low / Normal / Elevated / High / Fear / Extreme fear)
health_score_bandHealth score band crossing (favorable / mixed / cautionary / adverse)
cascade_stageTransmission cascade stage 0–5
zero_dte_notional_band0DTE notional dollar volume band (light / active / elevated / heavy / extreme)
mag7_weight_bandMag-7 share of S&P 500 (concentrated / elevated / normal)
sma_stackCTA trend-stack score 0–4 (count of SPY ≥ 20/50/100/200 SMA)
cot_specs_bandCFTC speculator net positioning Z-band (extreme_short / short / neutral / long / extreme_long)
aaii_spread_bandAAII bull-bear spread band (extreme_bear / bear / neutral / bull / extreme_bull)
squeeze_setupComposite short-squeeze setup state (none / partial / primed)

Row shape

Every row in signal_transitions carries:

ColumnMeaning
timestampET-aware ISO 8601 with offset (Law 1) — the moment the transition was detected
signalOne of the 18 classifier names above
from_stateThe previous band/state (NULL only on the very first sighting per signal)
to_stateThe new band/state
valueThe raw numeric reading at the transition, where applicable
spy_at_eventSPY close at event time (for cross-referencing price action)
contextJSON blob with extra per-classifier context (optional)

Dedup and restart behavior

Two mechanisms prevent transition floods:

A startup lint pass (lint_transitions) validates timestamps and known-signal coverage, surfacing any drift between KNOWN_SIGNALS and what’s actually in the table.

Retention

signal_transitions is keep-forever by default. Pruning is opt-in via RETENTION_TRANSITIONS_DAYS; default 0 means never prune. The retention contract is enforced by tests/test_retention_guard.py — any DELETE against this table that isn’t gated on the env-var check fails CI.

The endpoint that queries transitions caps its default window at 36 hours (days=114), but that’s a query convenience, not a retention horizon. The full history stays on disk indefinitely.

The unified events feed

/api/v1/events/feed composes five event kinds into one chronological stream:

KindSource tableSeverity surface
alertalerts (fired/resolved rows)info / warn / critical per alert definition
signal_transitionsignal_transitionsDerived from signal + to_state
cascade_transitioncascade_transitionsinfo for stage-down, warn for stage-up
newsnews_itemsinfo
source_failuresource_runs where ok=0warn if a source failed in the window

Query knobs: days (1–14, default 7), kinds (comma-separated whitelist), severity minimum (info / warn / critical), limit (default 200, hard cap 1000), bucket=true to group by trading-day.

The dashboard’s Event Feed widget consumes this endpoint directly — the “Today / Yesterday / This week” grouping comes from bucket=true.

See also