"""Contemporaneous price-stress diagnostics, separate from future prediction.""" import numpy as np import pandas as pd def limit_alert_rate(alerts, refill_sessions=20): """One-token bucket, initially full, refilling on original trading sessions. Held observations remain held. The cap acts on existing chronological alerts; it never refits a threshold or selects a test-period top-k score. """ if (refill_sessions<1 or not alerts.index.is_unique or not alerts.index.is_monotonic_increasing): raise ValueError('Require ordered unique sessions and a positive refill interval') output=pd.Series(pd.NA,index=alerts.index,dtype='boolean') tokens=1.0 for i,value in enumerate(alerts): if i:tokens=min(1.0,tokens+1.0/refill_sessions) if pd.isna(value):continue accepted=bool(value) and tokens>=1.0-1e-12 output.iloc[i]=accepted if accepted:tokens=0.0 return output def recent_stress_labels(index_returns, trailing_sessions=2, drop_cut=-.02): """Whether either index has stressed today or in the preceding fixed sessions.""" if (trailing_sessions<0 or not index_returns.index.is_unique or not index_returns.index.is_monotonic_increasing or not np.isfinite(index_returns.to_numpy()).all()): raise ValueError('Require complete, finite, ordered index returns') daily=index_returns.min(axis=1).le(drop_cut) labels=daily.rolling(trailing_sessions+1,min_periods=trailing_sessions+1).max().astype('boolean') onsets=daily & ~daily.shift(1,fill_value=False) return daily,labels,onsets def detection_metrics(alerts,labels,onsets,maximum_delay=2): """Count matched current/recent stress alerts and onsets detected within a delay. No alert before an onset is counted as contemporaneous detection. Missing sessions never shorten the fixed onset-to-deadline window. """ if maximum_delay<0 or not alerts.index.is_unique or not alerts.index.is_monotonic_increasing: raise ValueError('Require ordered unique alert sessions and nonnegative delay') calendar=alerts.index valid=alerts.notna() & labels.reindex(calendar).notna() actual=alerts.reindex(calendar).fillna(False).astype(bool) & valid y=labels.reindex(calendar).fillna(False).astype(bool) matched=int((actual & y).sum());count=int(actual.sum()) eligible=[];detected=[];held=[];censored=[];delays=[] for i,date in enumerate(calendar): if not bool(onsets.get(date,False)):continue if i+maximum_delay>=len(calendar): censored.append(str(date.date()));continue window=calendar[i:i+maximum_delay+1] if not valid.reindex(window).all(): held.append(str(date.date()));continue eligible.append(str(date.date())) hits=np.flatnonzero(actual.reindex(window).to_numpy()) if len(hits): detected.append(str(date.date()));delays.append(int(hits[0])) return dict(scorable_sessions=int(valid.sum()),alerts=count,matched_alerts=matched, unmatched_alerts=count-matched,precision=matched/count if count else None, recent_stress_base_rate=float(y.loc[valid].mean()) if valid.any() else None, event_onsets=len(eligible),onsets_detected=len(detected),onsets_missed=len(eligible)-len(detected), onset_recall=len(detected)/len(eligible) if eligible else None, onset_dates=eligible,detected_onset_dates=detected,held_onset_dates=held, right_censored_onset_dates=censored,delay_sessions=delays, median_delay_sessions=float(np.median(delays)) if delays else None, scope='Contemporaneous fixed index-price stress proxy; no independent anomaly gold or causal/forecasting claim')