Earnings · 5-session forward return of each reporting name · closes to 2026-09-24
Every settled live report of the 25 Core singles whose entry session has a close_adj row; the reaction session is inside the window. The window starts at the close before the reaction session: a premarket report moves its own date, a postmarket report the next session (worker/app/core/earnings_study.py's rule, mirrored). On the labelled span, median +0.1% against +0.6% for the regime-matched null (-0.53 pp), up 51% of the time against 56% (-6 pp). The two nulls agree to 0.01 pp: this class's regime mix is the calendar's, and the regime-matched null adds nothing here.
| condition | dates | windows | middle half | p25 | median | p75 | up | span |
|---|---|---|---|---|---|---|---|---|
Earnings every settled live report of the 25 Core singles whose entry session has a close_adj row; the reaction session is inside the window | 879 | 285 |
| -5.3% |
| +0.1% |
| +6.5% |
| 51% |
| 2016-09-01 2026-09-10 |
unconditional null every session of each reporting name since 2016-09-01 | 55,189 | 505 | -2.3% | +0.6% | +3.5% | 56% | 2016-09-01 2026-09-17 |
regime-matched null (DESIGN's) the labelled sessions re-weighted to this class's regime mix; its windows are the thinnest regime it draws on: downtrend-calm, 46 windows | 55,189 | 46 | -2.4% | +0.6% | +3.5% | 56% | 2016-09-01 2026-09-17 |
The regime-matched null is computed exactly, not drawn at random: every labelled session of each reporting name, weighted by this class's share of events in its regime over the calendar's share of sessions in it. Its quantiles are weighted type-1 quantiles; the unconditional rows use percentile_cont. Its windows are the thinnest regime it draws on, so it is withheld whenever a regime it rests on is below the floor. No confidence interval is drawn. DESIGN asks for block-bootstrap intervals over the overlapping windows; the worker computes them (event_study.py, a seeded date-clustered bootstrap of 2,000 draws) and persists nothing, and DECISIONS.md ADR-0023 records that Postgres cannot reproduce that seeded draw and that a TypeScript port was rejected. Seasonality Studio (page 8) draws a normal approximation because its cells are one date, one observation; here 879 reactions are 285 non-overlapping 5-session windows (3.1x) and the null's 55,139 name-sessions are 505 (109x), so no standard error can be stated without the bootstrap. What is drawn instead is the interquartile range and the de-overlapped count each statistic stands on.
core.earnings_current (live rows), closes from close_adj in core.metric_daily. Floor: 20 non-overlapping windows (forward.ts's BASE_RATE_N_MIN; GOVERNANCE section 5's stricter default is 30), applied inside the statement to each row's own de-overlapped count. 2,524 labelled sessions carry a closed 5-session window (regime_code labels 2,529 sessions to 2026-09-24; the last 5 have none). 893 live reactions on 606 sessions since 2016-09-01; 14 have no close_adj row at the entry session (DELL 9, SNDK 4, CRWD 1); leaving 879 on 596 sessions. In the table, "dates" counts (name, session) rows for this class - 55,189 name-sessions in the null - and "windows" counts non-overlapping sessions. close_adj rows written on different runs can differ by an ex-dividend step (forward.ts's restated-basis caveat).
The labelled span split by the regime label of the entry session, each event cell read against the same-regime sessions of each reporting name unweighted. Every event cell clears the floor at this horizon. Regime labels are restated on every materialiser run, so a cell here is today's rule applied to that day's axes, not the label a reader saw then.
| regime | sessions | of events | events | windows | what followed the event | same-regime null |
|---|---|---|---|---|---|---|
uptrend-calm uptrend, calm | 72.6% | 71.6% | 629 on 427 sessions | 214 | median -0.3%, IQR -5.3% to +5.9%, up 49% of the time | median +0.5%, IQR -2.2% to +3.1%, up 56% of the time |
uptrend-stressed uptrend, stressed | 11.5% | 11.1% | 98 on 71 sessions | 46 | median +1.3%, IQR -4.8% to +6.9%, up 54% of the time | median +1.0%, IQR -2.3% to +4.1%, up 58% of the time |
downtrend-calm downtrend, calm | 6.7% | 7.3% | 64 on 46 sessions | 25 | median +1.7%, IQR -4.8% to +6.1%, up 52% of the time | median -0.2%, IQR -4.6% to +3.7%, up 49% of the time |
downtrend-stressed downtrend, stressed | 9.2% | 10.0% | 88 on 52 sessions | 27 | median +1.6%, IQR -5.3% to +9.3%, up 59% of the time | median +1.9%, IQR -2.3% to +6.1%, up 62% of the time |
regime_code, entity US, from core.metric_daily: 1 uptrend-calm, 2 uptrend-stressed, 3 downtrend-calm, 4 downtrend-stressed.
DESIGN.md:459 asks for a visible running trial counter. This render drew 5 event cells; the lab can draw 150 at its default symbols across its 4 classes, 6 horizons, six regime cells (five for earnings, whose whole span is its labelled span) and the gap class's two directions. Nothing here tests a hypothesis, so no p-value is divided; the figure beside is what the worker's base_rate_report divides its family-wise 0.05 into.
Counted in events.ts: classes x horizons x cells at the default symbols. It counts what a reader CAN look at, which is the multiplicity that matters, not what one reader did look at; the gap class takes any symbol, so the family is a floor, not a ceiling.
DESIGN.md:177 names eight classes; four are here. The other four are absent for reasons that are facts about the warehouse, each with the date it stops being true, and none is approximated by a proxy.
Measured 2026-09-23 against production through the transaction pooler.
Sources: core.earnings_current with close_adj from core.metric_daily (earnings); ALFRED first vintages of CPIAUCSL in core.fred_observations (CPI); core.macro_observations VIX (spikes); core.prices_asof for SPY and the gap class's symbol; regime_code for the labels. Nothing on this page is a percentile of a reading against its own history: each statistic is a distribution of forward returns, ranked against nothing, read only beside its own null over the same names and span. Every window is de-overlapped before counting and the floor of 20 non-overlapping windows is applied to that count in the statement, the regime-matched null's being the thinnest regime it draws on. This page describes what followed; nothing on it predicts. Whether a class is worth acting on is graded on Signal Board (page 20), not here.