import pandas as pd,numpy as np,html,json,datetime as dt,sys
sys.path.insert(0,'scripts'); from load import SESS
R='results'; E=html.escape
D=pd.read_csv(f'{R}/daily_summary.csv').set_index('date'); C=pd.read_csv(f'{R}/contrib_daily_pts.csv',index_col=0)
F=pd.read_csv(f'{R}/stock_day_flow.csv'); BR=pd.read_csv(f'{R}/bursts.csv'); SW=pd.read_csv(f'{R}/swing_legs.csv'); WN=pd.read_csv(f'{R}/window_recon.csv')
PO=pd.read_csv(f'{R}/participant_oi.csv'); MB=pd.read_csv(f'{R}/market_breadth.csv').set_index('date'); W=pd.read_csv('data/implied_weights.csv',index_col=0)
def tbl(df,fmt=None,idx=True):
return df.to_html(index=idx,border=0,float_format=(fmt or (lambda x:f'{x:,.1f}')),na_rep='—',escape=True)
def top(d,n=5,asc=True):
x=F[F.date==d].set_index('sym'); s=C[d].sort_values(ascending=asc).head(n)
return ', '.join(f"{k} {v:+.1f} ({x.chg_pct[k]:+.1f}%, dlv {x.DELIV_PER[k]:.0f}% vs {x.DELIV_PER_20d[k]:.0f})" for k,v in s.items())
import zoneinfo; built=dt.datetime.now(zoneinfo.ZoneInfo('Asia/Kolkata')).strftime('%Y-%m-%d %H:%M')
# ---------- per-day summaries (facts auto, interpretation hand-written) ----------
INTERP={
'2026-10-12':"Gap-up (+73) on Trump's Russia–Ukraine 'energy ceasefire' and RBI rupee steps was sold from the first minute (high 09:15, low 15:10, −347 peak-to-trough). Broad-based: 36 of 50 Nifty stocks fell; RELIANCE, HDFCBANK, LT, ICICIBANK, BHARTIARTL did ~150 of the 321-pt fall. Futures: long unwinding (OI down, price down) — longs exiting rather than aggressive fresh shorts; clients bought +13.4k net index-futures contracts into the fall, Pros sold −13.8k.",
'2026-10-13':"'Heavy buying' day #1: +359, closed at the day high (15:12 high, then auction). Catalysts: IT rally on results in the morning (HCLTECH +8.4% on Q2, TCS +6.8%, INFY +4.1%; Nifty 22,321 → 22,566 by 10:00), then FM Sitharaman's LTCG/STT remarks at the Bloomberg New Economy Forum in the afternoon (first headlines 14:25 IST; Nifty 22,553 at 14:00 → 22,700 at 15:14). IT and HDFCBANK/ICICIBANK supplied ~126 pts. Futures OI fell while price rose = short covering; FIIs cut 3.2k index-futures shorts and added 3.1k longs (net +6.4k), clients sold −13.1k. FIIs still sold ₹1,305 cr cash. HDFCBANK/ICICIBANK cash volume was only 0.6x normal — the rally was futures/short-covering led, not heavy delivery buying.",
'2026-10-14':"Next-day reversal: −99 with short buildup (futures OI +2.3k contracts, price −186). FIIs added 6.1k index-futures shorts (net −7.2k), clients bought +15.5k. ICICIBANK (−33 pts), BAJFINANCE, M&M, SHRIRAMFIN led; IT kept rising (INFY +20). Delivery was normal (59.7% vs 59.1%).",
'2026-10-15':"'Heavy buying' day #2: +375 on the Jio IPO price band (RIL +3.4%) plus banks (ICICIBANK +79, RIL +57, HDFCBANK +53, BHARTIARTL +39 pts). Futures OI −19.7k contracts with price up = the biggest short-covering day of the period; FIIs covered 12.6k index-futures shorts (net +16.9k) while selling ₹5,285 cr in cash; clients sold −26.0k. Broad market did not join: median NSE stock −0.7%, 1,755 decliners. NESTLEIND −7.8% after results.",
'2026-10-16':"+149, still short covering (OI −2.7k). Unusual cash flow: FII +₹1,166 cr, DII −₹3,661 cr. BHARTIARTL +2.8% on 4.2x volume and 81% delivery (delivery value ₹3,891 cr vs ₹862 cr normal — consistent with a block trade, not verified); TECHM +8.5% after results/bonus. Highest index-weighted delivery of the period (61.5%).",
'2026-10-19':"'Next-day heavy selling' after the two short-covering days: −257, high at 09:18, low 13:47 (−330). Driven by bank Q2 results over the weekend: HDFCBANK −2.3% (record-low margins, deputy MD exit) −56 pts, AXISBANK −4.2% −33, ICICIBANK −25 (2.6x volume). 09:24–09:28 was the single biggest burst (−150 pts in 5 min). Long unwinding in futures; FIIs added 3.6k shorts and cut 3.3k longs (net −6.9k), clients bought +10.9k. Delivery was the lowest of the period (48% vs 59%) — mostly intraday/derivative selling, not delivery dumping.",
'2026-10-21':"Jio IPO day 1. Gap-up +127 (RIL, IT, Asia) to 23,121 at 09:40, then a 471-pt slide to 22,650 at 14:47 in a series of 40–55 pt futures sell bursts every ~30 min (10:02, 11:06, 11:18, 11:38, 12:11, 13:44). Financials did 176 of the 453-pt fall (HDFCBANK −49, ICICIBANK −34), RIL gave back −41 from its high, BAJFINANCE −3.3% after results. Futures: long unwinding (OI −7.5k); FIIs cut both longs (−4.1k) and shorts (−6.4k); FII cash +₹1,022 cr, DII +₹1,614 cr. Broad market far worse than Nifty: median stock −2.2%, 968 stocks down >3%, breadth 337/2,338.",
'2026-10-22':"Gap-down −124 to 22,555 low (09:35) on Saudi attacks / US diplomats leaving Saudi / oil. Intraday it was two-way (buy bursts +98 at 10:19, +87 at 12:50; sell −77 at 11:42 with 11 stocks at ≥3x volume). Short buildup: futures OI +13.9k contracts (largest add of the period); FIIs added 4.8k shorts; FII cash −₹3,459 cr, DII +₹2,891 cr. HDFCBANK −1.8% on 2.1x volume and delivery value ₹2,486 cr (1.9x normal) = real delivery selling; RIL −2.0% but on low delivery (33% vs 58%) = churn. Also BSE Sensex weekly expiry with closing-auction (CAS) swings reported.",
'2026-10-23':"Friday: Brent ~$113–114 (Houthi attacks on Saudi, Aramco HQ evacuation reports). Open 22,742 → 22,372 at 12:51 (−415): first hour alone −238 pts; IT (−61), RIL (−31), BHARTIARTL (−31), ICICIBANK (−27) led the fall. 13:38–13:42 the biggest buy burst of the period: +137 futures pts on 8.7x futures volume with 16 Nifty stocks at ≥3x volume (no confirmed news catalyst — futures-led spike; nearest event: FM chaired the 30th FSDC meeting ~12:16–13:28 IST, no market-moving remark found; the 13:55 'Finance Minister's tax comments' headline was a repost of the 13-Oct story) — immediately followed by a −64 sell burst at 13:50. Close via auction +83 above 15:14. Day = short buildup (OI +4.0k); FII cash +₹888 cr, DII +₹3,235 cr; VIX 16.9 (period high). Broad market: median stock −2.4%, 1,056 stocks down >3%.",
}
BIG=['2026-10-12','2026-10-19','2026-10-21','2026-10-22','2026-10-23']; HB=['2026-10-13','2026-10-15','2026-10-16']
def card(d):
r=D.loc[d]; mb=MB.loc[d]
facts=(f"Nifty O/H/L/C {r.n_open:,.0f}/{r.n_high:,.0f}/{r.n_low:,.0f}/{r.n_close_official:,.2f} ({r.n_chg:+.1f}, {r.n_chg_pct:+.2f}%), range {r.n_range:.0f} (high {r.n_hi_time}, low {r.n_lo_time}); Bank Nifty {r.bn_chg:+.0f} ({r.bn_chg_pct:+.2f}%). "
f"FII cash ₹{r.fii_cash_cr:+,.0f} cr, DII ₹{r.dii_cash_cr:+,.0f} cr. Nifty futures (all expiries) OI {r.nf_oi_chg_contracts:+,.0f} contracts, price {r.nf_px_chg:+.0f} → {r.nf_buildup}; FII index-fut long {r.fii_idxfut_long_chg:+,.0f} / short {r.fii_idxfut_short_chg:+,.0f} (long share {r.fii_idxfut_long_pct:.1f}%). "
f"Index-weighted delivery {r.w_deliv_pct:.1f}% (20d avg {r.w_deliv_pct_20d:.1f}%). Breadth NSE {int(mb.adv)}/{int(mb.dec)}.")
return f"
{d} ({pd.Timestamp(d).strftime('%a')}) — Nifty {r.n_chg:+.0f}
Top 5 draggers (pts): {top(d)}
Top supporters: {top(d,3,False)}
Facts: {facts}
Reading: {INTERP[d]}
"
# ---------- tables ----------
dt1=D[['n_open','n_high','n_low','n_1514','n_close_official','auction_jump','n_chg','n_range','n_gap','n_hi_time','n_lo_time','bn_close','bn_chg','vix']].copy()
dt1.columns=['Open','High','Low','15:14 (last real)','Official close','Auction jump','Chg','Range','Gap','High @','Low @','BankNifty','BN chg','VIX']
ft=D[['nf_oi_contracts','nf_oi_chg_contracts','nf_px_chg','nf_vol_contracts','nf_basis_near','nf_buildup','bnf_oi_chg_contracts','bnf_px_chg','bnf_buildup']].copy()
ft.columns=['NF OI (contracts)','NF OI chg','NF px chg','NF vol (contracts)','NF basis (near−spot)','NF buildup','BNF OI chg','BNF px chg','BNF buildup']
pl=D[['fii_cash_cr','dii_cash_cr','fii_idxfut_net_cr','fii_idxopt_net_cr','fii_stkfut_net_cr','fii_idxfut_long_chg','fii_idxfut_short_chg','fii_idxfut_net_chg','fii_idxfut_long_pct','pro_idxfut_net_chg','client_idxfut_net_chg','dii_idxfut_net_chg']].copy()
pl.columns=['FII cash','DII cash','FII idx-fut net buy (cr)','FII idx-opt net buy (cr)','FII stk-fut net buy (cr)','FII idx-fut long chg','FII idx-fut short chg','FII net chg','FII long %','Pro net chg','Client net chg','DII net chg']
po2=PO[PO.date.isin(SESS)].pivot(index='date',columns='cat',values=['opt_net_call_chg','opt_net_put_chg'])
po2.columns=[f'{a.replace("opt_net_","").replace("_chg","")} {b}' for a,b in po2.columns]
op=D[['expiry','atm','atm_iv_near','atm_iv_oct27','vix','pcr_near','pcr_all','max_ce_oi_strike','max_ce_oi_lots','max_pe_oi_strike','max_pe_oi_lots','top_ce_add','top_ce_add_lots','top_pe_add','top_pe_add_lots','ce_oi_chg_lots','pe_oi_chg_lots']].copy()
op.columns=['Near expiry','ATM','ATM IV near %','ATM IV 27-Oct %','VIX','PCR near','PCR all','Max CE OI strike','lots','Max PE OI strike','lots ','Top CE add','lots ','Top PE add','lots ','CE OI chg (lots)','PE OI chg (lots)']
fl=D[['w_vol_ratio','w_upvol_share','w_close_vs_vwap','w_deliv_pct','w_deliv_pct_20d','deliv_val_cr','deliv_val_cr_20d','turnover_cr','turnover_cr_20d','n_adv','n_dec']].copy()
fl.columns=['Vol vs 20d (wtd)','Up-minute vol share (wtd)','15:14 vs VWAP % (wtd)','Delivery % (wtd)','Delivery % 20d','Nifty50 delivery ₹cr','20d','Nifty50 turnover ₹cr','20d ','Nifty50 adv','dec']
mb=MB.loc[SESS,['turnover_cr','turnover_cr_20d','deliv_val_cr','deliv_val_cr_20d','adv','dec','median_chg_pct','n_down_gt3pct']].copy(); mb.insert(0,'Nifty %',D.n_chg_pct)
wn=WN.pivot(index='date',columns='window',values='nifty_actual')[['gap','09:15-10:15','10:15-13:00','13:00-15:14','auction 15:15-close']]
# per-window top draggers
WL=pd.read_csv(f'{R}/contrib_windows_long.csv'); WL=WL[WL.sym!='NIFTY_ACTUAL']
wtop=[]
for d in SESS:
for w in ['09:15-10:15','10:15-13:00','13:00-15:14']:
x=WL[(WL.date==d)&(WL.window==w)].set_index('sym').pts.sort_values()
wtop.append(dict(date=d,window=w,nifty=wn.loc[d,w],draggers=', '.join(f'{k} {v:+.1f}' for k,v in x.head(4).items()),supporters=', '.join(f'{k} {v:+.1f}' for k,v in x.tail(3)[::-1].items())))
wtop=pd.DataFrame(wtop).set_index(['date','window'])
sw=SW.set_index(['date','leg'])[['start','end','peak_to_trough','sum_components','banks_fin','reliance','it','top5']]
br=BR.copy(); br['fut_oi_chg_contracts']=(br.fut_oi_chg_units/65).round(0); br=br.drop(columns=['fut_oi_chg_units']); br.loc[br.fut_oi_chg_contracts.isna(),'classify']='n/a (includes open)'
br=br.set_index(['date','start'])
# big day stock tables
def bigtab(d):
x=F[F.date==d].set_index('sym').loc[C[d].abs().sort_values(ascending=False).index[:12],['contrib_pts','chg_pct','vol_ratio_20d','upvol_share','close_vs_vwap_pct','DELIV_PER','DELIV_PER_20d','deliv_val_cr','deliv_val_cr_20d','max_ratio','max_ratio_hm']]
x.columns=['Nifty pts','Chg %','Vol vs 20d','Up-vol share','15:14 vs VWAP %','Deliv %','Deliv % 20d','Deliv ₹cr','Deliv ₹cr 20d','Max 1m vol ratio','at']
return tbl(x,lambda v:f'{v:,.2f}')
gaps=["Holidays: 2026-10-02 (Gandhi Jayanti) and 2026-10-20 — no session; NSE archive URLs for those dates serve the previous day's file (filtered out by DATE1).",
"Spot Nifty / Bank Nifty and all 50 cash stocks: 15:15–15:29 bars are frozen by the NSE closing auction (since 2026-08-03) and are treated as MISSING; last real minute = 15:14. Official close taken from Upstox day candles; the 15:14→official-close move is shown separately as 'auction'.",
"Upstox 1-minute futures volume undercounts the day candle on 22-Oct (Nifty fut 76%, Bank Nifty fut 87% of the day total) and 23-Oct (72% / 55%); all other days ≈100%. Futures 1m volume ratios on those two days are therefore understated (conservative). Cash-stock 1m volume ≈100% of day volume except a few names on 22/23-Oct (min 55%; see results/volume_coverage_check.csv). Not filled.",
"Upstox intraday futures OI is lagged/partial (first bar ≈ previous day's official OI; the official EOD OI only appears next morning). Burst-level 'short covering / fresh longs' labels use Oct+Nov futures 1m OI and are INDICATIVE only; day-level buildup uses official NSE F&O bhavcopy OI (all expiries).",
"Nifty weights: NSE's weightage file was not accessible (NSE API 404). Weights are regression-implied: NNLS of 1-minute Nifty changes on the 50 stocks' 1-minute price changes, 1–23 Oct (5,385 minutes), R² 0.9985, implied weights sum to 99.9%. Daily stock contributions reconcile to the actual Nifty change within ±1.5 pts every day.",
"FII/DII cash = NSE provisional figures captured live by the local macro feed (fiidiiTradeReact). Participant-wise OI/volume, FII derivative stats, delivery and F&O bhavcopy = NSE public archives. No paid sources. 20-day baselines use the 20 sessions before each day (from 2026-09-08).",
"Jio IPO amounts: the local news archive reports issue size ₹30,213 cr and total demand ₹3.73 lakh cr after day 2 (5.5x); the final-day (23-Oct) total and the '₹1.76 lakh cr liquidity' figure in the brief were not found in the archive and are not used.",
"Options IV = Black-76 on the synthetic forward (put–call parity at ATM) from NSE bhavcopy closes; 12-Oct 'near' expiry is 13-Oct (1 day) so its near IV is noisy; 19-Oct's own expiry is skipped (next = 27-Oct)."]
css="""body{font-family:system-ui,-apple-system,Segoe UI,sans-serif;margin:0 auto;max-width:1250px;padding:20px;color:#1b1f24;line-height:1.45}
h1{font-size:1.55em}h2{margin-top:1.8em;border-bottom:1px solid #ddd;padding-bottom:4px}h3{margin:.2em 0}table{border-collapse:collapse;font-size:12px;margin:8px 0;display:block;overflow-x:auto}
th,td{border:1px solid #d6d9de;padding:3px 6px;text-align:right;white-space:nowrap}th{background:#f2f4f7}td:first-child,th:first-child{text-align:left}
.card{border:1px solid #d6d9de;border-left:6px solid #c62828;padding:8px 14px;margin:10px 0;border-radius:4px}.card.up{border-left-color:#2e7d32}.fact{color:#333;font-size:.93em;background:#fafbfc;padding:6px}
.verdict{background:#fff8e1;border-left:6px solid #f9a825;padding:12px 16px;margin:12px 0}img{max-width:100%;border:1px solid #eee}.note{color:#555;font-size:.92em}code{background:#f4f4f4;padding:1px 4px}
td.wrap{white-space:normal;text-align:left;min-width:300px}"""
H=[f"Nifty flow forensics: who sold, who bought — 12–23 Oct 2026",
"Nifty flow forensics, 12–23 Oct 2026: what actually happened on the 300-point falls and the buy-then-sell days
",
"Correction (25-Oct-2026 08:30 IST): an earlier version attributed the 23-Oct 13:38 +137 buy burst (and the recovery from the 12:51 low) to 'Finance Minister's tax comments'. That was wrong: Sitharaman's LTCG/STT remarks were made on
Tue 13-Oct-2026 at the Bloomberg New Economy Forum (Nifty +358.6 / Sensex +1,109 that day;
ET,
Indian Express). The 23-Oct 13:55 headline (INDIA New England News) is a repost of the 13-Oct story — the same item appears in our archive at 13-Oct 21:22, 21-Oct 10:49, 22-Oct 04:14 and 23-Oct 13:55. The 23-Oct burst now reads: no confirmed news catalyst, futures-led spike (8.7x futures volume); nearest event: FM chaired the 30th FSDC meeting ~12:16–13:28 IST, no market-moving remark found. The 13-Oct card now lists the FM remarks (afternoon) and the IT rally (HCL Tech +8% on results, TCS +6%) as catalysts. News matching now ignores headlines whose quoted index move does not match the actual Nifty move and keeps only the first copy of a reposted headline. No numbers changed.
Added 25-Oct 08:45 IST: section 9: who bought and who sold in the 23-Oct burst and the 13-Oct rally.
",
f"Built {built} IST. Research only, not advice; read-only data work, no orders. 9 sessions (20-Oct holiday). Sources: Upstox historical candles (1-min + day; 50 Nifty stocks, Nifty, Bank Nifty, Nifty/Bank Nifty futures, VIX), NSE public archives (security-wise delivery, F&O UDiFF bhavcopy, participant-wise OI, FII derivative stats), NSE provisional FII/DII cash (local feed), local news archive. Sample = 9 sessions: everything below is descriptive, not a tested edge.
",
"Plain-language summary
Short version. The 'heavy buying' days (13-Oct +359, 15-Oct +375, 16-Oct +149) were short covering by FIIs in index futures (Nifty futures OI fell each day while price rose; FIIs cut 3.2k, 12.6k and 5.4k index-futures shorts), with retail clients selling into the rally and FIIs still selling cash on 13/15-Oct. The following sell days (14-Oct, 19-Oct, 22-Oct, 23-Oct) saw FIIs re-add shorts (short buildup on 14, 22, 23-Oct; long unwinding on 12, 19, 21-Oct) while clients bought the dips. FIIs stayed ~89–91% short in index futures the whole fortnight, and their long share rose and fell with Nifty — i.e. the swings were mostly a heavily-short FII book covering and re-shorting, not fresh long money arriving. Most intraday 'heavy' bursts were futures-led and concentrated in 4–5 heavyweights (HDFCBANK, ICICIBANK, RELIANCE, BHARTIARTL, INFY); cash volume in those stocks was often near normal. The Jio IPO window (21–23 Oct) coincided with a broad-market sell-off far worse than Nifty (median NSE stock −2.2% and −2.4% on 21 and 23-Oct, ~1,000 stocks down >3%), but Nifty-50 delivery value was below its 20-day average and Reliance's 22-Oct drop was on low delivery — so there is no evidence in this data of heavyweights being dumped to fund IPO bids; any IPO-funding effect shows up in mid/small caps (interpretation).
",
"New (25-Oct): Buying at the lows — what happened at each intraday bottom 12–23 Oct, and whether 'heavy buying at the low' is tradable for an option buyer (verdict: FAIL).
",
"Recurring patterns (descriptive, n=9)
",
"- FII short-cover / re-short cycle. Up days: FII net index-futures +6.4k, +16.9k, +6.8k (13/15/16-Oct) with Nifty futures OI falling; down days: FII net −7.2k (14th), −6.9k (19th), −2.7k (22nd). Client index-futures flow had the opposite sign to FII on 7 of 9 days (exceptions 16-Oct and 22-Oct, when Pros were the main other side: −8.2k and +8.5k).
",
"- Morning dump on the big down days. On 12, 19, 21 and 23-Oct the day high came in the first 25 minutes (09:15, 09:18, 09:40, 09:16) and the low came between 12:51 and 15:10; peak-to-trough 347, 330, 471, 415 pts. 23-Oct had a 13:38 short burst up (+137) after the low; 21-Oct a late +81 bounce.
",
"- Closing-auction lift. The official close was above the last real 15:14 print on 8 of 9 days (avg +38 pts; 21-Oct +72, 23-Oct +83), while Nifty futures moved only −8 to +43 pts over the same 15:14–15:29 window. Spot closes in this regime are systematically higher than where the futures say the market was trading — relevant for anyone reading spot close vs options/futures.
",
"- Bursts are heavyweight + futures driven. Of 28 five-minute futures bursts (|move| ≥40 pts, futures volume ≥2x), only 3 had ≥10 Nifty stocks at ≥3x cash volume (14-Oct 12:58 sell, 22-Oct 11:42 sell, 23-Oct 13:38 buy). HDFCBANK/ICICIBANK/RELIANCE appear in the top-5 of almost every burst.
",
"- Low-delivery selling. Index-weighted delivery was below its 20-day average on 7 of 9 days (above only on 14 and 16-Oct); the lowest were the two sharpest sell days (19-Oct 48% vs 59%, 22-Oct 51% vs 58%) — selling dominated by intraday/derivative-linked trading rather than investors exiting holdings. Exception: HDFCBANK on 22-Oct (delivery value 1.9x normal).
",
"Day-by-day: big down days
"]+[card(d) for d in BIG]+["Day-by-day: the 'heavy buying' days and the day after
"]+[card(d).replace('class=card','class="card up"') for d in HB]+[card('2026-10-14')]+[
"1. Index, futures and Bank Nifty (official)
",tbl(dt1,lambda v:f'{v:,.2f}'),"Auction jump = official close − 15:14 last real print. Buildup rule: price↑OI↑ long buildup; price↓OI↑ short buildup; price↑OI↓ short covering; price↓OI↓ long unwinding (OI summed over all expiries, so Oct→Nov rollover nets out).
",tbl(ft,lambda v:f'{v:,.1f}'),
"2. Stock contribution to the Nifty move

Points = implied pts-per-₹ × (official close − previous official close). Sum vs actual Nifty change: residual within ±1.5 pts every day. Implied weights: top 10 "+', '.join(f"{k} {v:.1f}%" for k,v in W.implied_weight_pct.head(10).items())+" (full list: implied_weights.csv).
",
"Where in the day (gap / windows / auction)
",tbl(wn),"Top draggers / supporters per window
",wtop.to_html(border=0,float_format=lambda v:f'{v:+.1f}'),
"The main fall and the rebound after the low (peak-to-trough, real minutes only)
",tbl(sw,lambda v:f'{v:+.1f}'),
"3. Volume forensics

Per panel: black = Nifty spot (to 15:14); blue bars = Nifty futures 1m volume ÷ its own 20-day same-minute average (capped 10); orange = index-weighted cash volume ratio of the 50 stocks; shaded = 5-minute futures bursts (|move| ≥40 pts & avg vol ratio ≥2x; green buy, red sell; label = futures pts); triangles = single-stock 1m volume spikes ≥5x that moved Nifty ≥1 pt.
",
"Futures bursts (5-minute) — who moved the index
",tbl(br,lambda v:f'{v:,.1f}'),"classify = sign of Oct+Nov futures OI change over the burst from Upstox 1m OI (lagged → indicative only). top5 = stock contributions (Nifty pts) in the burst; volratio = those stocks' cash volume vs 20-day same-minute avg.
",
"
",
"Buy/sell pressure and delivery (index-weighted, Nifty 50)
",tbl(fl,lambda v:f'{v:,.2f}'),"Up-minute vol share = volume on minutes closing above the previous minute ÷ (up+down) volume, 09:15–15:14. Delivery % from NSE sec_bhavdata_full (EQ series).
",
"Biggest movers on each big day: contribution, volume, delivery
"]+[f"{d}
"+bigtab(d) for d in BIG+HB]+[
"4. Players: FII/DII cash, participant-wise OI, options
",tbl(pl,lambda v:f'{v:,.1f}'),
"Participant columns = change in contracts (NSE fao_participant_oi). FII derivative ₹cr = buy − sell from NSE fii_stats.
Index options: net long calls / puts change by participant (contracts)
",tbl(po2,lambda v:f'{v:+,.0f}'),
"Nifty options: IV, PCR, OI walls
",tbl(op,lambda v:f'{v:,.2f}'),"
",
"5. Context: broad market, Jio IPO, news
",tbl(mb,lambda v:f'{v:,.1f}'),
"Jio IPO check (facts): RELIANCE on 21/22/23-Oct: "+'; '.join(f"{d[5:]} {F[(F.sym=='RELIANCE')&(F.date==d)].chg_pct.iloc[0]:+.2f}%, vol {F[(F.sym=='RELIANCE')&(F.date==d)].vol_ratio_20d.iloc[0]:.2f}x, delivery {F[(F.sym=='RELIANCE')&(F.date==d)].DELIV_PER.iloc[0]:.0f}% (20d {F[(F.sym=='RELIANCE')&(F.date==d)].DELIV_PER_20d.iloc[0]:.0f}%)" for d in ['2026-10-21','2026-10-22','2026-10-23'])+
". Nifty-50 delivery value 21–23 Oct ₹"+', '.join(f"{D.deliv_val_cr[d]:,.0f}" for d in ['2026-10-21','2026-10-22','2026-10-23'])+" cr vs 20-day avg ₹"+', '.join(f"{D.deliv_val_cr_20d[d]:,.0f}" for d in ['2026-10-21','2026-10-22','2026-10-23'])+" cr (below normal). Whole-NSE EQ turnover on 23-Oct ₹1.22 lakh cr vs ₹1.12 lakh cr 20-day avg (+9%). Headline 23-Oct: 'Banking liquidity surplus shrinks to Rs 541 crore as cash crunch increases'. Jio allotment Mon 26-Oct, refunds Tue 27-Oct (per brief) — if IPO-bid funding caused the small/mid-cap selling, refunds could reverse some of it; that is a hypothesis, untested.
",
"Key catalysts per session (local news archive, IST)
| Session | Catalysts |
"]
CAT={'2026-10-12':"Trump 'energy ceasefire' Russia–Ukraine → oil eases; RBI rupee/forex-derivative curbs (weekend); Houthi attacks on Saudi; 'IT, telecom decline as selloff resumes amid FII outflows'; India Sept CPI near RBI ceiling (17:51).",
'2026-10-13':"Asia AI/chip sell-off (Nikkei −2%) but India rebounds on IT (HCL Tech Q2 +8%, TCS +6%) + HDFC Bank; afternoon: FM Sitharaman at Bloomberg New Economy Forum says open to views on LTCG/STT (14:25+ headlines) — 'Sensex jumps 1,109 points' (close; Nifty +358.6). Sources: ET, Indian Express.",
'2026-10-14':"Oil up again on US–Iran/Iraq strikes; 'Gulf oil production rebounds'; IT keeps rallying.",
'2026-10-15':"Jio Platforms IPO price band (₹30,213 cr, 21–23 Oct) → RIL +3%; US Sept CPI hot; WPI 11.4%; 'Short-covering rally may take Nifty to 23,000–23,150' (07:48); Nestle Q2 (−8%), TechM Q2 after close.",
'2026-10-16':"TechM bonus/results; Wipro, Jio Financial in focus; FII net buyers, DII net sellers.",
'2026-10-19':"Weekend bank Q2: HDFC Bank margins record low + deputy MD exit, Axis misses, ICICI beats; 'Crude tops $100'; 'Sensex crashes 900 pts… private banks lead'.",
'2026-10-21':"Jio IPO opens, fully subscribed in ~100 min, 3.16x day 1 (~₹70k cr bids); Bajaj Finance −3% post Q2 margin warning; 'Sensex crashes 1,350 pts from day's high'; VIX +8%.",
'2026-10-22':"US orders diplomats to leave Saudi Arabia; 'Oil jumps $2'; 7 tankers hit in Hormuz; Jio IPO 5.57x, ₹3.73 lakh cr demand; FIIs sell ₹3,459 cr; Sensex weekly expiry closing-auction swings ('CAS chaos'); RBI hike headline (20:55).",
'2026-10-23':"Brent $113–114 (5-month high), Houthi attacks on Saudi, Aramco HQ evacuation report (12:31); US Nasdaq −2.5% overnight (AI doubts); midcap/smallcap −4%; FM chaired the 30th FSDC meeting (~12:16–13:28 IST; no market-moving remark found) — the 13:55 'Sensex jumps over 1,100 pts as Finance Minister's tax comments…' item (INDIA New England News) is a repost of the 13-Oct story, not 23-Oct news; Jio IPO final day; banking liquidity surplus ₹541 cr."}
for d in SESS: H.append(f"| {d} | {E(CAT[d])} |
")
H+=["
Full keyword-filtered headline list: news_by_session.csv. Headlines are reported as published; not independently verified.
",
"6. Data gaps, methods and caveats
"+''.join(f"- {g}
" for g in gaps)+"
",
"Facts vs interpretation
Facts = every number in the tables (prices, OI, participant contracts, FII/DII, delivery, volume ratios). Interpretation = the 'Reading' lines, the word 'short covering' for a whole day (it is the standard price/OI rule, which cannot separate who closed), the IPO-funding link to small-cap selling, and the block-trade guess for BHARTIARTL on 16-Oct. With 9 sessions none of the patterns is statistically tested; treat them as a description of this fortnight only.
",
(lambda p:(lambda t:t.replace(''))(open(p).read()) if __import__('os').path.exists(p) else '')('lows/section_lows.html'),
(lambda p:(lambda t:t.replace(''))(open(p).read()) if __import__('os').path.exists(p) else '')('whoflow/section_whoflow.html'),
"Files
All CSVs in results/: daily_summary, contrib_daily_pts, contrib_windows_long, window_recon, swing_legs, bursts, stock_volume_spikes, stock_day_flow (per stock per day: volume ratio, up-vol share, VWAP, delivery), minute_timeline, participant_oi, fii_deriv_stats, nifty_options_daily, nifty_options_strikes, market_breadth, volume_coverage_check, news_by_session. Scripts: scripts/.
"]
open('index.html','w').write('\n'.join(H)); print('ok',len('\n'.join(H)))