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 .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
assert CallableNotificationPort
assert CallablePortfolioPort
assert resolve_canonical_profile("mega_cap_leader_rotation_top50_balanced") == "mega_cap_leader_rotation_top50_balanced"
assert resolve_hk_canonical_profile("hk_blue_chip_leader_rotation") == "hk_blue_chip_leader_rotation"
assert resolve_hk_canonical_profile("hk_listed_global_etf_rotation") == "hk_listed_global_etf_rotation"
PY

- name: Install editable shared repositories
Expand Down
16 changes: 9 additions & 7 deletions docs/hk_equity_runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ QuantStrategyLab 现有平台仓库里,能接入港股股票交易的平台是

## 运行时设计

本仓库只做券商运行时能力,不把港股策略逻辑硬编码进平台。当前已接入 `HkEquityStrategies` 的港股 profile 元数据:`hk_blue_chip_leader_rotation` 是架构占位,`hk_index_mean_reversion`、`hk_etf_regime_rotation` 是 `market_history` 研究候选,`hk_listed_global_etf_rotation` 已 runtime-enabled。生产 Cloud Run 仍保持原策略,除非单独变更 `RUNTIME_TARGET_JSON` / `STRATEGY_PROFILE`。整体沿用美股策略的架构:
本仓库只做券商运行时能力,不把港股策略逻辑硬编码进平台。当前已接入 `HkEquityStrategies` 的港股 profile 元数据,平台可选港股 profile 只暴露 `runtime_enabled` 的 `hk_listed_global_etf_rotation`。`hk_blue_chip_leader_rotation` 是 snapshot 架构占位,`hk_index_mean_reversion`、`hk_etf_regime_rotation` 是 `market_history` 研究候选,均留在研究/快照仓库,不进入平台可选列表。生产 Cloud Run 仍保持原策略,除非单独变更 `RUNTIME_TARGET_JSON` / `STRATEGY_PROFILE`。整体沿用美股策略的架构:

1. [`HkEquityStrategies`](https://github.com/QuantStrategyLab/HkEquityStrategies) 提供 `hk_equity` 策略 profile、运行入口和 IBKR runtime adapter。
1. [`HkEquityStrategies`](https://github.com/QuantStrategyLab/HkEquityStrategies) 提供非 snapshot `hk_equity` 策略 profile、运行入口和 IBKR runtime adapter。
2. [`HkEquitySnapshotPipelines`](https://github.com/QuantStrategyLab/HkEquitySnapshotPipelines) 发布 snapshot-backed profile 的 `<profile>_feature_snapshot_latest.csv`、manifest、ranking 和 release summary。
3. 非 snapshot profile 使用平台 market-data feed 提供的 `market_history`,不需要 snapshot artifact。
4. 平台仓库通过 `RUNTIME_TARGET_JSON`、snapshot/config 路径和平台 market scope 读取策略输入。
Expand All @@ -28,10 +28,12 @@ QuantStrategyLab 现有平台仓库里,能接入港股股票交易的平台是

| Profile | Domain | Inputs | Target mode | Snapshot manifest | Status |
| --- | --- | --- | --- | --- | --- |
| `hk_blue_chip_leader_rotation` | `hk_equity` | `feature_snapshot` | `weight` | required | eligible but disabled |
| `hk_index_mean_reversion` | `hk_equity` | `market_history` | `weight` | not required | eligible but disabled |
| `hk_etf_regime_rotation` | `hk_equity` | `market_history` | `weight` | not required | eligible but disabled |
| `hk_listed_global_etf_rotation` | `hk_equity` | `market_history` | `weight` | not required | runtime-enabled; not deployed by default |
| `hk_listed_global_etf_rotation` | `hk_equity` | `market_history` | `weight` | not required | runtime-enabled; platform-selectable |
| `hk_blue_chip_leader_rotation` | `hk_equity` | `feature_snapshot` | `weight` | required | snapshot scaffold; not platform-selectable |
| `hk_index_mean_reversion` | `hk_equity` | `market_history` | `weight` | not required | research/backtest only; not platform-selectable |
| `hk_etf_regime_rotation` | `hk_equity` | `market_history` | `weight` | not required | research/backtest only; not platform-selectable |

`scripts/print_strategy_profile_status.py` 只显示平台可选 profile,因此只会列出 `hk_listed_global_etf_rotation` 这一条港股 profile。其他港股候选继续保留在研究文档和 snapshot pipeline,不应该出现在 Cloud Run switch plan 里。

未来启用 snapshot-backed profile 后的最小策略配置示例;当前不要写入 Cloud Run:

Expand Down Expand Up @@ -145,5 +147,5 @@ gh workflow run sync-cloud-run-env.yml \
- IBKR 港股实盘依赖账户权限、行情权限、Gateway 登录账户可见账号和交易许可;平台配置无法替代这些权限。
- 不同 IBKR 账户或区域对港股 symbol 格式可能有差异,首批上线前需要用 dry-run 和小范围 symbol 做实盘连接验证。
- `XHKG` 是否可用取决于部署环境里的 `pandas_market_calendars` 版本;如不可用,可用 `IBKR_MARKET_CALENDAR` 临时覆盖。
- `hk_listed_global_etf_rotation` 已在策略包 runtime-enabled,但生产 Cloud Run 仍保持原配置;`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation` 仍未启用,不要写入生产 Cloud Run。
- `hk_listed_global_etf_rotation` 已在策略包 runtime-enabled,但生产 Cloud Run 仍保持原配置;`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation` 不进入平台可选列表,不要写入生产 Cloud Run。
- 港股 `market_history` profile 投入生产前,需要先用 IBKR HK 行情 feed 对 `02800`、`03033`、`02822`、`02840`、`03110`、`03188`、`02834`、`03175` 做 dry-run 校验,不提交真实订单。
4 changes: 3 additions & 1 deletion strategy_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,16 @@ def describe_platform_runtime_requirements(profile: str | None, *, platform_id:
),
supported_capabilities=frozenset({"broker_client"}),
)
ELIGIBLE_STRATEGY_PROFILES = derive_eligible_profiles_for_platform(
_STRUCTURALLY_ELIGIBLE_STRATEGY_PROFILES = derive_eligible_profiles_for_platform(
STRATEGY_CATALOG,
capability_matrix=PLATFORM_CAPABILITY_MATRIX,
runtime_adapter_loader=lambda profile: get_platform_runtime_adapter(
profile,
platform_id=IBKR_PLATFORM,
),
)
# Keep research-only and snapshot-scaffold HK profiles out of platform switch/status output.
ELIGIBLE_STRATEGY_PROFILES = _STRUCTURALLY_ELIGIBLE_STRATEGY_PROFILES & IBKR_ROLLOUT_ALLOWLIST
IBKR_ENABLED_PROFILES = derive_enabled_profiles_for_platform(
STRATEGY_CATALOG,
capability_matrix=PLATFORM_CAPABILITY_MATRIX,
Expand Down
46 changes: 9 additions & 37 deletions tests/test_runtime_config_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"hk_etf_regime_rotation",
}
)
EXPECTED_IBKR_PROFILES = EXPECTED_IBKR_ENABLED_PROFILES | HK_DISABLED_PROFILES
EXPECTED_IBKR_PROFILES = EXPECTED_IBKR_ENABLED_PROFILES


def runtime_target_json(
Expand Down Expand Up @@ -701,30 +701,6 @@ def test_platform_profile_status_matrix_matches_current_ibkr_rollout():
assert by_profile["nasdaq_sp500_smart_dca"]["display_name"] == "Nasdaq/S&P 500 Smart DCA"
assert by_profile["nasdaq_sp500_smart_dca"]["eligible"] is True
assert by_profile["nasdaq_sp500_smart_dca"]["enabled"] is True
assert by_profile["hk_blue_chip_leader_rotation"] == {
"canonical_profile": "hk_blue_chip_leader_rotation",
"display_name": "HK Blue Chip Leader Rotation",
"domain": "hk_equity",
"eligible": True,
"enabled": False,
"platform": "ibkr",
}
assert by_profile["hk_index_mean_reversion"] == {
"canonical_profile": "hk_index_mean_reversion",
"display_name": "HK Index Mean Reversion",
"domain": "hk_equity",
"eligible": True,
"enabled": False,
"platform": "ibkr",
}
assert by_profile["hk_etf_regime_rotation"] == {
"canonical_profile": "hk_etf_regime_rotation",
"display_name": "HK ETF Regime Rotation",
"domain": "hk_equity",
"eligible": True,
"enabled": False,
"platform": "ibkr",
}
assert by_profile["hk_listed_global_etf_rotation"] == {
"canonical_profile": "hk_listed_global_etf_rotation",
"display_name": "HK-listed Global ETF Rotation",
Expand All @@ -733,6 +709,8 @@ def test_platform_profile_status_matrix_matches_current_ibkr_rollout():
"enabled": True,
"platform": "ibkr",
}
for profile in HK_DISABLED_PROFILES:
assert profile not in by_profile


def test_print_strategy_profile_status_json_matches_registry():
Expand Down Expand Up @@ -774,12 +752,9 @@ def test_print_strategy_profile_status_json_matches_registry():
assert by_profile["mega_cap_leader_rotation_top50_balanced"]["input_mode"] == "feature_snapshot"
assert by_profile["mega_cap_leader_rotation_top50_balanced"]["requires_snapshot_artifacts"] is True
assert by_profile["mega_cap_leader_rotation_top50_balanced"]["requires_strategy_config_path"] is False
assert by_profile["hk_blue_chip_leader_rotation"]["profile_group"] == "snapshot_backed"
assert by_profile["hk_blue_chip_leader_rotation"]["input_mode"] == "feature_snapshot"
assert by_profile["hk_blue_chip_leader_rotation"]["requires_snapshot_artifacts"] is True
assert by_profile["hk_blue_chip_leader_rotation"]["requires_snapshot_manifest_path"] is True
assert by_profile["hk_blue_chip_leader_rotation"]["requires_strategy_config_path"] is False
for profile in ("hk_index_mean_reversion", "hk_etf_regime_rotation", "hk_listed_global_etf_rotation"):
for profile in ("hk_blue_chip_leader_rotation", "hk_index_mean_reversion", "hk_etf_regime_rotation"):
assert profile not in by_profile
for profile in ("hk_listed_global_etf_rotation",):
assert by_profile[profile]["profile_group"] == "direct_runtime_inputs"
assert by_profile[profile]["input_mode"] == "market_history"
assert by_profile[profile]["requires_snapshot_artifacts"] is False
Expand All @@ -802,16 +777,13 @@ def test_print_strategy_profile_status_table_contains_expected_headers():
assert "input_mode" in result.stdout
assert "requires_snapshot_artifacts" in result.stdout
assert "global_etf_rotation" in result.stdout
assert "hk_blue_chip_leader_rotation" in result.stdout
assert "hk_index_mean_reversion" in result.stdout
assert "hk_etf_regime_rotation" in result.stdout
assert "hk_listed_global_etf_rotation" in result.stdout
assert "Tech/Communication Pullback Enhancement" in result.stdout
assert "HK Blue Chip Leader Rotation" in result.stdout
assert "HK Index Mean Reversion" in result.stdout
assert "HK ETF Regime Rotation" in result.stdout
assert "HK-listed Global ETF Rotation" in result.stdout
assert "TQQQ Growth Income" in result.stdout
assert "hk_blue_chip_leader_rotation" not in result.stdout
assert "hk_index_mean_reversion" not in result.stdout
assert "hk_etf_regime_rotation" not in result.stdout


def test_print_strategy_switch_env_plan_for_tqqq_growth_income():
Expand Down