import pandas as pd,numpy as np,matplotlib; matplotlib.use('Agg'); import matplotlib.pyplot as plt M=pd.read_csv('results/lows_minute_windows.csv'); R=pd.read_csv('results/lows_summary.csv') n=len(R); cols=4; rows=int(np.ceil(n/cols)) fig,axs=plt.subplots(rows,cols,figsize=(18,3.1*rows),sharex=True) for ax,r in zip(axs.flat,R.itertuples()): g=M[M.low_id==r.low_id] ax2=ax.twinx(); ax2.bar(g.rel,g.fut_vr.clip(upper=12),color='tab:blue',alpha=.3,width=.9); ax2.set_ylim(0,24); ax2.axhline(3,color='tab:blue',lw=.6,ls=':') ax.plot(g.rel,g.nifty-r.low,color='k',lw=1.4,label='Nifty − low'); ax.plot(g.rel,g.fut-g.fut[g.rel==0].values[0],color='tab:orange',lw=.9,label='Fut − fut@low') ax.plot(g.rel,(g.pe-g.pe[g.rel==0].values[0]),color='tab:red',lw=.8,ls='--',label='ATM PE Δ'); ax.plot(g.rel,(g.ce-g.ce[g.rel==0].values[0]),color='tab:green',lw=.8,ls='--',label='ATM CE Δ') ax.axvline(0,color='grey',lw=.6); ax.axhline(0,color='grey',lw=.5) ax.set_title(f"{r.date[5:]} {r.low_hm} fall {r.fall:.0f} +30m {r.rec30:+.0f}\n{r.classification[:46]}",fontsize=8.5) ax.tick_params(labelsize=7); ax2.tick_params(labelsize=6) for ax in axs.flat[n:]: ax.axis('off') axs.flat[0].legend(fontsize=6,loc='upper left') fig.text(.5,.005,'minutes from the low (−15 … +45). Bars (right axis) = Nifty futures volume ÷ 20-day same-minute average (dotted = 3x). Spot after 15:14 missing.',ha='center',fontsize=9) plt.tight_layout(rect=(0,.02,1,1)); plt.savefig('charts/lows_windows.png',dpi=95); plt.close() # part 2 hit rates Z=pd.read_csv('results/p2_config_stats.csv'); C=pd.read_csv('results/p2_outcomes_controls.csv') fig,ax=plt.subplots(1,2,figsize=(14,4)) for k,(m,lab) in enumerate([('r40_30','P(+40 pts within 30 min) %'),('hold60','P(low not broken in next 60 min) %')]): xs=[];vals=[];labs=[] for X in [150,200,250]: for kind,col in [('signal','tab:blue'),('control_quiet','tab:grey'),('at_low_any','tab:orange')]: if kind=='signal': v=Z[(Z.X==X)&(Z.V==3)&(Z.win=='3bar')&(Z.oi=='any')&(Z.period=='all')][m if m!='r40_30' else 'r40_30'].values[0] if m=='r40_30' else Z[(Z.X==X)&(Z.V==3)&(Z.win=='3bar')&(Z.oi=='any')&(Z.period=='all')]['hold60'].values[0] else: c=C[(C.kind==kind)&(C.X==X)]; v=(c[m]*c.n).sum()/c.n.sum() xs.append(len(xs)+ (X-150)//50); vals.append(v); labs.append(col) ax[k].bar(xs,vals,color=labs); ax[k].set_xticks([1,5,9]); ax[k].set_xticklabels(['fall ≥150','fall ≥200','fall ≥250']); ax[k].set_title(lab,fontsize=10) for x,v in zip(xs,vals): ax[k].text(x,v+.5,f'{v:.0f}',ha='center',fontsize=8) from matplotlib.patches import Patch ax[0].legend(handles=[Patch(color='tab:blue',label='signal: 3-bar fut vol ≥3x + up bar at low'),Patch(color='tab:grey',label='control: same bar, fut vol <1.5x'),Patch(color='tab:orange',label='any first touch of low')],fontsize=7) plt.suptitle('Oct-2024 → Oct-2026, first event per day (futures-volume era)',fontsize=10); plt.tight_layout(); plt.savefig('charts/p2_hitrates.png',dpi=95); plt.close() T=pd.read_csv('results/p2_option_trades.csv'); T=T[(T.expiry_rule=='nearest')&(T['style']=='scale')] s=T[(T.kind=='signal')&(T.X==150)&(T.V==3)&(T.win=='3bar')&(T.oi=='any')].pnl; r=T[T.kind=='random'].pnl; c=T[(T.kind=='control_quiet')&(T.X==150)].pnl fig,ax=plt.subplots(1,2,figsize=(14,4)) b=np.arange(-30,80,4) ax[0].hist(r.clip(-30,78),bins=b,density=True,alpha=.5,label=f'random entries (n={len(r)}, avg {r.mean():.1f})',color='grey') ax[0].hist(s.clip(-30,78),bins=b,density=True,alpha=.6,label=f'signal X150/3x/3bar (n={len(s)}, avg {s.mean():.1f})',color='tab:blue'); ax[0].legend(fontsize=8); ax[0].set_title('ATM CE P&L per trade, pts after costs (SL 20, scale-out)',fontsize=10) for lab,x,col in [('signal X150/3x/3bar',T[(T.kind=='signal')&(T.X==150)&(T.V==3)&(T.win=='3bar')&(T.oi=='any')],'tab:blue'),('control quiet X150',T[(T.kind=='control_quiet')&(T.X==150)],'grey'),('signal X200/3x/3bar',T[(T.kind=='signal')&(T.X==200)&(T.V==3)&(T.win=='3bar')&(T.oi=='any')],'tab:green')]: x=x.sort_values('date'); ax[1].plot(pd.to_datetime(x.date),x.pnl.cumsum(),label=lab,color=col) ax[1].axhline(0,color='k',lw=.5); ax[1].legend(fontsize=8); ax[1].set_title('cumulative pts per 1 unit (multiply by lot size for ₹)',fontsize=10) plt.tight_layout(); plt.savefig('charts/p2_option_pnl.png',dpi=95); plt.close(); print('ok')