# Read-only: v3 1m history for India VIX + Nifty Bank (2024-10..2026-10-23); Oct-2026 Nifty options (expired API) for flow features. import sys,os,json,gzip,time,pandas as pd; sys.path.insert(0,os.path.dirname(__file__)); from up import get,q O='/workspace/research/flow-forensics-2026-10/recov/data'; cols=['ts','open','high','low','close','volume','oi'] for nm,k in [('VIX','NSE_INDEX|India VIX'),('BANKNIFTY','NSE_INDEX|Nifty Bank')]: rows=[] for m in pd.period_range('2024-10','2026-10',freq='M'): fr=m.start_time.strftime('%Y-%m-%d'); to=min(m.end_time,pd.Timestamp('2026-10-23')).strftime('%Y-%m-%d') c,j=get(f"/v3/historical-candle/{q(k,safe='')}/minutes/1/{to}/{fr}") if c==200: rows+=j['data']['candles'] else: print('ERR',nm,m,c,str(j)[:120]) time.sleep(0.2) d=pd.DataFrame(rows,columns=cols).drop_duplicates('ts').sort_values('ts'); d.to_parquet(f'{O}/{nm}_1m.parquet'); print(nm,len(d),d.ts.min(),d.ts.max(),flush=True) # Oct-2026 options (days 2026-09-30..2026-10-23), nearest + next expiry, strikes 21600..23600 step 50 os.makedirs(f'{O}/opt_oct',exist_ok=True) EXP=['2026-10-06','2026-10-13','2026-10-19','2026-10-27','2026-11-03'] con={} for e in EXP[:3]: c,j=get('/v2/expired-instruments/option/contract',{'instrument_key':'NSE_INDEX|Nifty 50','expiry_date':e}); print(e,c,len(j.get('data',[])) if c==200 else j) for x in j.get('data',[]): con[(e,x['instrument_type'],float(x['strike_price']))]=x['instrument_key'] ins=json.load(gzip.open('/workspace/research/flow-forensics-2026-10/data/NSE.json.gz')) for x in ins: if x.get('segment')=='NSE_FO' and x.get('name')=='NIFTY' and x.get('instrument_type') in('CE','PE'): e=pd.to_datetime(x['expiry'],unit='ms').tz_localize('UTC').tz_convert('Asia/Kolkata').strftime('%Y-%m-%d') if e in EXP[3:]: con[(e,x['instrument_type'],float(x['strike_price']))]=x['instrument_key'] days=[d.strftime('%Y-%m-%d') for d in pd.bdate_range('2026-09-30','2026-10-23') if d.strftime('%Y-%m-%d') not in ('2026-10-02','2026-10-20')] n=0 for d in days: ex=[e for e in EXP if e>=d][:2] for e in ex: for k in range(21600,23601,50): for t in ('CE','PE'): f=f'{O}/opt_oct/{d}_{e}_{k}{t}.parquet' if os.path.exists(f): continue key=con.get((e,t,float(k))) if key is None: continue path=(f"/v2/expired-instruments/historical-candle/{q(key,safe='')}/1minute/{d}/{d}" if e<'2026-10-25' else f"/v2/historical-candle/{q(key,safe='')}/1minute/{d}/{d}") c,j=get(path) if c!=200 or not j['data']['candles']: continue df=pd.DataFrame(j['data']['candles'],columns=cols); df['ts']=pd.to_datetime(df.ts.str[:19]); df['expiry']=e; df['strike']=float(k); df['type']=t df.sort_values('ts').to_parquet(f); n+=1 print(d,'files',n,flush=True) print('done')