# curated per-day headlines from local archive (market-moving keywords), saved for the report import json,glob,re,pandas as pd H={} for f in sorted(glob.glob('/workspace/market-live-stack/feeds/news/2026-10-*.jsonl')): for l in open(f): try: j=json.loads(l) except: continue h=j.get('headline','') if h not in H or j.get('ts','')lo)&(rows.ts<=hi)&rows.headline.str.contains(pat,flags=re.I,regex=True)].sort_values('ts') x=x[~x.headline.str.contains('SEBI|Notice of Demand|Recovery Certificate',regex=True)] x=x.drop_duplicates(subset=x.headline.str.lower().str[:45]) if False else x x['session']=d; out.append(x) o=pd.concat(out) # rule (2026-10-25 newsfix): ignore headlines whose quoted index move doesn't match the actual Nifty move that day (late reposts) import sys; sys.path.insert(0,'/workspace/research/flow-forensics-2026-10/scripts'); from news_rules import mismatch o['move_mismatch']=[mismatch(t.replace('T',' '),h) for t,h in zip(o.ts,o.headline)] o[o.move_mismatch==True].to_csv('results/news_ignored_move_mismatch.csv',index=False); print('ignored (quoted move mismatch):',(o.move_mismatch==True).sum()) o=o[o.move_mismatch!=True]; o.to_csv('results/news_by_session.csv',index=False); print(o.groupby('session').size())