24 September update: Read the fixed ₹60L / ₹5L comparison of all 132 opportunities. It separates closed profit, open marks, ordering sensitivity and missing-stop assumptions. Earlier figures below use different experiments and must not be treated as interchangeable.
An independent audit of the 132-trade sample reported three numbers: eight entry prices outside their daily range, three rows needing corporate-action checks, and a ₹61,474.80 gap between the broker statement and the trade log. All three are real. None of them is a cause. This resolves each into one.
| symbol | broker | trade log | gap | what is actually wrong |
|---|---|---|---|---|
| JUNIORBEES | ₹42,582.84 | ₹-172.64 | ₹42,755 | Two trades in the log against a year of broker activity. The log did not record it |
| AVALON | ₹67,228.15 | ₹50,157.00 | ₹17,071 | A third round trip sits in the database marked cancelled with ₹0 realised |
| everything else | 24 symbols | ₹1,648 | Rounding and charge attribution. Ordinary | |
Eight entry prices sit outside the range of the session they are recorded against. The useful question is not how many, but whether the price exists anywhere nearby. For five of the eight it exists exactly one session away.
| symbol | recorded date | entry | that day's range | price actually exists | verdict |
|---|---|---|---|---|---|
| NIFTYBEES | 2026-04-02 | 273.45 | 251.70–259.29 | 13 days away (15 Apr) | date or price wrong |
| SAKAR | 2026-04-17 | 633.14 | 580.10–614.35 | 2 sessions (15 Apr) | date attribution |
| NATIONALUM | 2026-04-28 | 433.00 | 436.05–444.20 | 1 session (29 Apr) | date attribution |
| SGMART | 2026-04-28 | 561.59 | 543.00–556.80 | 1 session (27 Apr) | date attribution |
| JUNIORBEES | 2026-05-05 | 778.94 | 750.55–763.50 | no nearby session | unexplained |
| HONASA | 2026-05-07 | 360.87 | 343.00–357.00 | 1 session (8 May) | date attribution |
| WELCORP | 2026-05-22 | 1,348.81 | 1252.20–1306.80 | 1 session (21 May) | duplicate of the 21 May row |
| GOLDBEES | 2026-09-10 | 125.30 | 126.05–126.93 | 1 session (9 Sep) | date attribution |
The audit flagged three rows for corporate-action checks. Two are real: POCL falls 1401.80 to 561.10 on 21 July, a ratio of 2.498 against a 2.5:1 action, and TDPOWERSYS falls 1534.80 to 780.10 on 24 August, 1.967 against a 2:1. The third, KIRLOSENG at +20%, is a day in the market.
The right question was the one behind it: how many are there? Scanning all 2,971 symbols the backtests read gives 58. Nothing in the pipeline detects or adjusts for a single one of them.
| corporate actions in the panel | count | why |
|---|---|---|
| caught by the per-symbol move guard | 40 | A 2:1 or larger shows as a >35% one-day fall, and the guard drops the symbol whole |
| missed by it | 18 | Every one a 1.5:1, showing as a ~33% fall — just inside the band. TRENT, OLAELEC and sixteen others |
So the guard that protects these studies is a filter written to drop garbage ticks, which catches a 2:1 split by accident and a 1.5:1 not at all. That is luck, not design.
The published results survive, and it was checked rather than assumed. Across the G3 population (46,404 setups) and the stop-rules population (2,876), the number holding a position across one of the eighteen missed actions is zero. A different window would not have been so lucky.
All 58 actions are now back-adjusted: every bar before an action is divided by its factor, open, high, low and close together so ranges stay internally consistent. Volume is left alone, because multiplying it would invent liquidity that did not exist. Re-running the detector on the adjusted panel finds zero remaining discontinuities, and the script refuses to write the file if any survive.
Adjusting the panel is not a free change: forty symbols the move guard used to discard for having had a split now stay in, so the population grows. The test that matters is whether the published conclusion moves with them.
| G3 measurement | raw panel (published) | adjusted panel |
|---|---|---|
| setups after G1, G2 and G4 | 32,007 | 32,706 |
| Spearman, momentum vs return | −0.079 | −0.078 |
| G3 at 25, kept minus refused | +0.34pp (p=0.43) | +0.37pp (p=0.38) |
| Mar–May / Jun–Jul | +2.21 / −2.76 | +2.15 / −2.64 |
| threshold 15 | −0.89pp (p=0.0005) | −0.91pp (p=0.0003) |
Adjust the panel for corporate actions, or detect them. Fifty-eight known events and a guard that sees forty of them by accident. A ratio near a simple fraction on a single session is a reliable signature — this page found all 58 with six lines of arithmetic.
Record the fill, not the booking. done Reconciliation stamps entry_time with the moment it noticed a holding, because the broker exposes no purchase date. It now also sets entry_time_estimated — the counterpart of the exit_price_estimated flag this model already carried — so research can tell an observed fill from an adopted one. Not set on the parking sweep, which really does buy in that moment.
Repair the two broken records rather than excluding them. The AVALON round trip marked cancelled and the missing JUNIORBEES history are 97% of the reconciliation gap, and both are recoverable from broker data. Exclusion moves the modeled total by about ₹24,000 and teaches nothing.
Not fixed here, and worth saying: 39 of the 132 trades still have no recorded entry stop, and no backup contains one. That stays unknown. See the correction on the six-month replay.
← Trading book · 2026-09-24_data_quality.py · 24 September 2026