# Detect wall crosses (calls: up through heaviest CE strike; puts: down through heaviest PE strike) + outcomes + random same-minute base. import numpy as np,pandas as pd,sys,os,warnings; warnings.filterwarnings('ignore') sys.path.insert(0,os.path.dirname(__file__)); from cwlib import * DD=load(); rows=[] def wall(D,j,sgn,lo,hi): c=D['c'][j] if c!=c: return None K=D['K']; oi=D['oi_CE' if sgn>0 else 'oi_PE'][j] m=((K>=c)&(K<=c+hi)) if sgn>0 else ((K<=c)&(K>=c-hi)); m&=np.isfinite(oi) if lo=='strict': m&=(K>c) if sgn>0 else (K0 else 'oi_PE'; opp='oi_PE' if sgn>0 else 'oi_CE' fixedW=wall(D,5,sgn,'strict',1000) seen=set(); fixed_done=False for i in range(1,LASTX+1): if c[i]!=c[i] or c[i-1]!=c[i-1]: continue for wd in ('dyn','fixed'): if wd=='dyn': W=wall(D,i-1,sgn,'ge',300) else: if i<=5 or fixed_done: continue W=fixedW if W is None: continue crossed=(c[i-1]0 else (c[i-1]>W>=c[i]) if not crossed or (wd=='dyn' and W in seen): continue if wd=='dyn': seen.add(W) else: fixed_done=True k=np.where(K==W)[0][0]; oo=D[own][:,k]; op=D[opp][:,k] r=dict(date=d,exp=D['exp'],dte=(D['exp']-d).days,wd=d.dayofweek,side='call' if sgn>0 else 'put',wall=wd,K=W,i=i,hm=HM[i],spot=c[i], own_oi_ref=oo[i-1],opp_oi_chg30=(op[i]/op[max(0,i-30)]-1)*100 if op[max(0,i-30)]>0 else np.nan, own_oi_chg30_before=(oo[i-1]/oo[max(0,i-31)]-1)*100 if oo[max(0,i-31)]>0 else np.nan) for kk in (1,2,3): r[f'own_drop{kk}']=(oo[i+kk]/oo[i-1]-1)*100 if oo[i-1]>0 and i+kk<375 else np.nan for X in (1,2,3): s=next((i+kk for kk in (1,2,3) if r[f'own_drop{kk}']==r[f'own_drop{kk}'] and r[f'own_drop{kk}']<=-X),None) r[f's_X{X}']=s if s is not None else -1 r[f'basis_chg5_X{X}']=(basis[s]-basis[s-5]) if s is not None else np.nan r['basis_chg5_X0']=basis[i]-basis[i-5] if i>=5 else np.nan rows.append(r) E=pd.DataFrame(rows) # outcomes at every needed signal minute (cross minute for (a), first OI-drop minute for X) for X in (0,1,2,3): col='i' if X==0 else f's_X{X}'; res=[] for r in E.itertuples(): s=getattr(r,col); o=outcome(DD[r.date],s,1 if r.side=='call' else -1) if s>=0 else None res.append({f'{k}_X{X}':v for k,v in (o or {}).items()}) E=pd.concat([E,pd.DataFrame(res,index=E.index)],axis=1) E.to_pickle(f'{C}/results/events.pkl'); E.to_csv(f'{C}/results/events.csv',index=False) print(E.groupby(['side','wall']).size()); print(E.groupby(['side','wall']).date.nunique()) # random same-minute base: outcome for every day x minute 0..LASTX+3, both sides base={} for d,D in sorted(DD.items()): for sgn in (1,-1): for s in range(0,LASTX+4): o=outcome(D,s,sgn) if o: base[(d,sgn,s)]=o B=pd.DataFrame.from_dict(base,orient='index'); B.index.names=['date','sgn','s']; B.to_pickle(f'{C}/results/base_outcomes.pkl'); print('base rows',len(B))