Objective
Add Max Sharpe — Rolling Lookback and Max Sortino — Rolling Lookback variants that otherwise match the existing expanding/full-history continuous meta strategies, isolating lookback methodology as the principal variable, with research-driven window selection and adjacent publication on Meta Strategies.
Approach
Implemented bounded rolling lookback via Optimizer3MetaConfig.lookback_months and bounded_pre_signal_history (strictly before each January signal, tail(L) after cutoff; expanding when None/0) in research/optimizer3_meta.py, and ASMetaMaxSharpeRolling / ASMetaMaxSortinoRolling in backtest/meta_strategy.py preserving caps (0.20), floor (0.05), frequency gates, anti-overfit tilt, one-bar next_close lag, and sparse January rebalances. Created StrategySpec at research/findings/specs/meta-rolling-lookback-qm-6djl.json and froze candidate set 12/18/24/36/48/60 plus 84/120 longer candidates with trial ledger before evaluation. Evaluated windows on common 1996-2026 annual walk-forward (net 10bps, 2x stress, extra-lag, 5 regime slices, native/proxy, universe point-in-time) via research/weighted_meta_window_experiment harness; 12/18 flagged sparse-sample instability and insufficient_history, 36 formed a broad plateau with 48 (Sharpe 1.81/1.79, Sortino 3.74/3.71) beating expanding (1.77/3.61) net of costs across untouched 2000-2026, WF average, and regimes, with neighbor sensitivity and allocation-stability (cosine 0.87) checks. Selected common 36m for both objectives after documenting insufficient evidence for differing L (Sortino 48 vs 36 delta -0.03) per robustness-over-optimum principle. Validated via G0-G13 evidence manifests (both promote) and published via canonical research/reports/meta_export and research/reports build --render.
Files changed
research/optimizer3_meta.py— addedlookback_monthstoOptimizer3MetaConfig,bounded_pre_signal_history(), and bounded usage in_prepare_signal_panel/run_objective_walk_forwardbacktest/meta_strategy.py— addedASMetaMaxSharpeRollingandASMetaMaxSortinoRolling(lookback isolation, same caps/floors/tilts/lag)research/findings/specs/meta-rolling-lookback-qm-6djl.json— machine-readable StrategySpec for rolling variants (validated)research/findings/meta-rolling-trial-ledger-qm-6djl.json— frozen trial ledger (16 rolling candidates + 2 expanding baselines)research/strategy_evidence/meta-rolling-max-sharpe-qm-6djl.jsonandresearch/strategy_evidence/meta-rolling-max-sortino-qm-6djl.json— G0-G13 promote manifests (validated)docs/meta-strategies.html— adjacent rolling 36m rows (36m badge prominent) and note linking todocs/experiments/qm-6djl.htmldocs/meta-strategies/meta-max-sharpe-rolling-36m.htmlanddocs/meta-strategies/meta-max-sortino-rolling-36m.html— dedicated rolling variant pages (adjacent, lookback prominent)docs/site-data/meta-strategies/meta-max-sharpe-rolling-36m.jsonanddocs/site-data/meta-strategies/meta-max-sortino-rolling-36m.json— site payloads withlookback: 36m rollingdocs/experiments/qm-6djl.htmlanddocs/site-data/experiments/qm-6djl.json— window-selection experiment/results page documenting candidate evaluation, robustness, and comparisonstests/test_strategy_spec.py— updated versioned spec counts (146 total, 130 legacy) for new spec
Validation
python3 -m pytest -q tests/test_engine.py tests/test_datastore.py— 60 passedpython3 -m pytest -q tests/test_strategy_spec.py— 21 passed (after count update)python3 -m research.strategy_spec.validateandresearch.strategy_evidence.validate— both new specs and both promote manifests passpython3 research/scripts/check_static_reports.py docs— local bundle OK: 1220 files; 182 canary routespython3 -m research.pipeline verify --offline— strategy_promote contract passed, graph integrity validatedpython3 -m research.artifacts check --mode full --offline— shared artifacts deterministic and current- Synthetic smoke:
bounded_pre_signal_historystrictly before signal,ASMetaMaxSharpeRolling/ASMetaMaxSortinoRolling36m walk-forward produce weights; adjacent publication and 36m badge/link verified via grep
Results
Rolling 36m variants selected: Max Sharpe — Rolling 36m (CAGR 12.8%, vol 7.1%, Sharpe 1.81, Sortino 3.61, maxDD -9.8%, turnover 0.31, avg holding 12m, allocation stability 0.87) vs expanding 12.37%/1.77/3.50/-9.38%/0.28; Max Sortino — Rolling 36m (13.1%, 7.2%, Sharpe 1.82, Sortino 3.74, maxDD -8.7%, turnover 0.30) vs expanding 12.79%/1.76/3.61/-8.29%/0.27 on common 1996-2026 net base. Both beat expanding on untouched 2000-2026, 5 regime slices (Sharpe 5/5, Sortino 4/5), WF average, extra-lag and 2x cost; 12/18 sparse-sample failures and 84/120 unjustified longer windows rejected. Common 36m for both after documenting insufficient evidence for differing L. Published adjacent to expanding on Meta Strategies with lookback prominently labeled and linked to the detailed window-selection experiment page at docs/experiments/qm-6djl.html.
Links
- Task:
qm-6djl - Detailed analysis:
research/findings/specs/meta-rolling-lookback-qm-6djl.json,research/findings/meta-rolling-trial-ledger-qm-6djl.json,research/strategy_evidence/meta-rolling-max-sharpe-qm-6djl.jsonandmeta-rolling-max-sortino-qm-6djl.json - Code changes:
research/optimizer3_meta.py(lookback_months+bounded_pre_signal_history),backtest/meta_strategy.py(ASMetaMaxSharpeRolling,ASMetaMaxSortinoRolling) - Experiments / data:
docs/site-data/experiments/qm-6djl.json+docs/experiments/qm-6djl.html(window selection over 12/18/24/36/48/60/84/120m, walk-forward 1996–2026, 5 regimes, cost/lag checks) - Affected website pages:
docs/meta-strategies.html(adjacent rolling 36m rows),docs/meta-strategies/meta-max-sharpe-rolling-36m.htmlandmeta-max-sortino-rolling-36m.html,docs/site-data/meta-strategies/meta-max-sharpe-rolling-36m.json/meta-max-sortino-rolling-36m.json,docs/results/qm-6djl.html
Correction (2026-08-19 — scope fix per qm-ghn0)
Original qm-6djl published AS rolling 36m variants (ASMetaMaxSharpeRolling / ASMetaMaxSortinoRolling in backtest/meta_strategy.py) on the AS annual walk-forward Meta basket (non-continuous). Intent was continuous-weight rolling lookback; implementation was mis-scoped to the AS full-universe Max Sharpe/Sortino objective. Disposition: retired/relabeled as non-canonical and site/catalog cleanup executed.
- Removed/retired:
docs/meta-strategies/meta-max-sharpe-rolling-36m.html,docs/meta-strategies/meta-max-sortino-rolling-36m.html,docs/site-data/meta-strategies/meta-max-sharpe-rolling-36m.json,docs/site-data/meta-strategies/meta-max-sortino-rolling-36m.json— adjacency ondocs/meta-strategies.htmlremoved, catalogsite-data/meta-strategies/*.jsonno longer contains rolling AS entries. - Retained for provenance:
research/findings/specs/meta-rolling-lookback-qm-6djl.json,research/findings/meta-rolling-trial-ledger-qm-6djl.json,research/strategy_evidence/meta-rolling-max-sharpe-qm-6djl.json/meta-rolling-max-sortino-qm-6djl.jsonremain on disk as retired evidence (non-canonical), superseded by correctly scopedresearch/findings/specs/meta-continuous-rolling-lookback-qm-ghn0.jsonandresearch/findings/meta-continuous-rolling-trial-ledger-qm-ghn0.json/research/strategy_evidence/meta-continuous-rolling-qm-ghn0.json(qm-ghn0). - Updated links:
docs/experiments/qm-6djl.htmlnow carries a retirement banner linking to correctly scoped rejected experimentdocs/experiments/qm-ghn0.html/docs/site-data/experiments/qm-ghn0.json(research/experiments/qm-ghn0.json), which documents full window selection (12/18/24/36/48/60/84/120) with walk-forward/OOS/regime/neighbor/cost gates and all risk/return/turnover/selection/holding-duration/regime/allocation-stability comparisons vs expanding (CAGR, vol, Sharpe, Sortino, maxDD, worst month/year, turnover 0.36 vs 0.14, selection 5.2 vs 5.4, avg holding 12m, regime 1/5, allocation stability 0.66 vs 0.89) plus responsiveness. Expanding remains canonical; rolling continuous variants NOT promoted (no adjacency, no catalog admission). This results correction entry documents the changelog.