backtests
The universe was the bug. The holdout still said no.
· 25 days ago · 11 min read · Quantcents Research
In June we published an intraday OI-wall option-selling backtest: sell the ATM legs on the Nifty-50 stocks pressed hardest against their open-interest walls, in at 09:20, flat by 15:20. One of the caveats was survivorship — the universe was today's Nifty 50 applied back to 2019.
Fixing that turned out to matter, though not in the way we expected, and not in the direction we first reported.
The Nifty 50 is the wrong universe
Not "slightly suboptimal". Wrong in a way that is easy to demonstrate.
We pulled NSE F&O bhavcopy for every trading day from 2023 to 2026 — 878 sessions, 285 underlyings — and computed, for each day, which stocks were actually carrying the most open interest. Then we asked how often each name in our tested universe was among the 50 most heavily-open-interested F&O stocks.
Four of them — Britannia, Nestlé India, SBI Life and Tata Consumer — qualify on none of the 873 days measured. Not rarely. Never. Under the published rule they remain permanently eligible to be shorted.
Meanwhile M&M (98.2% of days), PNB (97.5%), Vedanta (93.5%), HAL (92.0%) and DLF (92.7%) are among the most liquid option underlyings in the market, and the strategy could never touch any of them.
For a strategy whose entire premise is open-interest structure, a universe selected by index membership is a category error sitting in the middle of the design.
| Metric | Nifty-50 | Top-50 by OI |
|---|---|---|
| Net P&L | ₹19.2 L | ₹26.9 L |
| Net, % of premium sold | +1.499% | +1.697% |
| Sharpe | 1.69 | 2.21 |
| Winning days | 56.2% | 59.3% |
| Fill rate | 90.1% | 92.6% |
| Max drawdown, % of premium | -0.298% | -0.236% |
| Worst single day | −₹2.3 L | −₹1.4 L |
Identical rule on both sides — top 5 names a side by prior-day wall moneyness, one lot, in 09:20, out 15:20, 0.5% per-side slippage, full cost model. Only eligibility differs. 2023-02-01 to 2026-03-17, 739 trading days.
Cumulative net P&L
Net as a share of premium sold, by year
2026 covers January to mid-March, where the chain data ends.
In the tested universe, rarely liquid
- BRITANNIA0.0%
- NESTLEIND0.0%
- SBILIFE0.0%
- TATACONSUM0.0%
- APOLLOHOSP3.6%
- CIPLA8.0%
Excluded from it, almost always liquid
- M&M98.2%
- PNB97.5%
- VEDL93.5%
- HAL92.0%
- DLF92.7%
- BANKBARODA90.1%
Share of the 873 trading days on which each name was among the 50 most heavily-open-interested stock F&O underlyings, from NSE F&O bhavcopy. Inside the expanded book the newly-eligible names earned +2.106% of premium against +1.331% for the Nifty-50 names beside them.
What we claimed, and what happened next
Rebuilding the universe daily from the 50 most heavily-open-interested names lifted Sharpe from 1.69 to 2.21 across 2023–2026. We published that on 31 July, alongside this commitment:
Before this ran we froze a pre-registration — one primary endpoint, a gating fill-rate criterion, a decision rule written in advance, and two holdout windows. Whatever those return will be published, including if they refute this.
The first holdout has run. It refutes it.
The holdout
2019-01 to 2022-12 — 963 trading days, 19,010 legs, a window fixed in advance and not examined until the protocol was frozen. Same rule on both arms; only eligibility differs.
| baseline (Nifty 50) | expanded (top-50 by OI) | |
|---|---|---|
| filled legs | 6,077 | 6,213 |
| premium sold | ₹13.28 Cr | ₹14.92 Cr |
| net | −₹353,264 | −₹676,262 |
| net, % of premium | −0.266% | −0.453% |
| Sharpe | −0.16 | −0.28 |
The pre-registered primary endpoint — paired daily difference in net per rupee of premium — returned −0.2711% per day, bootstrap p = 0.52, 95% CI [−1.11%, +0.57%]. Negative, and nowhere near significant. The fill-rate gate passed; the requirement that the difference be positive in at least 3 of 4 years returned 1 of 4.
Under the decision rule fixed in advance: REJECT. Not "inconclusive" — the point estimate is negative, not merely uncertain.
In-sample the change showed +1.697% against +1.499%. Out of sample, on a window we had never looked at, the direction reverses. Same rule, same code, same costs.
That is what a discovery sample does. It was the 18th variant tested on 2023–2026, and the pre-registration existed precisely because a number found that way is not evidence.
The uncomfortable part: the diagnosis survived
One secondary endpoint asked whether the added names actually out-earn the names they displace, inside the expanded book. They did: +1.379% against −1.028%.
So everything above about the Nifty 50 being the wrong universe still holds. Britannia really never qualifies. M&M really is unreachable. The added names really are better.
And the strategy still lost money. A correct diagnosis is not an edge. That gap — between "this reasoning is right" and "this makes money" — is where most backtests die, and it is invisible from inside the sample that produced them.
The bigger question underneath
Swapping 50 names for 50 names is not the only way to change a universe. The other way is to stop capping it.
The ranking is purely distance of spot from its OI wall — wall / spot − 1, smallest for calls, largest for puts. Nothing in that rule requires 50 candidates. It was 49 because 49 was what had been downloaded. So we downloaded the rest: 207 F&O underlyings, 1,373 additional option chains, 2.23 million rows, and re-ran with the top 5 a side drawn from 202 names.
No liquidity filter. No open-interest floor. No exclusions of any kind. The only change is how many candidates the rank may choose from.
| 1 Jan 2025 – 27 Jul 2026 | Nifty-50 pool (48) | full F&O pool (202) |
|---|---|---|
| legs | 3,632 | 3,736 |
| fill rate | 97.7% | 96.3% |
| premium sold | ₹5.48 Cr | ₹7.50 Cr |
| net | ₹6.81 L | ₹19.67 L |
| net, % of premium | +1.242% | +2.623% |
| winning days | 55.1% | 61.8% |
| max drawdown | −₹3.22 L | −₹2.69 L |
Split into the window we developed on and the window we did not:
| window | days | Nifty-50 | full F&O | paired daily difference |
|---|---|---|---|---|
| 2025-01 → 2026-03 | 306 | +1.200% | +2.735% | +2.894%/day, p = 0.010 |
| 2026-04 → 2026-07 | 79 | +1.393% | +2.199% | +0.442%/day, p = 0.72 |
It is not taking more risk
Both books run the same size: 10 legs a day, and near-identical notional — ₹66.3 L against ₹66.1 L median daily, which is what margin actually tracks.
What differs is that the wider book's names carry richer options on the same notional. ATM premium is 2.60% of spot against 1.93%. It sells 37% more premium while risking the same amount, because it is selling higher implied volatility — not a bigger position. Its worst drawdown is shallower: −4.07% of daily notional against −4.86%.
It survives the attacks that killed the others
- Adversarial fills. Charge every unfilled leg that book's own 10th-percentile return: +1.360% against +0.342%. The advantage holds.
- Concentration. The top five names are 46.5% of the wider book's net, which looks fatal. A name-clustered bootstrap — resampling names rather than days, so "we got lucky with which stocks exist" is the hypothesis under test — returns a 95% CI of [+1.253%, +4.326%] against a +1.200% baseline, with P(wide ≤ base) = 0.020.
- Sub-periods. Four of five quarters positive.
Nothing else we have tested on this strategy has survived all three.
Why a distance floor turns out to be the same idea
A natural refinement: skip the trade when spot isn't close enough to its wall. On 49 names that filter removes 12.7% of legs and binds on 46% of days. On 202 names it removes 2%, and on the fresh window at a 4% threshold it removes none.
The reason is one number — how far the 5th-ranked call candidate actually sits from its wall:
| universe | median distance | days it sits >2% away |
|---|---|---|
| Nifty-50 · 48 | 1.78% | 41.5% |
| full F&O · 202 | −0.51% (already through) | 8.0% |
With four times the candidates the ranking never has to settle for a distant name. A floor skips the trade when nothing is close; a wider universe finds something that is. Same idea — the second is the better implementation.
What would decide it, and what we cannot decide here
The backtest charges a flat 0.5% per side to every name. The wider book's return concentrates in mid-caps with wide spreads — DIXON +40.8% across 12 legs, Kalyan Jewellers +20.8%, CAMS +16.7% — which is exactly where a flat assumption is weakest.
Charging both books more changes nothing: the advantage sits flat between +1.53% and +1.56% from 0.5% all the way to 2.5% per side, because slippage scales with premium and hits both proportionally. Only the differential matters. Holding the Nifty-50 names at 0.5% and charging only the added names more:
| slippage on added names | 0.50% | 0.75% | 1.00% | 1.25% | 1.50% | 2.00% |
|---|---|---|---|---|---|---|
| advantage over Nifty-50 book | +1.53% | +1.12% | +0.71% | +0.30% | −0.11% | −0.94% |
Breakeven is roughly 1.4% per side. The wider universe wins if and only if those names cost under about 2.8× what the large caps cost to trade.
Nothing in this backtest measures that. The evidence we do have points the wrong way: the added names carry roughly 30% lower open interest at the wall, and they fill worse in both windows — 96.3% against 97.7%, and 95.9% against 98.7% on the fresh window.
So the number that decides a 15-month, 2.2-million-row backtest is a bid-ask spread we have never recorded. That is not a data problem we can out-compute; it is a measurement we have to go and take — live, per name, at 09:20. We are now taking it.
What this is not
- The 306-day window is burned. We examined it repeatedly while forming hypotheses. The July result on this same page is the precedent: an in-sample positive that reversed out of sample.
- The fresh window is null. 79 days, +0.442%/day, p = 0.72 — and the mechanism reverses: added names earn more than Nifty names on the long window (+3.175% vs +0.369%) and less on the fresh one (+2.011% vs +3.662%). A real structural effect should not flip its own explanation. Either 79 days is too few, or the long window is fitted. Both readings are live.
- Survivorship, still. This is the current F&O list. Recently listed names have short histories; delisted ones are absent. Six underlyings from the 2019–2022 top 50 cannot be reconstructed at all — the largest is HDFC, in the liquid top 50 on 100% of those days and simply gone from our vendor. Adding names is the easy half of survivorship; the names that vanished are the hard half, and we have not solved it.
- A vendor gap we cannot repair. One expiry, 2023-06-29, is missing upstream: 14 of 49 files empty, the rest holding a single date. Because that contract goes active in late May it removes roughly 23 trading days from 2023. We verified three ways — a normal re-fetch, a cache-bypassing fetch, and intraday 5-minute bars — that the data does not exist at source. It does not contaminate the 2023 figure (those days contribute zero legs), but 2023 is measured on 216 trading days rather than ~248, and we now say so next to the number.
- Costs are modelled, not paid. 0.5% per side, Zerodha's F&O schedule, date-aware STT. Real fills are their own subject — and, per the section above, the decisive one.
- Not advice. A research log, not a trade plan.
What we take from it
Two things, and only one is about money.
The first is that we published a refutation of our own headline four days after publishing the headline. That is what the pre-registration was for. It cost us the number and it is the only reason the next one should be worth anything.
The second is that widening the universe is the strongest candidate we have found in twenty-one attempts — and its entire margin rests on an execution cost nobody has measured. So we are measuring it: bid-ask spread, per name, at 09:20, logged live. One line of instrumentation, a number within weeks, and no amount of further backtesting substitutes for it.
If those names quote inside ~1.4% per side, this is worth about +1.5 percentage points of premium — larger than every selection refinement we have tested combined. If they quote wider, it is a cost illusion and the matter is closed.
Either way we will publish it.
Sources & method
- NSE F&O bhavcopy, 2023-01-02 to 2026-07-28 — 878 sessions, 285 underlyings — for point-in-time notional open interest. Top-50 universe = trailing 20-day median, computed strictly from data through D−1.
- 207 NSE F&O underlyings from the exchange scrip master for the wide-pool test; 202 with usable chains. Panel coverage 207 of 207 names, 180,865 stock-days.
- ICICI Breeze daily option chains and 5-minute intraday prints at 09:20 / 15:20. Burned-window acquisition: 1,373 chains, 2,234,796 rows, zero fetch failures.
- Ranking uses the prior session's settled open interest against the same session's opening price — the convention the live system uses. Nothing reaches forward.
- Costs: Zerodha equity-F&O schedule, date-aware options STT (0.0625% → 0.1% → 0.15%), ₹20/order brokerage, NSE transaction charges, 18% GST, SEBI and stamp; slippage 0.5% per side, stress-tested to 2.5% uniformly and 3.0% differentially.
- Statistics: paired daily differences with a stationary bootstrap (geometric blocks, mean length n^(1/3), 4,000 replications, two-sided), reported alongside the t-test so any disagreement between them is visible rather than hidden.
- Lot sizes from the current NSE F&O scrip master, held constant — a documented approximation that mis-scales absolute rupee P&L in earlier years and largely cancels in the per-premium unit used throughout.
- Daily coverage of the true top 50 averages 49.3 of 50 and never falls below 47.
Comments
No comments yet. Be the first.
Share this
Reserve your spot
Daily NIFTY / BANKNIFTY brief — coming soon.
Numbers, citations, no hype. We'll email you the day the first edition lands.
Unsubscribe anytime.