Tipsheet models, v1: pre-registered specification
Written 2026-10-08, before any result for the new rules in section 4 was computed. It follows the proposal in model_library_proposal.md (2026-10-03) and the owner’s decisions of 2026-10-08:
- the reader-facing name is “Tipsheet models”, not “indices”;
- global legs may use overseas index levels for derived results;
- the foreign leg is held the way a resident would hold it today, through the Liberalised Remittance Scheme (LRS).
If a rule changes after its results are seen, the change is logged under Amendments with the date and the reason, and the original result is kept.
What is already known, stated up front. I have already seen the results of every rule in section 3: lab v2’s results log (2026-10-02, corrected 2026-10-03) and the trend and sector logs in trend_momentum_spec.md. Those rules are promoted to the model board unchanged. Their backtests are not new evidence, and their entry dates stay the dates of their original specs.
1. What this adds
- A model board. Each model’s target today, the date of its last change, and how close it is to switching. The same board appears in compact form on the homepage.
- A live record. From each model’s entry date, an append-only log of its daily return and holdings that is never recomputed (section 6).
- New rules (section 4):
- global dual momentum and global GTAA, with the S&P 500 and the Nasdaq-100 in rupees;
- size rotation;
- sector rotation v2 on a de-duplicated sector list;
- the house trend model, local and global (five or six markets, each sized by its trend score), and the trend score as a graded Nifty 50 exposure.
- A “didn’t survive” shelf for retired and failed models, with the reason and the evidence.
Out of scope: stock-level models, leverage, shorting, and anything driven by Fear & Greed or flows (twelve pre-registered versions of the mood index failed, market_mood_spec.md).
2. Three dates per model
Every model carries:
- its source date, when the rule was published;
- its entry date, the commit date of the spec that registered it here;
- its data start.
Charts shade three periods differently:
- before the source date (in-sample for the rule’s author);
- between source and entry (out of sample for the author, but seen by me);
- after the entry date (out of sample for me).
A table gives each model’s return in each period beside the full history. The return after the entry date is the only one that is not a backtest, and it is published that way.
3. Promoted unchanged (already registered and already run)
| Board code | Rule | Spec and code | Source date | Entry date |
|---|---|---|---|---|
n50_sma10m | Nifty 50, 10-month rule | trend_momentum_spec.md, compute/trend.py | Faber 2007 | 2026-10-01 |
n50_sma200d | Nifty 50, 200-day rule | same | Brock et al. 1992 | 2026-10-01 |
n50_blend | Nifty 50, 1/3/6/12-month blend | same | Hurst et al. 2017 | 2026-10-01 |
mid150_sma200d, small250_sma200d | 200-day rule on mid and small caps | same | Brock et al. 1992 | 2026-10-01 |
gtaa | Faber GTAA, domestic: Nifty 500, 5-year G-sec, gold | portfolio_lab_v2_spec.md 5.6, lab/rules.py | Faber 2007 | 2026-10-02 |
dual_momentum | Dual momentum, domestic: Nifty 500 vs gold, else G-sec | same | Antonacci 2012 | 2026-10-02 |
paa, daa, vaa, baa | Keller and Keuning family | same | 2016, 2018, 2017, 2022 | 2026-10-02 |
vol_managed, cppi | Volatility-managed equity; CPPI | same | 2017; 1988 | 2026-10-02 |
valuation_cape, valuation_yield_gap | Valuation glides | same | Campbell and Shiller 1998 | 2026-10-02 |
sixty_forty_trend | 60/40 with a trend filter on equity | same | 2026-10-01 (v1) | 2026-10-02 |
ensemble_equal | Equal blend of the lab’s rules | same | n/a | 2026-10-02 |
| Benchmarks | 60/20/20, 60/40, permanent, equal thirds | same | Bogle 1994; Browne 1987 | 2026-10-02 |
| Retired | Sector momentum v1 (mom12_1, mom6_1) | trend_momentum_spec.md | Jegadeesh and Titman 1993 | 2026-10-01 |
Local twins. The domestic gtaa and dual_momentum are first-class board models, not footnotes. Each global rule in section 4 has a local twin built only from Indian assets: gtaa for gtaa_global, dual_momentum for gem_spx and gem_ndx, and trend_local for trend_global. The board shows each pair side by side (section 5), so a reader who doesn’t use LRS has a model to follow, and every reader can see what the foreign leg added or cost.
4. New rules
All rules here:
- decide at month-end on completed months only, and trade at the next NSE close (lab engine timing);
- are long-only, unlevered, and treat cash as an asset;
- use the lab’s costs, tax engine and evaluators unless stated otherwise.
4.1 Global legs
Assets added to the lab universe:
| Key | Series | Source | First date |
|---|---|---|---|
spx_inr | S&P 500 (price) in rupees | kite_global_index_history US500 to 2016-05-30, then FRED SP500. This is the same splice as compute/world.py; Kite equals the official close on all 2,125 overlapping days. | 2004-01-02 |
ndx_inr | Nasdaq-100 (price) in rupees | nasdaq_giw_index_history NDX (official) | 1990 |
ivv_inr | iShares S&P 500 ETF, total return, in rupees | etf_issuer_nav_history IVV, distributions reinvested (world.total_return_index) | 2000-05-15 |
- Currency: ECB reference rates (
world.ecb_inr_per_unit), as on the world pages. - Calendar and timing: the US close of day t comes after the NSE close of day t. Each foreign series is therefore placed on the NSE calendar lagged one session: its value on NSE day t is the last US close strictly before t, converted at that US date’s ECB rate. A month-end decision never sees a US close the Indian investor could not have seen. Daily returns use the same lag, the way an Indian fund-of-fund’s NAV does.
- Dividends:
spx_inrandndx_inrare price indices, so they miss the dividend yield (about 1.5–2 points a year for the S&P 500, under 1 for the Nasdaq-100). That biases relative momentum and returns against the foreign leg. Every model that usesspx_inris also run onivv_inr, total return with a real fund fee, as a sensitivity. It is reported beside the headline and not counted as a separate trial. - Licence: results, rebased model curves and statistics only. No index level, no rebased curve of a foreign index on its own, and no single-sleeve curve. The licence gate gets an explicit, tested exception for composite model curves under
models/(owner decision, 2026-10-08).
How the foreign sleeve is held (LRS, direct, a US-listed index ETF):
- Running cost: 0.10% a year.
- Trade cost each way: 0.60% (forex markup and remittance charges about 0.5%, plus brokerage). Sensitivity at 0.25% each way for cheaper platforms.
- Tax: new tax class
foreigninlab/tax.py, treated as foreign unlisted securities:- to 2024-07-22: long-term after 36 months at 20% with indexation; short-term at the slab;
- from 2024-07-23: long-term after 24 months at 12.5% without indexation; short-term at the slab.
- Dividends are ignored, consistent with the price-index headline. The
ivv_inrsensitivity notes that a resident pays 25% US withholding and then the slab rate with a credit. - Each rule gets a worked example in
tests/test_lab_tax.pybefore any result is read.
- Not modelled, stated as caveats:
- TCS on remittances (a refundable timing cost);
- the LRS ceiling, which was $50,000–$200,000 a year between 2006 and 2015 and is $250,000 since 2015;
- the 2022 freeze on new money into Indian funds that invest abroad, which does not bind under LRS.
Rules:
| Code | Rule | Source |
|---|---|---|
gem_spx | If Nifty 500’s 12-month total return beats cash’s, hold whichever of n500 and spx_inr has the higher 12-month return. Otherwise hold gsec5. | Antonacci 2012 (GEM); home equity is the absolute-momentum test, as in the original |
gem_ndx | As gem_spx, with ndx_inr as the foreign leg | Same; Nasdaq-100 is the foreign index most Indian investors actually buy |
gtaa_global | Four sleeves of 25%: n500, spx_inr, gsec5, gold. Each sleeve is held when its month-end level is above its 10-month average, otherwise it goes to cash. | Faber 2007. No Indian REIT or broad commodity series is long enough, so gold stands in for commodities and there is no real-estate sleeve |
Static counterparts (for prediction P1):
- 50/50
n500/spx_inrforgem_spx; - 50/50
n500/ndx_inrforgem_ndx; - equal quarters of the four sleeves for
gtaa_global.
All are rebalanced each January, as in the lab.
Window:
- Headline: the lab’s, from 2005-04-01. The first decision has 12 months of warm-up from the 2004-01 start of
spx_inr. - Long window for
gem_ndxand the IVV sensitivity: from 2002-10-01.
4.2 Size rotation
| Code | Rule | Source |
|---|---|---|
size_dm | If Nifty 500’s 12-month total return beats cash’s, hold the one of n50, mid150 and small250 with the highest 12-month return. Otherwise hold gsec5. | Antonacci’s dual momentum, applied to size segments |
- Static counterpart: equal thirds of
n50,mid150andsmall250, rebalanced each January. - Caveat: Midcap 150 and Smallcap 250 are back-calculated before their 2016-04-01 launch. A second window starting at that launch is reported beside the headline.
4.3 Sector rotation, v2
v1 failed. mom12_1 trailed equal weight, 14.5% against 15.5% with a deflated Sharpe of 0.33; mom6_1 led but was not significant (DSR 0.66). v1’s log noted that NSE’s sectoral group contains near-duplicates (Bank, Private Bank and Financial Services), so the top three could be one bet held three times. v2 fixes the universe in advance.
Universe: one index per economic sector, the broadest Nifty version of each. Twelve sectors:
- Financial Services, IT, Healthcare, FMCG, Auto, Metal;
- Oil & Gas, Consumer Durables, Realty, Media, Chemicals, Cement.
Dropped as sub-sets or variants of a kept sector:
- Bank, Private Bank, PSU Bank, Financial Services 25/50, Financial Services Ex-Bank, MidSmall Financial Services;
- Pharma, Nifty500 Healthcare, MidSmall Healthcare;
- MidSmall IT & Telecom;
- REITs & Realty.
The list is fixed here. A sector NSE adds later joins only by amendment.
Rules:
| Code | Rule |
|---|---|
sec_mom_v2 | At each month-end, rank eligible sectors by total return over months t−12 to t−1. Hold the top 3 equally for the next month. This is v1’s rule on the new universe. |
sec_dm_v2 | As sec_mom_v2, but a top-3 slot goes to cash when that sector’s t−12 to t−1 return is below cash’s over the same months (absolute momentum per slot) |
Two universes per rule, both counted as trials:
- As published: a sector is eligible once it has 13 months of NSE’s history.
- Live only: a sector is eligible once it has 13 months of history after its launch date (
compute/trend_launch_dates.csv), and the rule runs only from the first month with at least six eligible sectors (about 2011-09 on the frozen launch dates). IT, whose launch parses as unknown, counts from its first value.
Benchmarks: equal weight over the same eligible universe with the same costs, and Nifty 500.
Costs: sector index funds and ETFs at the lab’s factor cost class. Taxed as equity.
Rotation view (not a test): /models/ also gets a descriptive sector rotation chart: each sector’s 6-month return relative to Nifty 500 against its 1-month change, with a 12-week tail. It carries no claim and is labelled as a description.
4.4 Trend models: the flagship and the single-market version
The trend family’s headline is a multi-asset trend model, the house trend model. It is the classic diversified trend-following design (Hurst, Ooi and Pedersen 2017, long-only): many markets, each sized by its own trend, with what isn’t invested held in cash. Single-market rules such as n50_sma10m stay on the board as the simple reference.
All three rules use the pre-registered trend score of trend_barometer_spec.md: 24 votes on the market’s level over cash, as a share from 0 to 100.
| Code | Rule | Source |
|---|---|---|
trend_local | Five equal sleeves of 20%: n50, mid150, small250, gold, gsec5. Each sleeve’s exposure is its trend score ÷ 100, and the rest of the sleeve is in cash. Decided weekly at each week’s last session. | Hurst, Ooi and Pedersen 2017 (long-only); score from trend_barometer_spec.md |
trend_global | As trend_local with a sixth sleeve, spx_inr; six equal sleeves of 1/6 | Same |
n50_trend_score | Nifty 50 alone: exposure = its trend score ÷ 100, the rest in cash, decided weekly | Same |
-
What the board shows for these: each sleeve’s state in words (fully invested, partly invested with the share, or in cash), and the model’s total exposure. “In cash since” is dated for each sleeve.
-
Static counterparts:
- equal fifths of the five sleeves for
trend_local; - equal sixths for
trend_global; - buy-and-hold Nifty 50 for
n50_trend_score.
All rebalanced each January.
- equal fifths of the five sleeves for
-
Window: from 2006-04, when
mid150andsmall250have the 252 sessions the score needs. Back-calculated before 2016-04, with a second window from that launch, as in 4.2. -
Engine: these need the lab engine to accept weekly decision dates (build item 3). A sleeve rebalances only when its target moves by 5 points or more, so drift and tiny score changes don’t become trades. The band is fixed here and is not tuned.
-
History: the trend section already replays the score on single markets but has never tested it. Registering these rules makes them counted trials with entry dates.
5. What is reported
For every model in sections 3 and 4:
- the lab’s full evaluation (
portfolio_lab_v2_spec.mdsection 9): CAGR before and after tax, real after-tax CAGR, risk, drawdown anatomy, rolling windows, turnover, cost and tax drag; - returns before the source date, between the source and entry dates, and after the entry date;
- a timing-luck spread: each monthly rule is rerun on each of 21 trading-day offsets within the month, with the headline unchanged and the minimum-to-maximum range beside it;
- the deflated Sharpe ratio against cash and against its static counterpart.
Trial count for the deflated Sharpe:
- 136 lab portfolios, 35 trend trials and 2 sector v1 trials, all already run;
- plus the new trials here:
gem_spx,gem_ndx,gtaa_global,size_dm,trend_local,trend_global,n50_trend_score, and two sector rules × two universes; - 184 in total.
The board:
- Per model: the target held today; the date of its last change; the provisional target if the month ended today, with how far each comparison is from flipping (in return points, or percent from the average); and the return since its entry date.
- A “may change at this month-end” flag on the last three sessions of a month.
- The aggregate row: the average equity share across all board models, Indian and foreign equity counted together.
- The board is descriptive. Each row links to the model’s page, where the verdict (deflated Sharpe, and the after-tax gap to its static counterpart) sits beside the backtest.
Homepage: the aggregate equity share and a compact board with one row per model family. A family that has a local and a global version shows both in two columns, “India only” and “With global”:
| Row | India only | With global |
|---|---|---|
| Trend | trend_local | trend_global |
| Nifty 50 trend | n50_sma10m | n/a |
| GTAA | gtaa | gtaa_global |
| Dual momentum | dual_momentum | gem_spx |
| Size rotation | size_dm | n/a |
| Sector rotation | sec_dm_v2 (live-only universe) | n/a |
| Valuation glide | valuation_cape | n/a |
| Benchmark | 60/20/20 | n/a |
The homepage shows no backtest curve.
6. The live record
- Log: from each model’s entry date, the pipeline appends one row per model per session: date, target weights, held weights, the day’s return after costs and before tax, and a SHA-256 of the previous row. The log is append-only, and the hash chain makes any rewrite visible. It lives in R2 beside the bundles and is mirrored monthly into the repo under
data/models_live/. - Repairs: the log is never recomputed. When a data repair changes the backtest, the page shows the gap between the live log and the recomputed backtest for the same dates.
- Missing days: if a refresh fails, the missing sessions are filled on the next run from data as it stood then, and flagged
late. - Reviews: a written review of the live record every October, starting 2027-10. A model whose after-tax live record trails its static counterpart by more than its backtest’s 90% interval over 36 months moves to the “didn’t survive” shelf with that evidence.
7. Predictions (graded in the results log)
- P1. No new rule in section 4 beats its static counterpart after tax with a pre-tax bootstrap interval above zero. This is the lab’s P1, which held for every domestic tactical rule.
- P2. The static 50/50 Nifty 500/S&P 500 mix has lower volatility and a shallower maximum drawdown than Nifty 500 alone over the headline window.
- P3. Neither sector v2 rule reaches a deflated Sharpe of 0.5 against its equal-weight benchmark in either universe.
- P4. The live-only sector universe gives a lower excess return over equal weight than the as-published universe for both rules. I expect back-calculated history to flatter rotation.
- P5.
gem_spxswitches between India and the US at least as often as the domesticdual_momentumswitches between Nifty 500 and gold, and pays more cost drag because of the LRS trade cost. - P6.
trend_localhas a shallower maximum drawdown than its static counterpart (equal fifths), but trails it after tax. This is the pattern every single-market trend rule showed intrend_momentum_spec.md. - P7. For each global model and its local twin, the 90% pre-tax bootstrap interval of the difference in annualised return contains zero. I expect the foreign leg to change the path (drawdowns, time in cash) more than the end result.
8. Known limits
- One rupee-depreciation sample. The rupee fell from about 44 to about 88 per dollar over the window, which flatters every foreign leg measured in rupees.
- The foreign legs are price indices in the headline (section 4.1, dividends).
- Kite’s US500 before 2016 is a quote feed, not an official series; the overlap check covers 2,125 days, not the years before 2016.
- LRS costs vary widely by platform; 0.60% each way is a middle estimate.
- Sector and size histories are mostly back-calculated before 2011–2020; the live-only runs show the cost of that.
- Around 21 years and three or four equity cycles: differences between sensible models will rarely be significant.
9. Build list
lab/universe.py:spx_inr,ndx_inrandivv_inrwith the one-session lag; cost classlrs; tax classforeign. Test that a month-end decision never reads a US close dated on or after the NSE decision date.lab/tax.py: theforeignclass with worked examples.lab/rules.py: generalise_dual_momentum(home, contenders, absolute test, fallback as parameters) forgem_*andsize_dm; a cross-sectional sector kind forsec_*_v2; weekly decision dates and the 5-point band fortrend_local,trend_globalandn50_trend_score, with the look-ahead scramble test extended to them.models/registry.yaml: one entry per board model, with its code, its lab or trend rule, its three dates, its static counterpart and its shelf status.- The live log (section 6), with a test that a rewritten past row fails the chain check.
- Bundles
models/board,models/aggregateandmodels/<code>; the licence-gate exception, with tests. - Site:
/models/(board, aggregate, rotation view, shelf),/models/<code>/, and the homepage board. Today/models/redirects to/trend/evidence/; it becomes the board, with links to the evidence pages. - Docs:
docs/methods/models.md,docs/STATUS.md, and a results log entry here.
Amendments
2026-10-08, before any result was computed (found while wiring the rules to the engine and the data):
-
Foreign tax holding periods (4.1). US-listed ETF units held through LRS are shares not listed in India, not fund units. So the long-term threshold follows the date of sale:
- 12 months for sales to 2014-07-10;
- 36 months to 2016-03-31 (Finance (No. 2) Act 2014);
- 24 months from 2016-04-01 (Finance Act 2016).
The rates are as written: 20% after indexation, then 12.5% without it from 2024-07-23. The draft’s “36 months to 2024-07-22” was the debt-fund rule. Worked examples are in
tests/test_lab_tax.py. -
Windows. Each model starts at the first session after its first decision, and never before 2005-04-01. Its counterpart runs over the same dates. The spec’s single headline window can’t hold every model: size rotation and the trend models need Midcap 150 and Smallcap 250 history, which start in 2005-04.
-
The band (4.4). “A sleeve trades only when it moves 5 points” is implemented as: at each weekly decision, the whole model rebalances only if some asset’s weight is more than 5 points off its new target (lab engine policy
decision_bands). -
The live log (6) lives in the pipeline’s derived cache, which the cloud refresh keeps in R2, and is published in full as the
models/livebundle. The published bundle is the public copy, so there is no monthly repo mirror; the cloud run can’t commit to the repo. -
Promoted trend rules (3) run on the lab engine with the lab’s cost schedule, like every other model. The rules themselves are unchanged. Their numbers can differ slightly from
/trend/evidence/, which uses the trend spec’s flat costs. -
Sector live-only start (4.3). On the frozen launch dates, the sixth eligible sector arrives at the 2012-07 month-end, not “about 2011-09”.
-
Deflated Sharpe variance. The cross-sectional variance of Sharpe ratios is taken across the board’s own models (the 184-trial count is unchanged). The earlier trials’ Sharpe ratios live in other tables, with other windows.
-
Timing luck (5) covers the monthly rules other than the valuation glides. A glide reads a monthly external signal that cannot be shifted with the prices. Offsets relabel sessions so that each “month” ends k sessions before the true month-end, k = 0 to 20.
2026-10-08, after the first results (presentation only; no rule, window or test changed):
- Tipsheet indices. Eleven board models are also published as index levels: total return, base 1,000, before any cost or tax. The method is in
docs/methods/tipsheet_indices.md. Each launch date is the model’s entry date. After launch, levels chain the gross returns written to the live log, which now records each index model’s gross return beside its after-cost return. Because results had been seen, the eleven are chosen by a fixed rule: the models on the homepage board plus its benchmark, never by performance. No model was added to or removed from the board after the results. - Wording. “Static counterpart” and “fixed mix” read as “benchmark” on the site: the same assets held in fixed shares, named on each model’s page.
2026-10-08, after the first results, before any result for the rules below was computed (owner’s review):
-
Nifty 100 and Nifty 500 versions, and factor rotation.
- Why the change: the board treats the Nifty 500 as the market everywhere else (GTAA, dual momentum, the market rows). Its large-cap sleeves used the Nifty 50, which overlaps nothing and covers less. The Nifty 100, Midcap 150 and Smallcap 250 together make up exactly the Nifty 500, with no overlap.
- New rules (entry 2026-10-08), each counted as a trial:
trend_indiaandtrend_world:trend_localandtrend_globalwith the Nifty 100 in place of the Nifty 50;size_rotation:size_dmwith the Nifty 100 in place of the Nifty 50;n500_sma10m: the 10-month rule on the Nifty 500;factor_dmandfactor_dm_live: at each month-end, hold equally the top two of four factor indices (Nifty200 Momentum 30, Nifty200 Quality 30, Nifty500 Value 50, Nifty100 Low Volatility 30), ranked by return over months t−12 to t−1. A slot goes to cash when its factor’s return is below cash’s.factor_dmuses NSE’s history.factor_dm_livecounts each factor only from 13 months after its launch and runs from the first month with three. Benchmark: equal weight across the same eligible factors, monthly. Sources: Gupta and Kelly (2019) on factor momentum; the absolute filter as in 4.3.
- The board and the indices move to the new versions, and Tipsheet Factor Rotation (
factor_dm_live) joins the index family. - The first versions (
trend_local,trend_global,size_dm,n50_sma10m) stay listed with their records and entry dates. They are not deleted or rewritten. - Trial count: 190.
-
Prediction P8 (for the rules in 11).
- Neither factor rotation rule beats its equal-weight benchmark with a pre-tax 90% range above zero.
- The Nifty 100 versions’ after-tax gaps to their benchmarks are within 1 point a year of the Nifty 50 versions’ gaps. The change is structural, and I expect it to change little.
-
Which version is on the board and in the index family (owner decision, 2026-10-08, after results).
- Sector and factor rotation: the board and the indices use the versions on NSE’s full history (
sec_dm_v2,factor_dm). The launch-counted versions (sec_dm_v2_live,factor_dm_live) stay listed as models. - Why: every index then follows one policy. NSE’s histories are used in full, and back-calculated years are marked, as the trend and size indices already did with Midcap 150 and Smallcap 250.
- This changes which version is shown, not any rule or result. The launch-counted version of sector rotation did better on its shorter window (−1.98 against −3.06 points after tax); of factor rotation, worse (−6.05 against −4.55).
- Sector and factor rotation: the board and the indices use the versions on NSE’s full history (
-
Allocation styles and Tipsheet Dynamic Allocation (owner’s request, 2026-10-08, before any result for the new rule was computed).
- Allocation styles join the board as models, with no new trials: the portfolio lab’s risk parity (equal risk contribution), minimum variance, inverse volatility, hierarchical risk parity, maximum diversification, All Weather (India), golden butterfly and endowment-style portfolios. They are the lab’s rules and results, unchanged (entry 2026-10-02). The fixed mixes among them have no benchmark of their own; the risk-based ones keep the lab’s (equal weight of their assets).
- New rule
dyn_alloc(entry 2026-10-08, one trial; total 191). At each month-end:- valuation half: the Nifty 500 P/E (consolidated basis,
valuation_nifty_500, same-day) is ranked against every month-end since 1999 up to that date, with at least 60 needed. It maps to an equity share of 80% at or below the 20th percentile, falling linearly to 20% at or above the 80th; - trend half: the Nifty 500’s trend score (24 votes on its level over cash) maps to 20% equity at 0, rising linearly to 80% at 100;
- equity: Nifty 500, at the average of the two halves; the rest in the 5-year G-sec. It trades at the next close, only when a weight is more than 5 points off target.
- Benchmark: 50% Nifty 500 + 50% 5-year G-sec, rebalanced each January.
- Sources: valuation-based allocation as in balanced advantage funds and NSE’s Nifty50 and Short Duration Debt – Dynamic P/E index; trend as in 4.4.
- valuation half: the Nifty 500 P/E (consolidated basis,
- Index family: Tipsheet Dynamic Allocation replaces Tipsheet Valuation Glide, whose CAPE input is a reference file that is not refreshed daily. The family stays at twelve. The valuation glides stay as models.
- P9:
dyn_allocdoes not beat its benchmark after tax with a pre-tax 90% range above zero, and its worst fall is shallower than the benchmark’s.
Results log
2026-10-08: first run (data to 2026-10-06; rules as specified and amended above)
These ran exactly as registered and amended, with no parameter changed after results were seen. Code: pipeline/tipsheet/models/run.py. Tables: .cache/derived/models_*. Bundles: models/*.
The models from the lab reproduce lab v2’s published figures:
- GTAA: 10.88% before tax, 9.78% after;
- dual momentum: 13.39% and 11.97%;
- 60/40: 11.92% and 11.44%.
The new rules against their fixed mixes. Returns are a year after costs; the 90% range is on the gap before tax.
| Model | From | Before tax | After tax | Fixed mix, after tax | Gap after tax (pts) | 90% range (pts) | Worst fall | Fixed mix’s worst fall |
|---|---|---|---|---|---|---|---|---|
| Trend, India only | 2006-04 | 11.45 | 9.40 | 13.01 | −3.61 | −4.66 to +0.26 | −17.6 | −38.1 |
| Trend, with global | 2006-04 | 10.74 | 8.53 | 13.16 | −4.62 | −5.39 to −0.66 | −16.1 | −36.4 |
| Nifty 50 graded by trend score | 2005-04 | 10.67 | 9.18 | 12.18 | −3.00 | −5.75 to +2.24 | −25.0 | −59.9 |
| GTAA with global | 2005-04 | 11.02 | 9.57 | 12.51 | −2.94 | −3.47 to −0.87 | −14.8 | −19.2 |
| Dual momentum, S&P 500 | 2005-04 | 11.94 | 9.91 | 13.44 | −3.53 | −6.81 to +2.65 | −45.1 | −51.2 |
| Dual momentum, Nasdaq-100 | 2005-04 | 10.98 | 8.50 | 16.24 | −7.74 | −11.45 to −0.45 | −45.1 | −49.4 |
| Size rotation | 2006-05 | 9.69 | 8.66 | 11.73 | −3.06 | −8.61 to +3.59 | −49.1 | −69.6 |
| Sectors, top 3 (NSE history) | 2005-04 | 12.47 | 11.13 | 13.35 | −2.21 | −5.74 to +2.58 | −66.0 | −66.5 |
| Sectors, top 3 with cash filter (NSE history) | 2005-04 | 11.56 | 10.29 | 13.35 | −3.06 | −7.57 to +2.47 | −54.4 | −66.5 |
| Sectors, top 3 (from launch) | 2012-08 | 13.88 | 12.17 | 11.75 | +0.42 | −2.39 to +5.37 | −38.6 | −45.3 |
| Sectors, top 3 with cash filter (from launch) | 2012-08 | 11.16 | 9.76 | 11.75 | −1.98 | −6.48 to +3.72 | −37.4 | −45.3 |
Deflated Sharpe ratios against the fixed mix, 184 trials: all between 0.00 and 0.13.
Sensitivities:
- S&P 500 dividends (iShares IVV, total return): after-tax returns rise by 0.05 to 0.27 points (
gem_spx9.96%,gtaa_global9.84%,trend_global8.77%). - LRS costs of 0.25% each way:
gem_spxrises to 10.68% after tax.
Timing luck. Deciding 0 to 20 sessions before the month-end moved before-tax returns widely:
- Nifty 50 10-month rule: 8.7% to 13.4%;
- DAA: 13.3% to 18.9%;
- VAA: 8.7% to 16.0%.
Predictions:
- P1 holds. No new rule beat its fixed mix with a pre-tax range above zero. Three were worse with ranges below zero: Trend with global, GTAA with global, and dual momentum with the Nasdaq-100. Only the live-universe top-3 sector rule finished ahead after tax (+0.42 points), well inside its range.
- P2 holds. The 50/50 Nifty 500 / S&P 500 mix had volatility of 14.6% and a worst fall of −51.2%, against 21.8% and −64.1% for Nifty 500 alone (lab v2, same start).
- P3 holds. The four sector rules’ deflated Sharpe ratios are 0.00, 0.00, 0.13 and 0.01.
- P4 fails. Counting sectors only from launch gave a better gap to equal weight for both rules: +0.42 against −2.21 points, and −1.98 against −3.06. The two universes cover different years (from 2012-08 against from 2005-04), so this does not show that back-calculated history flatters rotation, or that it doesn’t.
- P5 holds, graded on turnover: 2.75 a year for
gem_spxagainst 1.66 for the domesticdual_momentum, and tax drag of 2.04 against 1.42 points. Cost drag was not tabulated separately. Cutting LRS costs to 0.25% each way adds 0.77 points a year after tax. - P6 holds.
trend_localfell at most 17.6% against 38.1% for equal fifths, and trailed it after tax by 3.61 points a year. - P7 holds. The 90% ranges of the pre-tax gap between each global model and its India-only twin all include zero:
gem_spxagainstdual_momentum: −8.0 to +4.6 points;gem_ndxagainstdual_momentum: −9.0 to +3.6;gtaa_globalagainstgtaa: −1.1 to +1.3;trend_globalagainsttrend_local: −1.5 to +0.0.
What the record says. Every rule in this batch cut drawdowns, the trend models by half. Every rule but one paid for it with a lower after-tax return than simply holding its assets in fixed proportions. The foreign leg added nothing to any rule. The fixed 50/50 mixes with the S&P 500 or the Nasdaq-100 were among the best performers in the batch: 13.4% and 16.2% after tax over a window in which the rupee fell from about 44 to about 88 to the dollar. That is a statement about a fixed allocation abroad in this one sample, not about switching into it.
2026-10-08: the rules of amendment 11 (data to 2026-10-06)
Returns are after costs. “Gap” is the gap to the benchmark after tax. The range is the 90% range of the gap before tax.
| Model | From | After tax | Benchmark after tax | Gap (pts) | 90% range (pts) | Worst fall | Benchmark’s worst fall |
|---|---|---|---|---|---|---|---|
| Trend, India only (Nifty 100) | 2006-04 | 9.53 | 13.10 | −3.57 | −4.63 to +0.38 | −17.6 | −38.5 |
| Trend, with global (Nifty 100) | 2006-04 | 8.56 | 13.24 | −4.68 | −5.41 to −0.72 | −16.1 | −36.8 |
| Nifty 500, 10-month rule | 2005-04 | 11.28 | 12.67 | −1.39 | −5.81 to +4.14 | −33.9 | −64.2 |
| Size rotation (Nifty 100) | 2006-05 | 8.60 | 11.80 | −3.20 | −9.07 to +3.54 | −49.1 | −70.2 |
| Factor rotation (NSE history) | 2006-05 | 9.00 | 13.56 | −4.55 | −9.57 to +0.30 | −51.5 | −59.8 |
| Factor rotation (from launch) | 2019-11 | 7.55 | 13.59 | −6.05 | −14.33 to +0.72 | −29.1 | −34.2 |
Deflated Sharpe ratios against the benchmarks, 190 trials: all 0.00.
P8 holds on both counts:
- Neither factor rule’s range lies above zero.
- The Nifty 100 versions’ gaps are within 0.15 points of the Nifty 50 versions’ (−3.57 against −3.61; −4.68 against −4.62; −3.20 against −3.06).
2026-10-08: the rule of amendment 14 (data to 2026-10-06)
dyn_alloc, from 2005-04:
- Returns a year: 11.08% before tax and 10.13% after, against 10.85% after tax for 50/50 Nifty 500 / G-sec. The gap is −0.72 points, with a 90% range of −0.93 to +0.42.
- Worst fall: −32.4%, against −29.5% for the benchmark.
- Other statistics: average equity share 43%; turnover 0.52 a year; deflated Sharpe 0.00 (191 trials).
For comparison, the CAPE glide it replaces in the index family returned 10.15% after tax, with a worst fall of −15.7%.
P9 is half held:
-
Held: the range includes zero.
-
Failed: its worst fall was deeper than the benchmark’s, not shallower. Its month-end weights show why:
- it held 53–57% equity into the January 2008 peak;
- it cut to about 30% in early 2008;
- it went back to about 50% by mid-2008, as falling P/Es lifted the valuation half, ahead of the September–November crash.
The CAPE glide sat near 20% throughout.