feat: sharpen the event study — more events, fair baseline, per-event view
Deploy / lint (push) Successful in 6s
Deploy / test (push) Successful in 41s
Deploy / deploy (push) Successful in 26s

The first run gave only 2 events (N=2 is anecdote, not evidence) and an unfairly
weak coincident baseline, so the +42d lead couldn't be trusted. This makes the
measurement meaningful:

- More, cleaner events: default drawdown threshold 15%→10%, and dedup switched
  from "recover to the high" to a rising-edge + cooldown (40d), so distinct
  drawdowns each register instead of merging.
- Fair comparison: each indicator now warns at its OWN 80th percentile instead of
  a shared absolute 60, removing the artifact that muted the coincident baseline.
- Per-event breakdown (date · depth · breadth lead · coincident lead) so a median
  over a tiny sample can't hide an apples-to-oranges comparison — you see whether
  both warned on the same drawdown.
- Surface precision/recall (best row) + base rate per indicator — the honest edge
  read, not just lead time.

Re-run the Event Study job to regenerate the cached report in the new shape.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 14:54:29 +02:00
parent f8d62e4074
commit 7c5fb1138d
4 changed files with 173 additions and 35 deletions
+11 -1
View File
@@ -316,6 +316,7 @@ export interface EventStudyLeadStats {
median_lead_days: number | null;
events_with_signal: number;
events_total: number;
warn_threshold: number;
mean_path: { rel_day: number; value: number }[];
signal: {
base_rate: number;
@@ -324,6 +325,13 @@ export interface EventStudyLeadStats {
};
}
export interface EventStudyPerEvent {
date: string;
depth_pct: number;
breadth_lead: number | null;
coincident_lead: number | null;
}
export interface EventStudyReport {
available: boolean;
reason?: string;
@@ -331,14 +339,16 @@ export interface EventStudyReport {
params?: {
benchmark: string;
event_threshold_pct: number;
cooldown_days: number;
horizon_days: number;
warn_threshold: number;
warn_percentile: number;
};
events?: { date: string; index: number; depth_pct: number }[];
indicators?: {
breadth_divergence: EventStudyLeadStats;
coincident_price: EventStudyLeadStats;
};
per_event?: EventStudyPerEvent[];
lead_delta_days?: number | null;
recent_breadth?: { date: string; breadth: number; divergence: number | null }[];
}