# Fix the trade rule on TRAIN ONLY (Oct-2024..Dec-2025): max mean net pts/trade with n_train>=30, per side. Writes results/fixed_rule.json + train grid. import numpy as np,pandas as pd,sys,os,json,time sys.path.insert(0,os.path.dirname(__file__)); from cwlib import *; from stats import variants E=pd.read_pickle(f'{C}/results/events.pkl'); T=pd.read_pickle(f'{C}/results/trades_all.pkl'); T=T[T.status=='ok'] T=T.merge(E[['date']],left_on='ev',right_index=True); T=T[T.date<'2026-01-01'] # <- train only V=variants(E); rows=[] for (side,wd,vn),(idx,X) in V.items(): t=T[T.ev.isin(idx)&(T.X==X)] for (ins,ex),g in t.groupby(['instr','exit']): rows.append(dict(side=side,wall=wd,variant=vn,X=X,instr=ins,exit=ex,n=len(g),days=g.date.nunique(),mean_pts=g.pnl.mean(),median_pts=g.pnl.median(),win=(g.pnl>0).mean()*100,sum_rs_lot=g.pnl_rs_lot.sum(), y2024=g[g.date.dt.year==2024].pnl.mean(),y2025=g[g.date.dt.year==2025].pnl.mean())) G=pd.DataFrame(rows).sort_values('mean_pts',ascending=False); G.round(2).to_csv(f'{C}/results/train_grid.csv',index=False) rule={} for side in ('call','put'): g=G[(G.side==side)&(G.n>=30)] rule[side]=g.iloc[0].to_dict(); rule[side]['n_candidates_searched']=int(len(G[G.side==side])); rule[side]['n_eligible']=int(len(g)) rule['fixed_at_ist']=time.strftime('%Y-%m-%d %H:%M',time.gmtime(time.time()+19800))+' IST'; rule['criterion']='max mean net pts/trade on train, n_train>=30' json.dump(rule,open(f'{C}/results/fixed_rule.json','w'),indent=1,default=float) pd.set_option('display.width',250); print(G[G.n>=30].groupby('side').head(8).round(2).to_string()); print(json.dumps(rule,indent=1,default=float))