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_listed_global_etf_rotation") == "hk_listed_global_etf_rotation"
assert resolve_hk_canonical_profile("hk_global_etf_tactical_rotation") == "hk_global_etf_tactical_rotation"
PY

- name: Install editable shared repositories
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sync-cloud-run-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ jobs:
json.dumps(
{
"platform_id": "ibkr",
"strategy_profile": "hk_listed_global_etf_rotation",
"strategy_profile": "hk_global_etf_tactical_rotation",
"deployment_selector": os.environ["ACCOUNT_GROUP_VALUE"],
"account_scope": os.environ["ACCOUNT_GROUP_VALUE"],
"execution_mode": "paper",
Expand Down
2 changes: 1 addition & 1 deletion configs/paper_global_etf_rotation.rollback.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ACCOUNT_GROUP=default
IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME=ibkr-account-groups
GLOBAL_TELEGRAM_CHAT_ID=<telegram-chat-id>
NOTIFY_LANG=zh
# remove if previously set for tech_communication_pullback_enhancement:
# remove if previously set by a snapshot-backed strategy:
# IBKR_FEATURE_SNAPSHOT_PATH
# IBKR_FEATURE_SNAPSHOT_MANIFEST_PATH
# IBKR_STRATEGY_CONFIG_PATH
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

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

## 运行时设计

本仓库只做券商运行时能力,不把港股策略逻辑硬编码进平台。当前已接入 `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` 选择当前运行策略。整体沿用美股策略的架构:
本仓库只做券商运行时能力,不把港股策略逻辑硬编码进平台。当前已接入 `HkEquityStrategies` 的港股 profile 元数据,平台可选港股 profile 只暴露 `runtime_enabled` 的 `hk_global_etf_tactical_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) 提供非 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。
Expand All @@ -28,12 +28,12 @@ QuantStrategyLab 现有平台仓库里,能接入港股股票交易的平台是

| Profile | Domain | Inputs | Target mode | Snapshot manifest | Status |
| --- | --- | --- | --- | --- | --- |
| `hk_listed_global_etf_rotation` | `hk_equity` | `market_history` | `weight` | not required | runtime-enabled; platform-selectable |
| `hk_global_etf_tactical_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 里。
`scripts/print_strategy_profile_status.py` 只显示平台可选 profile,因此只会列出 `hk_global_etf_tactical_rotation` 这一条港股 profile。其他港股候选继续保留在研究文档和 snapshot pipeline,不应该出现在 Cloud Run switch plan 里。

未来启用 snapshot-backed profile 后的最小策略配置示例;这些 profile 晋级为 `runtime_enabled` 前不会出现在平台可选列表:

Expand Down Expand Up @@ -76,7 +76,7 @@ IBKR_MARKET_DATA_SYMBOL_SUFFIX=.HK

```bash
python scripts/print_strategy_switch_env_plan.py \
--profile hk_listed_global_etf_rotation \
--profile hk_global_etf_tactical_rotation \
--dry-run-only \
--deployment-selector hk-verify \
--account-scope hk-verify \
Expand All @@ -87,7 +87,7 @@ python scripts/print_strategy_switch_env_plan.py \

这个命令只打印计划。输出会显式包含:

- `RUNTIME_TARGET_JSON`:`strategy_profile=hk_listed_global_etf_rotation`、`dry_run_only=true`、`execution_mode=paper`。
- `RUNTIME_TARGET_JSON`:`strategy_profile=hk_global_etf_tactical_rotation`、`dry_run_only=true`、`execution_mode=paper`。
- `IBKR_DRY_RUN_ONLY=true` 和 `IBKR_MARKET=HK` / `XHKG` / `SEHK` / `HKD` / `.HK`。
- `remove_if_present`:清理 snapshot/config 相关环境变量,因为该 profile 直接使用 `market_history`。
- `dry_run_plan`:检查 HK 行情权限、SEHK/HKD 映射、整数股和 lot-size、HKD 现金口径、通知和 runtime report。
Expand All @@ -99,7 +99,7 @@ python scripts/print_strategy_switch_env_plan.py \
仓库的 `Deploy Cloud Run` workflow 支持手动 `workflow_dispatch` 目标 `hk-verify`。这个目标会设置或更新独立港股 dry-run 服务:

- `CLOUD_RUN_SERVICE=interactive-brokers-hk-verify-service`(可通过输入改名)
- `STRATEGY_PROFILE=hk_listed_global_etf_rotation`
- `STRATEGY_PROFILE=hk_global_etf_tactical_rotation`
- `ACCOUNT_GROUP=hk-verify`
- `RUNTIME_TARGET_JSON.execution_mode=paper`、`dry_run_only=true`
- `IBKR_DRY_RUN_ONLY=true`
Expand Down Expand Up @@ -147,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`,可由 IBKR HK Cloud Run 通过运行时环境选择;`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation` 仍不进入平台可选列表。
- `hk_global_etf_tactical_rotation` 已在策略包 `runtime_enabled`,可由 IBKR HK Cloud Run 通过运行时环境选择;`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation` 仍不进入平台可选列表。
- 港股 `market_history` profile 运行后,需要持续用 IBKR HK 行情 feed 对 `02800`、`03033`、`02822`、`02840`、`03110`、`03188`、`02834`、`03175` 做行情、价差、lot-size 和订单预览/执行结果复核。
12 changes: 6 additions & 6 deletions notifications/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@
"strategy_name_qqq_tech_enhancement": "科技通信回调增强",
"strategy_name_mega_cap_leader_rotation_top50_balanced": "Mega Cap Top50 平衡龙头轮动",
"strategy_name_nasdaq_sp500_smart_dca": "纳斯达克 / 标普智能定投",
"strategy_name_hk_listed_global_etf_rotation": "港股上市全球 ETF 轮动",
"strategy_name_hk_high_dividend_low_vol_trend": "港股高股息低波趋势",
"strategy_name_hk_low_vol_dividend_quality": "港股低波股息质量",
"strategy_name_hk_global_etf_tactical_rotation": "港股全球 ETF 战术轮动",
"strategy_name_hk_dividend_gold_defensive_rotation": "港股股息黄金防守轮动",
"strategy_name_hk_low_vol_dividend_quality_snapshot": "港股低波股息质量快照",
"strategy_name_tqqq_growth_income": "TQQQ 增长收益",
"strategy_name_soxl_soxx_trend_income": "SOXL/SOXX 半导体趋势收益",
},
Expand Down Expand Up @@ -280,9 +280,9 @@
"strategy_name_qqq_tech_enhancement": "Tech/Communication Pullback Enhancement",
"strategy_name_mega_cap_leader_rotation_top50_balanced": "Mega Cap Leader Rotation Top50 Balanced",
"strategy_name_nasdaq_sp500_smart_dca": "Nasdaq/S&P 500 Smart DCA",
"strategy_name_hk_listed_global_etf_rotation": "HK-listed Global ETF Rotation",
"strategy_name_hk_high_dividend_low_vol_trend": "HK High Dividend Low-Volatility Trend",
"strategy_name_hk_low_vol_dividend_quality": "HK Low-Volatility Dividend Quality",
"strategy_name_hk_global_etf_tactical_rotation": "HK Global ETF Tactical Rotation",
"strategy_name_hk_dividend_gold_defensive_rotation": "HK Dividend-Gold Defensive Rotation",
"strategy_name_hk_low_vol_dividend_quality_snapshot": "HK Low-Vol Dividend Quality Snapshot",
"strategy_name_tqqq_growth_income": "TQQQ Growth Income",
"strategy_name_soxl_soxx_trend_income": "SOXL/SOXX Semiconductor Trend Income",
},
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
flask
gunicorn
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@v0.7.36
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@v0.7.50
hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@hk-low-vol-dividend-quality-20260603
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@v0.7.37
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@v0.7.52
hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@v0.4.3
pandas
numpy
requests
Expand Down
2 changes: 1 addition & 1 deletion scripts/build_cloud_run_env_sync_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def _should_add_local_src(candidate: Path) -> bool:
return _has_catalog_marker(
candidate,
"hk_equity_strategies",
"hk_listed_global_etf_rotation",
"hk_global_etf_tactical_rotation",
)
return True

Expand Down
2 changes: 1 addition & 1 deletion scripts/print_strategy_profile_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def _should_add_local_src(candidate: Path) -> bool:
return _has_catalog_marker(
candidate,
"hk_equity_strategies",
"hk_listed_global_etf_rotation",
"hk_global_etf_tactical_rotation",
)
return True

Expand Down
2 changes: 1 addition & 1 deletion scripts/print_strategy_switch_env_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def _should_add_local_src(candidate: Path) -> bool:
return _has_catalog_marker(
candidate,
"hk_equity_strategies",
"hk_listed_global_etf_rotation",
"hk_global_etf_tactical_rotation",
)
return True

Expand Down
2 changes: 1 addition & 1 deletion tests/test_execution_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ def accountValues(self):
order_intent_cls=OrderIntent,
translator=translate,
strategy_symbols=["02834", "03110"],
strategy_profile="hk_listed_global_etf_rotation",
strategy_profile="hk_global_etf_tactical_rotation",
account_group="paper-hk",
service_name="ibkr-hk-paper",
signal_metadata=_signal_metadata(
Expand Down
12 changes: 6 additions & 6 deletions tests/test_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ def test_strategy_display_name_translates_new_live_profiles():
assert en_name("mega_cap_leader_rotation_top50_balanced") == "Mega Cap Leader Rotation Top50 Balanced"
assert zh_name("nasdaq_sp500_smart_dca") == "纳斯达克 / 标普智能定投"
assert en_name("nasdaq_sp500_smart_dca") == "Nasdaq/S&P 500 Smart DCA"
assert zh_name("hk_listed_global_etf_rotation") == "港股上市全球 ETF 轮动"
assert en_name("hk_listed_global_etf_rotation") == "HK-listed Global ETF Rotation"
assert zh_name("hk_high_dividend_low_vol_trend") == "港股高股息低波趋势"
assert en_name("hk_high_dividend_low_vol_trend") == "HK High Dividend Low-Volatility Trend"
assert zh_name("hk_low_vol_dividend_quality") == "港股低波股息质量"
assert en_name("hk_low_vol_dividend_quality") == "HK Low-Volatility Dividend Quality"
assert zh_name("hk_global_etf_tactical_rotation") == "港股全球 ETF 战术轮动"
assert en_name("hk_global_etf_tactical_rotation") == "HK Global ETF Tactical Rotation"
assert zh_name("hk_dividend_gold_defensive_rotation") == "港股股息黄金防守轮动"
assert en_name("hk_dividend_gold_defensive_rotation") == "HK Dividend-Gold Defensive Rotation"
assert zh_name("hk_low_vol_dividend_quality_snapshot") == "港股低波股息质量快照"
assert en_name("hk_low_vol_dividend_quality_snapshot") == "HK Low-Vol Dividend Quality Snapshot"


def test_supported_strategy_profiles_have_translated_names():
Expand Down
6 changes: 3 additions & 3 deletions tests/test_request_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ def test_cycle_report_summary_counts_dry_run_order_previews(strategy_module):
def test_notification_delivery_log_summary_records_sent_dry_run_without_raw_text(strategy_module):
payload = strategy_module._build_notification_delivery_log_for_report(
platform="interactive_brokers",
strategy_profile="hk_low_vol_dividend_quality",
strategy_profile="hk_low_vol_dividend_quality_snapshot",
run_id="run-001",
dry_run=True,
orders_previewed_count=2,
Expand All @@ -446,7 +446,7 @@ def test_notification_delivery_log_summary_records_sent_dry_run_without_raw_text
assert payload["notification_event_type"] == "hk_snapshot_live_enablement_dry_run"
assert payload["notification_correlation_id"] == "run-001"
assert payload["locales"] == ["en", "zh-Hans"]
assert payload["profile"] == "hk_low_vol_dividend_quality"
assert payload["profile"] == "hk_low_vol_dividend_quality_snapshot"
assert payload["platform"] == "interactive_brokers"
assert payload["orders_previewed"] == 2
assert payload["notification_redacts_sensitive_fields"] is True
Expand All @@ -456,7 +456,7 @@ def test_notification_delivery_log_summary_records_sent_dry_run_without_raw_text
def test_notification_delivery_log_summary_stays_empty_without_sent_event(strategy_module):
payload = strategy_module._build_notification_delivery_log_for_report(
platform="interactive_brokers",
strategy_profile="hk_low_vol_dividend_quality",
strategy_profile="hk_low_vol_dividend_quality_snapshot",
run_id="run-001",
dry_run=True,
orders_previewed_count=2,
Expand Down
Loading