Backtest · simulated history
Zen v1 backtest
SimulatedSimulated performance of the strategy's rules from Fri 15 Feb 2019 to Fri 18 Sep 2026, on a survivorship-free universe of NSE-listed companies using only information public at each date.
Live performance is tracked separately from Mon 5 Oct 2026 under Live.
Reading these results
- The first run of the held-back test (22 Sep 2026) gave 29.4% a year; the current figure comes from a re-run after two data faults were fixed, with no stock-picking rule changed.
- Most of the return is the market and two well-known factors.
- What is left after the factors is not statistically significant: four-factor alpha t-statistic 1.21, p-value 0.23.
- A backtest is simulated: it assumes fills at the open with a flat 0.20% cost per side and fractional shares, on Rs 5,00,000. The live portfolios use whole shares, itemised charges and 0.1% slippage on Rs 50,00,000.
CAGR (strategy)
30.68%
CAGR (same universe, equal weight)
22.03%
CAGR (Nifty 500 TRI)
14.36%
Sharpe ratio (zero risk-free)
1.39
Maximum drawdown
−33.56%
Final multiple
7.62x
Held-back years, CAGR
34.31%
Growth of 100 (simulated)
Every series rebased to 100 at its first mark in the range. The shaded span from 15 Feb 2023 is the held-back period: rules fixed before this date; later years were held back. Clock: open of the first decision date, every close, open of the end date.
The interactive chart needs the charting library; the same figures are in the table below.
Sensitivity series (no overnight move where NSE printed no open) are off by default.
Drawdown
Decline of the simulated value from its running peak
The interactive chart needs the charting library; the same figures are in the table below.
- Maximum: Zen v1 (simulated)
- −33.56%
- Maximum: Same universe, equal weight
- −47.90%
- Maximum: Nifty 500 (TR official)
- −38.11%
Calendar-year returns
return per calendar year from the last mark of the previous year (or the start); the last year is partial
The interactive chart needs the charting library; the same figures are in the table below.
| Year | Zen v1 (simulated) | Same universe, equal weight | Nifty 500 (TR official) | Nifty Midcap 150 (TR official) | Nifty Smallcap 250 (TR official) |
|---|---|---|---|---|---|
| 2026 | −3.28% | +8.74% | −4.13% | +2.04% | +8.63% |
| 2025 | +24.29% | −11.29% | +7.76% | +5.98% | −5.48% |
| 2024 | +33.94% | +28.74% | +16.24% | +24.46% | +27.21% |
| 2023 | +74.82% | +53.20% | +26.91% | +44.61% | +49.09% |
| 2022 | −2.52% | +6.19% | +4.25% | +3.91% | −2.64% |
| 2021 | +95.36% | +74.01% | +31.60% | +48.16% | +63.34% |
| 2020 | +28.30% | +32.74% | +17.89% | +25.56% | +26.46% |
| 2019 | +10.78% | −2.90% | +12.31% | +8.57% | +2.77% |
Rolling 12-month return
The return over the year to each date. It shows how steady the result was, not just where it ended. The strategy was ahead of the Nifty 500 over the trailing year 84.08% of the time.
The interactive chart needs the charting library; the same figures are in the table below.
Worst drawdowns
The five deepest falls from a previous high, how long each took to reach bottom and how long it took to get back.
| Peak | Trough | Recovered | Depth | Fall | Recovery |
|---|---|---|---|---|---|
| 27 Jan 2020 | 24 Mar 2020 | 5 Nov 2020 | −33.56% | 57 days | 226 days |
| 11 Apr 2022 | 20 Jun 2022 | 17 Jul 2023 | −30.71% | 70 days | 392 days |
| 16 Sep 2024 | 28 Feb 2025 | 4 Sep 2025 | −23.78% | 165 days | 188 days |
| 12 Feb 2026 | 30 Mar 2026 | Not yet | −16.47% | 46 days | — |
| 8 Nov 2021 | 20 Dec 2021 | 13 Jan 2022 | −12.44% | 42 days | 24 days |
Calendar days, from the strategy's simulated value at each mark.
How long a record has to be
A Sharpe ratio from a few years of data is an estimate, and fat tails make it less certain. These figures follow Bailey and López de Prado’s 2012 paper on the Sharpe ratio and allow for the skew and kurtosis of the daily returns.
| Whole period | Held-back years | |
|---|---|---|
| Sharpe ratio | 1.39 | 1.73 |
| Nifty 500 (TR official) Sharpe ratio | 0.88 | 1.01 |
| Skew of daily returns | −0.89 | −0.69 |
| Excess kurtosis | 6.04 | 3.53 |
| Probability the true Sharpe is above zero | Above 99.9% | 99.9% |
| Probability it is above the index's | 90.8% | 90.2% |
| Years of record needed to show a positive Sharpe | 1.5 years | 1.0 years |
| Years needed to show it beats the index | 11.4 years | 5.7 years |
Both at 95% confidence, from daily returns with a zero risk-free rate. The record needed is how long a live portfolio with the same Sharpe ratio and return shape would have to run before it proves the point. It is the reason I judge the live record over years, not months. The whole period includes the years the rules were designed on, so the held-back column is the fairer read, and neither column allows for the number of ideas tested along the way, which the deflated Sharpe ratio in the held-back panel does. The index’s Sharpe ratio is treated as known.
Statistics
20| Statistic | Value | Definition |
|---|---|---|
| CAGR (strategy) | 30.68% | calendar-day CAGR over the full clock |
| CAGR (same universe, equal weight) | 22.03% | calendar-day CAGR over the full clock |
| CAGR (Nifty 500 TRI) | 14.36% | Nifty 500 TRI, calendar-day CAGR on the run's clock |
| Volatility (annualised) | 21.28% | std of returns between marks x sqrt(252) |
| Sharpe ratio (zero risk-free) | 1.39 | mean / std x sqrt(252), zero risk-free rate |
| Sortino ratio | 1.94 | quantstats qs.stats.sortino(returns, periods=252): mean return over the root mean square of the negative returns taken over all periods, times sqrt(252), zero risk-free rate |
| Calmar ratio | 0.94 | quantstats qs.stats.calmar(returns): quantstats' CAGR (compounded return over len(returns)/252 years) over the absolute maximum drawdown |
| Maximum drawdown | −33.56% | worst fall from a running peak |
| Final multiple | 7.62x | NAV at the end / NAV at the start |
| Turnover (one-way, incl. initial build) | 1.96x a year | annual one-way turnover including the initial build: the value of every buy and sell / 2 / mean NAV over all marks / calendar years |
| Average holding period | 181 days | mean calendar days per holding episode |
| Holding episodes | 153 | holding episodes |
| Beta to Nifty 500 TRI | 0.89 | beta of daily returns to Nifty 500 TRI |
| Up capture | 129.79% | |
| Down capture | 65.93% | |
| Best day | 6.73% | |
| Worst day | −10.90% | |
| VaR 95% (daily) | −2.02% | |
| CVaR 95% (daily) | −3.33% | |
| Rolling 12 months ahead of Nifty 500 TRI (share of time) | 84.08% |
Held-back test
15 Feb 2023 to 18 Sep 2026: years the rules were not designed on.
- Strategy CAGR
- 34.31%
- Same universe, equal weight
- 20.96%
- Nifty 500 TRI
- 13.50%
- In-sample: Strategy CAGR
- 27.50%
- In-sample: Same universe, equal weight
- 23.00%
Margin over the same universe equally weighted, held-back years: +13.35% a year, 90% interval −2.68% to +29.23%; 8.4% of resamples at or below zero. stationary bootstrap of paired daily returns, mean block 21 sessions, 5000 draws, statistic = difference in compound annual growth
Whole period, margin over the same universe: +8.88 pp, 90% interval −3.54 pp to +20.74 pp (block 21, 5,000 resamples, share at or below zero 0.1148).
Deflated Sharpe: Sharpe 1.39 over 1,872 observations and 195 trials; probability of genuine skill 0.84, 1.00 or 0.94 under three assumptions. probability of genuine skill after the search; the spread between these is the honest answer, not any single one
Against each index
Whole period, total return indices.
| Index | Index CAGR | Excess | Information ratio |
|---|---|---|---|
| Nifty 500 | +14.36% | +16.32 pp | 0.97 |
| Nifty Midcap 150 | +20.38% | +10.30 pp | 0.66 |
| Nifty Smallcap 250 | +20.14% | +10.54 pp | 0.65 |
| Nifty200 Momentum 30 | +15.62% | +15.06 pp | 0.86 |
| Nifty500 Value 50 | +22.97% | +7.70 pp | 0.38 |
| Nifty200 Quality 30 | +11.91% | +18.77 pp | 1.01 |
| Nifty100 Low Volatility 30 | +13.31% | +17.37 pp | 0.96 |
| Nifty Alpha 50 | +23.48% | +7.20 pp | 0.38 |
| Nifty200 Momentum 30 (sensitivity: no overnight move) | +15.66% | +15.02 pp | 0.85 |
| Nifty500 Value 50 (sensitivity: no overnight move) | +23.01% | +7.67 pp | 0.38 |
| Nifty200 Quality 30 (sensitivity: no overnight move) | +11.91% | +18.77 pp | 1.01 |
| Nifty100 Low Volatility 30 (sensitivity: no overnight move) | +13.31% | +17.37 pp | 0.96 |
| Nifty Alpha 50 (sensitivity: no overnight move) | +23.48% | +7.20 pp | 0.38 |
Random-portfolio test
500 random portfolios from the same universe through the same engine and rules: 'persistent' keeps one random ranking for the whole run, 'fresh' draws a new one each quarter
Strategy: 30.68% a year
One random ranking kept for the whole run
- Percentile
- 96th
- Random at or above
- 20 of 500
- Median random
- 20.66%
- 5th to 95th
- 11.46% to 29.94%
- Best random
- 40.51%
- Median turnover
- 0.50x
A new random ranking at each rebalance
- Percentile
- 98.6th
- Random at or above
- 7 of 500
- Median random
- 19.30%
- 5th to 95th
- 10.77% to 28.35%
- Best random
- 45.83%
- Median turnover
- 3.95x
Factor attribution
IIMA four-factor (market, size SMB, value HML, momentum WML), monthly, Mar 2019 to Dec 2025. statsmodels OLS, HAC (Newey-West, Bartlett) with 3 lags; alpha annualised as (1 + monthly alpha)^12 - 1
- Alpha (annualised)
- +5.74%
- Alpha t-statistic
- 1.21
- Alpha p-value
- 0.23
- R squared
- 0.72
- Months
- 82
Loadings
- Market0.865t 9.70
- Size (small minus big)0.227t 1.69
- Value (high minus low)0.467t 4.78
- Momentum (winners minus losers)0.341t 3.61
After costs and tax
After itemised Indian costs, slippage and capital gains tax on every lot, against a Nifty 500 index fund held throughout.
- Strategy CAGR after costs and tax
- 25.81%
- Nifty 500 index fund (growth option) CAGR after tax
- 13.08%
- Strategy minus the index fund
- +12.73 pp
- Information ratio against the index fund
- 0.85
- Strategy maximum drawdown after tax
- −31.67%
- Starting capital
- Rs 5,00,000
- End value before tax
- Rs 38,09,312
- End value after tax, if everything were sold
- Rs 28,56,676
- Tax paid during the run
- Rs 4,57,950
- Itemised trading costs
- Rs 1,02,764
Figures from the committed backtest run in the research repository (version 8589efd).