Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/us_equity_strategy_status.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`. |
Expand Down
2 changes: 1 addition & 1 deletion docs/us_equity_strategy_status.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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。 |
Expand Down
10 changes: 5 additions & 5 deletions src/us_equity_strategies/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -637,15 +637,15 @@ 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=(),
cadence="monthly review",
asset_scope="us_equity_combo",
benchmark="SPY",
role="us_equity_combo",
status="runtime_enabled",
status="shadow_candidate",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Propagate the combo demotion to its runtime manifest

In contexts that load us_equity_combo_entrypoint directly, this catalog demotion is not reflected because the entrypoint is still constructed from combo_manifests.us_equity_combo_manifest, whose description continues to label the profile as live and whose default config has no shadow marker. A manifest-driven platform or operator UI can therefore still surface us_equity_combo as live even though get_runtime_enabled_profiles() now excludes it; please update the combo manifest alongside this status change.

Useful? React with 👍 / 👎.

),
US_EQUITY_COMBO_CORE_PROFILE: StrategyMetadata(
canonical_profile=US_EQUITY_COMBO_CORE_PROFILE,
Expand All @@ -666,15 +666,15 @@ 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=(),
cadence="daily review",
asset_scope="us_equity_combo_leveraged",
benchmark="SPY",
role="us_equity_combo_leveraged",
status="runtime_enabled",
status="shadow_candidate",
),
}

Expand Down
17 changes: 17 additions & 0 deletions src/us_equity_strategies/runtime_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"}),
Expand Down Expand Up @@ -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),
Comment on lines +198 to +200

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add portfolio inputs for value-mode shadow adapters

For the shadow combo profiles on Schwab, Longbridge, and Firstrade, this new adapter path skips the cross-target-mode normalization done in _build_runtime_adapter_for_platform: these profiles emit weight targets while those platforms are value-native, so their adapters used to add portfolio_snapshot and set portfolio_input_name for translation. Because the profiles are still exposed through PLATFORM_RUNTIME_ADAPTERS, get_platform_runtime_adapter("us_equity_combo", platform_id="schwab") now returns an adapter with only russell_snapshot/current_holdings, leaving value-mode runtimes without the portfolio snapshot needed to convert weights into dollar targets.

Useful? React with 👍 / 👎.

)
)
return adapters


Expand Down
10 changes: 8 additions & 2 deletions tests/test_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand Down Expand Up @@ -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,
}
),
)
Expand Down
3 changes: 2 additions & 1 deletion tests/test_contract_governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
LONGBRIDGE_PLATFORM,
PAPER_SIGNAL_PLATFORM,
PLATFORM_RUNTIME_ADAPTERS,
SHADOW_RUNTIME_ADAPTERS,
SCHWAB_PLATFORM,
FIRSTRADE_PLATFORM,
get_platform_runtime_adapter,
Expand Down Expand Up @@ -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)
Expand Down
Loading