diff --git a/docs/us_equity_strategy_status.md b/docs/us_equity_strategy_status.md index 91f64e2..1c21406 100644 --- a/docs/us_equity_strategy_status.md +++ b/docs/us_equity_strategy_status.md @@ -37,7 +37,7 @@ See the Chinese handbook for localized positioning text and default parameter ta | Profile / track | Status | Why not live | | --- | --- | --- | -| `tecl_xlk_trend_income` | `research_enabled` | Failed promotion versus live TQQQ and SOXL on overlapping windows (2024+ CAGR 24.8%, max drawdown -46.0%). Code and backtest tooling retained. Docs: [`UsEquitySnapshotPipelines/docs/tecl-xlk-optimization-research.md`](../../UsEquitySnapshotPipelines/docs/tecl-xlk-optimization-research.md). | +| `tecl_xlk_trend_income` | `research_backtest_only` | Failed promotion versus live TQQQ and SOXL on overlapping windows (2024+ CAGR 24.8%, max drawdown -46.0%). Code and backtest tooling retained. Docs: [`UsEquitySnapshotPipelines/docs/tecl-xlk-optimization-research.md`](../../UsEquitySnapshotPipelines/docs/tecl-xlk-optimization-research.md). | | `tech_communication_pullback_enhancement` | research_only | Underperforms `russell_top50_leader_rotation` on return and drawdown. | | `QQQ` / `SPY` LEAPS growth overlay | research_only | Design: [`research/index_leaps_growth_overlay.md`](./research/index_leaps_growth_overlay.md). Proxy backtest module: `UsEquitySnapshotPipelines/docs/index-leaps-growth-overlay-research.md`. | | `us_equity_combo_leveraged_shadow_352045` | shadow_candidate | TQQQ 35% / SOXL 20% / BOXX 45% with `hard_defense_risk_exposure=0.0`. Backtest evidence: 22.21% CAGR, -33.88% max drawdown over 2010-01-05 to 2026-07-02 with 5 bps cost. Runtime config: `src/us_equity_strategies/configs/us_equity_combo_leveraged_shadow_352045.json`. | diff --git a/docs/us_equity_strategy_status.zh-CN.md b/docs/us_equity_strategy_status.zh-CN.md index 2902d09..922e299 100644 --- a/docs/us_equity_strategy_status.zh-CN.md +++ b/docs/us_equity_strategy_status.zh-CN.md @@ -82,7 +82,7 @@ _更新日期:2026-06-28_ | 研究方向 | 当前状态 | 不直接部署的原因 | | --- | --- | --- | -| `tecl_xlk_trend_income` | `research_enabled` | 重叠窗口未跑赢 live TQQQ / SOXL(2024+ CAGR 24.8%,最大回撤 -46.0%);保留策略实现与回测入口,不进入 runtime。研究文档见 [`UsEquitySnapshotPipelines/docs/tecl-xlk-optimization-research.zh-CN.md`](../../UsEquitySnapshotPipelines/docs/tecl-xlk-optimization-research.zh-CN.md)。 | +| `tecl_xlk_trend_income` | `research_backtest_only` | 重叠窗口未跑赢 live TQQQ / SOXL(2024+ CAGR 24.8%,最大回撤 -46.0%);保留策略实现与回测入口,不进入 runtime。研究文档见 [`UsEquitySnapshotPipelines/docs/tecl-xlk-optimization-research.zh-CN.md`](../../UsEquitySnapshotPipelines/docs/tecl-xlk-optimization-research.zh-CN.md)。 | | `us_equity_combo_leveraged_shadow_352045` | shadow candidate | 组合型杠杆候选:`TQQQ 35% / SOXL 20% / BOXX 45%`,risk-off 归零风险腿转 `BOXX`。当前仅提供受控 runtime_config 与测试保护,不改变默认 live;需要平台 dry-run / shadow 周期证据后才可重新评估 live。 | | `us_equity_combo_leveraged_shadow_402040` | shadow candidate | 组合型杠杆候选:`TQQQ 40% / SOXL 20% / BOXX 40%`,risk-off 归零风险腿转 `BOXX`。这是 35%-40% 回撤预算下的下一轮 shadow 配置,不直接替换 live。 | | `crisis_response_shadow` 插件 | 可作为 `tqqq_growth_income` 的 `shadow` 插件候选,只写信号、日志和通知上下文。 | 现在是 defense-only 黑天鹅观察流,不下单、不改 allocation;需要稳定 shadow 日志后再做 evidence review。 | diff --git a/src/us_equity_strategies/catalog.py b/src/us_equity_strategies/catalog.py index 18673ba..2949c38 100644 --- a/src/us_equity_strategies/catalog.py +++ b/src/us_equity_strategies/catalog.py @@ -595,7 +595,7 @@ def _build_strategy_definition( asset_scope="technology_etf_plus_income", benchmark="XLK", role="sector_offensive_income", - status="research_enabled", + status="research_backtest_only", ), RUSSELL_TOP50_LEADER_ROTATION_PROFILE: StrategyMetadata( canonical_profile=RUSSELL_TOP50_LEADER_ROTATION_PROFILE, @@ -637,7 +637,7 @@ def _build_strategy_definition( canonical_profile=US_EQUITY_COMBO_PROFILE, display_name="US Equity Combo", description=( - "Live US core combo: Russell Top50 leaders (40%) + Nasdaq/S&P ETF " + "Shadow/internal US core combo: Russell Top50 leaders (40%) + Nasdaq/S&P ETF " "sleeve (40%) + BOXX cash defense (20%), with dynamic defense weights." ), aliases=(), @@ -645,7 +645,7 @@ def _build_strategy_definition( asset_scope="us_equity_combo", benchmark="SPY", role="us_equity_combo", - status="runtime_enabled", + status="shadow_candidate", ), US_EQUITY_COMBO_CORE_PROFILE: StrategyMetadata( canonical_profile=US_EQUITY_COMBO_CORE_PROFILE, @@ -666,7 +666,7 @@ def _build_strategy_definition( canonical_profile=US_EQUITY_COMBO_LEVERAGED_PROFILE, display_name="US Equity Combo Leveraged", description=( - "Leveraged US combo: TQQQ (40%) + SOXL (20%) + BOXX (40%) with " + "Shadow leveraged US combo: TQQQ (40%) + SOXL (20%) + BOXX (40%) with " "SPY MA200 dynamic risk-off cut." ), aliases=(), @@ -674,7 +674,7 @@ def _build_strategy_definition( asset_scope="us_equity_combo_leveraged", benchmark="SPY", role="us_equity_combo_leveraged", - status="runtime_enabled", + status="shadow_candidate", ), } diff --git a/src/us_equity_strategies/runtime_adapters.py b/src/us_equity_strategies/runtime_adapters.py index ae2e7ae..033cf19 100644 --- a/src/us_equity_strategies/runtime_adapters.py +++ b/src/us_equity_strategies/runtime_adapters.py @@ -108,6 +108,11 @@ available_capabilities=frozenset({"fractional_share_execution"}), runtime_policy=StrategyRuntimePolicy(signal_effective_after_trading_days=0), ), +} + +# Shadow/internal combo profiles remain describable for runtime contract and +# test coverage, but they are not treated as base live adapters. +SHADOW_RUNTIME_ADAPTERS: dict[str, StrategyRuntimeAdapter] = { US_EQUITY_COMBO_PROFILE: StrategyRuntimeAdapter( status_icon="\U0001f1fa\U0001f1f8", available_inputs=frozenset({"russell_snapshot", "current_holdings"}), @@ -183,6 +188,18 @@ def _build_platform_runtime_adapter_map(platform_id: str) -> dict[str, StrategyR profile, platform_id=normalized_platform, ) + for profile, base_adapter in SHADOW_RUNTIME_ADAPTERS.items(): + definition = get_strategy_definition(profile) + if normalized_platform not in definition.supported_platforms: + continue + adapters[profile] = validate_strategy_runtime_adapter( + replace( + base_adapter, + available_inputs=frozenset(base_adapter.available_inputs or definition.required_inputs), + portfolio_input_name=base_adapter.portfolio_input_name + or ("portfolio_snapshot" if "portfolio_snapshot" in definition.required_inputs else None), + ) + ) return adapters diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 38be913..9a70dc5 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -264,6 +264,14 @@ def test_metadata_map_exposes_display_names_and_roles(self): metadata_map[US_EQUITY_COMBO_CORE_PROFILE].status, "shadow_candidate", ) + self.assertEqual( + metadata_map[US_EQUITY_COMBO_PROFILE].status, + "shadow_candidate", + ) + self.assertEqual( + metadata_map[US_EQUITY_COMBO_LEVERAGED_PROFILE].status, + "shadow_candidate", + ) def test_option_overlay_defaults_are_enabled_but_live_gated(self): live_option_profiles = ( @@ -514,8 +522,6 @@ def test_runtime_enabled_profiles_are_the_live_catalog(self): RUSSELL_TOP50_LEADER_ROTATION_PROFILE, NASDAQ_SP500_SMART_DCA_PROFILE, IBIT_SMART_DCA_PROFILE, - US_EQUITY_COMBO_PROFILE, - US_EQUITY_COMBO_LEVERAGED_PROFILE, } ), ) diff --git a/tests/test_contract_governance.py b/tests/test_contract_governance.py index 7a7ffd8..f9e4c7c 100644 --- a/tests/test_contract_governance.py +++ b/tests/test_contract_governance.py @@ -17,6 +17,7 @@ LONGBRIDGE_PLATFORM, PAPER_SIGNAL_PLATFORM, PLATFORM_RUNTIME_ADAPTERS, + SHADOW_RUNTIME_ADAPTERS, SCHWAB_PLATFORM, FIRSTRADE_PLATFORM, get_platform_runtime_adapter, @@ -155,7 +156,7 @@ def test_runtime_adapter_map_matches_catalog_compatibility(self) -> None: supported_profiles = frozenset( profile for profile, platforms in compatibility_map.items() - if platform_id in platforms and profile in BASE_RUNTIME_ADAPTERS + if platform_id in platforms and profile in (BASE_RUNTIME_ADAPTERS | SHADOW_RUNTIME_ADAPTERS) ) with self.subTest(platform_id=platform_id): self.assertEqual(frozenset(adapters), supported_profiles)