Method
Data
NSE's end-of-day F&O bhavcopy, 2011 to present, in two file formats with a changeover on 2024-07-08. Both are parsed into one schema and cross-checked against each other on the sessions where NSE published both.
Earlier data exists back to 2005 but is not used: on 2008-01-15, NSE listed 268 BankNifty option contracts and not one of them traded.
Prices
The underlying forward is recovered from put-call parity on the chain itself rather than taken from a separate price feed, which avoids any dividend or interest assumption. Implied volatility uses Black-76 on that forward, solved by bisection. Contracts that did not trade are excluded — NSE publishes a settlement price for every listed contract, but a price nobody paid is not a market observation.
Median share of the listed chain that actually traded in a session: 26.6%. Mean: 30.4%. Both are low because most listed strikes, on most days, sit too far from the money for anyone to trade them — expected, not a data fault.
An at-the-money implied volatility could be computed for 40.7% of the 28,343 (date, expiry) rows in the panel; the rest are left null rather than estimated, because a session with too few traded strikes near the money cannot support an honest implied-volatility read.
Interest rate sensitivity
The discount rate (default 6.5%, a single constant) enters only through Black-76's discount factor once the forward is already recovered from put-call parity, so its effect on the implied volatility solved from a given price is expected to be small. Measured directly, not assumed: rebuilding one year (2021) of the panel at rate=4% and rate=8% and comparing every (date, expiry) row's ATM IV against the same rows built at the 6.5% baseline —
- rate 4%: median shift 0.0244 vol points, mean 0.0363, largest single-row shift 0.197 vol points (n=1,056 rows with a usable ATM IV on both builds)
- rate 8%: median shift 0.0147 vol points, mean 0.0218, largest single-row shift 0.119 vol points
A quarter of a vol point at most, against typical ATM IV levels of
15–25 vol points on this index (median ~21.6 in the year checked) — genuinely
negligible across the spec's 4%–8% band. atm_straddle is
identically unchanged across all three rates (it is the observed market close
price, which does not depend on the discount rate at all — only the IV solved
from it does); skew_25d has a negligible median shift but a rare
larger one, from the discrete nearest-25-delta strike occasionally flipping
which strike counts as "nearest" when a small rate change nudges a delta
across a near-tie, not a defect.
Testing
Each hypothesis was registered with its expected direction before being run. Patterns were looked for in the earlier years and confirmed on the later ones. Significance uses permutation tests, which assume nothing about the shape of the distribution. Benjamini-Hochberg correction is applied within each family.
Why some ideas were not tested
11 of the 27 pre-registered ideas could not be honestly tested with the methods used here, and are marked Not tested rather than Rejected (1 calendar, 1 expiry, 2 positioning, 7 volatility). Four different problems caused this:
- Some ideas pick their event by how unusual a number already is (for example, "implied volatility is in the top 10% of its own past year") and then measure that same number's next move. An unusually extreme reading tends to be followed by a less extreme one anyway, purely by chance — so this design finds an apparent pattern even in data with no real relationship at all, and the significance check this project uses does not correct for it.
- One idea compares two things quoted on the same day, and the safeguard that checks whether a detector is reading the future cannot tell "this day's own readings were split in half" apart from "the detector read tomorrow's data." It could not be verified as safe, so it was never run.
- Some ideas measure implied volatility, which is not observed directly — it is computed from an option's price using an assumed clock, and this analysis counts calendar days while the market trades on business days. A simulation with no market behaviour in it at all, only that calendar-day clock, reproduces those ideas' published effects almost exactly, and each one weakens toward nothing or reverses sign under a trading-day clock. The apparent pattern lived in the clock, not in BankNifty.
- Some ideas set a fixed percentage threshold on open interest, which turns out to accumulate over a contract's life rather than hold roughly steady the way a price does — an ordinary day's change already exceeds the threshold most of the time, so it does not select anything unusual.
None is a failure of the idea itself. All four are limits of the testing machinery available today, recorded honestly rather than smoothed over — every excluded idea's own exact reason is on its card in the catalogue.
Regimes
BankNifty's expiry rules changed twice — weekly expiries were introduced and later abolished. The boundaries are derived from the data rather than assumed, and every result is reported per regime.
The COVID window
The out-of-sample window (2020 onward) contains March-June 2020, four months unlike any other in this sample (800 of the panel's rows). Every out-of-sample result was re-checked with that window excluded entirely from the out-of-sample side — not down-weighted, removed — and compared verdict by verdict, pattern by pattern, against the result with it included.
All three Confirmed patterns are identical either way.
decay_final_three_days, weekly_final_two_days and
monthly_final_two_days do not depend on the COVID window at
all — none of their own selected events fall inside it, and each one's
effect, p-value and verdict are unchanged with it removed. The headline
result of this project does not depend on March-June 2020 in any way.
Two patterns move, neither ever Confirmed in either version:
january_iv_higher: Candidate (p=0.094) with the window included, Confirmed (p=0.0035) without it. Its own effect is unchanged (its events fall only in January, outside the dropped window) — what moves is the comparison baseline, computed across the whole out-of-sample panel: removing the extreme volatility of March-June 2020 lowers that baseline, which makes January's already-fixed IV elevation look larger by comparison, not because January itself changed.skew_inverted_precedes_iv_rise: Candidate (p=0.952) with the window included, Rejected (p=0.295, wrong direction) without it. Unlike the pattern above, its own effect genuinely shrinks once the COVID months are removed — several of its own selected events fall inside that window — and what little remains reverses sign against its declared prior.
Neither movement changes which patterns are published as Confirmed, and both were already unproven (Candidate, not Confirmed) in the version that includes the COVID window.
Downloads
Every statistic on this site is also written as CSV and parquet, in
data/ next to this page:
- patterns.csv / patterns.parquet
— one row per pre-registered pattern: every number in every card's Analyst
table, plus the per-regime breakdown.
regimesis JSON-encoded text in the CSV (CSV cannot hold a nested structure) and a native struct column in the parquet. - panel.csv / panel.parquet — the full per-(date, expiry) analytics panel every pattern above was computed from: forward, ATM IV, ATM straddle, skew, PCR, max pain, open interest, realised volatility and the variance risk premium, one row per session per listed expiry.
Both formats carry identical numbers; parquet keeps types and the nested
regimes column exactly as this project computed them, CSV opens
anywhere. A technical reader can export, chart or re-check any figure on this
site without touching the HTML at all.