"""Independent public-input recomputation of candidate rules and 24h event outcomes.""" import csv,gzip,json,statistics,sys,math from collections import Counter from pathlib import Path base=Path(sys.argv[1]) if len(sys.argv)>1 else Path(__file__).resolve().parent report=json.loads((base/'research.json').read_text()) with gzip.open(base/'inputs.csv.gz','rt',newline='') as f: raw=list(csv.DictReader(f)) with (base/'events.csv').open(newline='') as f: events=list(csv.DictReader(f)) with gzip.open(base/'candidate-ledger.csv.gz','rt',newline='') as f: candidates=list(csv.DictReader(f)) with gzip.open(base/'controls.csv.gz','rt',newline='') as f: controls=list(csv.DictReader(f)) series={s:{} for s in report['symbols']} for row in raw: series[row['symbol']][int(float(row['opened']))]=row assert len(events)==report['retained_events'] assert Counter(r['status'] for r in candidates)==Counter(report['candidate_status_counts']) assert {r['id'] for r in events} == {r['id'] for r in candidates if r['status']=='retained_event'} checked=0 for row in events: s=series[row['symbol']];t=int(float(row['event_open'])) prev=[float(s[t-i*3600]['qv']) for i in range(1,25)] r=s[t];ratio=float(r['qv'])/statistics.median(prev) assert math.isclose(ratio,float(row['relative_volume']),rel_tol=0,abs_tol=1e-9) move=100*(float(r['c'])/float(r['o'])-1) assert abs(move)<=.25 and ratio>=2 assert math.isclose(move,float(row['candle_return_pct']),rel_tol=0,abs_tol=1e-9) for h in (1,4,24): key=f'return_{h}h_pct' if row[key]: assert all(t+i*3600 in s for i in range(1,h+1)) result=100*(float(s[t+h*3600]['c'])/float(r['c'])-1) assert math.isclose(result,float(row[key]),rel_tol=0,abs_tol=1e-9) checked+=1 if row['mfe_24h_pct']: sub=[s[t+i*3600] for i in range(1,25)] mfe=100*(max(float(x['h']) for x in sub)/float(r['c'])-1) mae=100*(min(float(x['l']) for x in sub)/float(r['c'])-1) assert math.isclose(mfe,float(row['mfe_24h_pct']),abs_tol=1e-9) assert math.isclose(mae,float(row['mae_24h_pct']),abs_tol=1e-9) checked+=2 assert checked>0 for published in report['groups']: group=published['group']; horizon=published['horizon_hours'] members=(controls if group=='flat_nonspike_unmatched' else events if group=='all_events' else [r for r in events if r['symbol']==group] if group in report['symbols'] else [r for r in events if r['flow_group']==group]) values=[float(r[f'return_{horizon}h_pct']) for r in members if r[f'return_{horizon}h_pct']] assert len(members)==published['total_rows'] assert len(values)==published['n'] assert sum(v>0 for v in values)==published['positive_n'] for key,actual in [('median_return_pct',statistics.median(values) if values else None), ('positive_pct',100*sum(v>0 for v in values)/len(values) if values else None), ('median_mfe_pct',statistics.median(float(r['mfe_24h_pct']) for r in members if r['mfe_24h_pct']) if horizon==24 and values else None), ('median_mae_pct',statistics.median(float(r['mae_24h_pct']) for r in members if r['mae_24h_pct']) if horizon==24 and values else None)]: expected=published[key] assert (actual is None and expected is None) or (actual is not None and expected is not None and math.isclose(actual,expected,abs_tol=1e-9)),(group,horizon,key,actual,expected) print(f'PASS: {len(events)} retained events, {checked} outcome/path values and {len(report["groups"])} summary cells checked from frozen inputs; independent source provenance and causal claims not proven')