# Squeeze detector vs price-only breakout (same episodes). Train <2026-01-01, test 2026. Excludes nothing; 23-Oct & 26-Oct flagged as hypothesis-source days. import pandas as pd,numpy as np,sys,os from scipy.stats import fisher_exact,binomtest sys.path.insert(0,os.path.dirname(__file__)); from tradelib import * S=pd.read_csv(f'{R}/results/squeeze_candidates.csv',parse_dates=['date']) S['test']=S.date>='2026-01-01'; src=S.date.isin(pd.to_datetime(['2026-10-23','2026-10-26'])) S['flow']=(S.call_oi_chg5_pct<=-2)&(S.basis_chg5>=3) base=S.groupby('episode').head(1).assign(kind='price_breakout_first') flow=S[S.flow].groupby('episode').head(1).assign(kind='squeeze_flow_first') callonly=S[S.call_oi_chg5_pct<=-2].groupby('episode').head(1).assign(kind='call_oi_drop_first') basisonly=S[S.basis_chg5>=3].groupby('episode').head(1).assign(kind='basis_widen_first') A=pd.concat([base,flow,callonly,basisonly]); A=A[~A.date.isin(pd.to_datetime(['2026-10-23','2026-10-26']))|True] rows=[] for k,g in A.groupby('kind'): for sp,m in [('train',~g.test),('test',g.test),('test_excl_23_26Oct',g.test&~g.date.isin(pd.to_datetime(['2026-10-23','2026-10-26']))),('all',g.test|~g.test)]: x=g[m]; b=base[(base.test==(sp!='train'))] if sp!='all' else base rows.append(dict(kind=k,split=sp,n=len(x),y200=x.y200.mean()*100,y_entry100=x.y_entry100.mean()*100,med_gain_entry=x.gain_entry.median(),med_mae60=x.mae60.median(),med_run_at_entry=x.run_now.median(),med_base_min=x.base_min.median())) Q=pd.DataFrame(rows).round(2); print(Q.to_string()) # Fisher: squeeze vs price-only first breakout (test) for sp,m in [('train',lambda d:~d.test),('test',lambda d:d.test)]: f=flow[m(flow)]; b=base[m(base)] for y in ['y200','y_entry100']: print(sp,y,'flow',f[y].sum(),'/',len(f),' base',b[y].sum(),'/',len(b),' fisher p=%.3f'%fisher_exact([[f[y].sum(),len(f)-f[y].sum()],[b[y].sum(),len(b)-b[y].sum()]])[1]) Q.to_csv(f'{R}/results/squeeze_summary.csv',index=False) out=[] for r in pd.concat([base,flow]).itertuples(): K=float(round(r.entry/50)*50); e=nexp(r.date) for st in ('sl_only','spotstop','runner'): z=trade(r.date,e,K,r.hm,st,RL=r.RL) if z: out.append(dict(date=r.date,hm=r.hm,kind=r.kind,test=r.test,style=st,**z)) TR=pd.DataFrame(out); TR.to_csv(f'{R}/results/squeeze_trades.csv',index=False) print(TR.groupby(['kind','test','style']).agg(n=('pnl','size'),mean=('pnl','mean'),median=('pnl','median'),win=('pnl',lambda x:(x>0).mean()*100),rs=('pnl_rs_lot','sum')).round(2).to_string()) print(TR[TR.date>='2026-10-23'].round(2).to_string()) print(flow[flow.date>='2026-10-20'][['date','hm','RL','entry','run_now','call_oi_chg5_pct','basis_chg5','y200','gain_entry']].to_string())