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
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Quant system on LongPort OpenAPI and Google Cloud Run.

This repository uses `QuantPlatformKit` for LongPort token handling, context bootstrap, account snapshot access, market data, and order submission. Cloud Run deploys this repository directly.
The runtime now carries a structured `RuntimeTarget` / `RUNTIME_TARGET_JSON` alongside the compatibility `STRATEGY_PROFILE` selector. Strategy-owned defaults come from `UsEquityStrategies` and `HkEquityStrategies`; platform variables are only explicit overrides.
The LongBridge runtime can execute the current `runtime_enabled` `us_equity` profiles from `UsEquityStrategies`. It also carries eligible-but-disabled HK profiles from `HkEquityStrategies`: `hk_blue_chip_leader_rotation`, `hk_index_mean_reversion`, `hk_etf_regime_rotation`, and `hk_listed_global_etf_rotation`; `LongBridgePlatform` keeps the LongPort runtime, token refresh, execution, and notification flow.
The LongBridge runtime can execute the current `runtime_enabled` `us_equity` profiles from `UsEquityStrategies`. It also carries HK profiles from `HkEquityStrategies`: eligible-but-disabled `hk_blue_chip_leader_rotation`, `hk_index_mean_reversion`, `hk_etf_regime_rotation`, plus runtime-enabled `hk_listed_global_etf_rotation`; `LongBridgePlatform` keeps the LongPort runtime, token refresh, execution, and notification flow.
`STRATEGY_PROFILE` remains the compatibility selector for strategy routing, while `RuntimeTarget` describes the running service identity.

Strategy documentation lives in [`UsEquityStrategies`](https://github.com/QuantStrategyLab/UsEquityStrategies) and [`HkEquityStrategies`](https://github.com/QuantStrategyLab/HkEquityStrategies). Snapshot artifact contracts for the HK profile are produced by [`HkEquitySnapshotPipelines`](https://github.com/QuantStrategyLab/HkEquitySnapshotPipelines). The sections below focus on LongBridge runtime behavior, profile enablement, deployment, and credentials.
Expand Down Expand Up @@ -45,7 +45,7 @@ Platform execution no longer depends on `strategy/allocation.py` or hard-coded s
| `hk_blue_chip_leader_rotation` | HK Blue Chip Leader Rotation | Yes | No | `hk_equity` | architecture scaffold only; not runtime-enabled |
| `hk_index_mean_reversion` | HK Index Mean Reversion | Yes | No | `hk_equity` | market-history research candidate; not runtime-enabled |
| `hk_etf_regime_rotation` | HK ETF Regime Rotation | Yes | No | `hk_equity` | market-history research candidate; not runtime-enabled |
| `hk_listed_global_etf_rotation` | HK-listed Global ETF Rotation | Yes | No | `hk_equity` | volatility-targeted market-history research candidate; not runtime-enabled |
| `hk_listed_global_etf_rotation` | HK-listed Global ETF Rotation | Yes | Yes | `hk_equity` | runtime-enabled; production env unchanged until explicit rollout |

Check the current matrix locally:

Expand Down Expand Up @@ -73,7 +73,7 @@ Telegram notifications include structured execution and heartbeat messages, with
| `LONGPORT_APP_SECRET` | Yes | LongPort OpenAPI app secret (for token refresh); recommended to inject from the region-specific Secret Manager secret for this deployment, such as `longport-app-secret-paper` / `longport-app-secret-hk` / `longport-app-secret-sg` |
| `LONGPORT_SECRET_NAME` | No | Secret Manager secret name for LongPort token (default: `longport_token_paper`) |
| `ACCOUNT_PREFIX` | No | Alert/log prefix for account/environment (default: `DEFAULT`) |
| `STRATEGY_PROFILE` | Yes | Strategy profile selector for compatibility and strategy routing. Set explicitly per deployment; enabled values include `global_etf_confidence_vol_gate`, `global_etf_rotation`, `mega_cap_leader_rotation_top50_balanced`, `russell_1000_multi_factor_defensive`, `soxl_soxx_trend_income`, `tech_communication_pullback_enhancement`, and `tqqq_growth_income`. The structured runtime target is carried separately as `RUNTIME_TARGET_JSON`. |
| `STRATEGY_PROFILE` | Yes | Strategy profile selector for compatibility and strategy routing. Set explicitly per deployment; enabled values include `global_etf_confidence_vol_gate`, `global_etf_rotation`, `mega_cap_leader_rotation_top50_balanced`, `russell_1000_multi_factor_defensive`, `soxl_soxx_trend_income`, `tech_communication_pullback_enhancement`, `tqqq_growth_income`, and `hk_listed_global_etf_rotation`. The structured runtime target is carried separately as `RUNTIME_TARGET_JSON`; production Cloud Run remains on its configured profile until an explicit rollout changes it. |
| `ACCOUNT_REGION` | No | Account region marker for platform-style deployment (e.g. `PAPER`, `HK`, `SG`; defaults to `ACCOUNT_PREFIX` / `DEFAULT`) |
| `LONGBRIDGE_MARKET` | No | Market scope. Defaults to `HK` when `ACCOUNT_REGION=HK`, otherwise `US`. |
| `LONGBRIDGE_MARKET_CALENDAR` | No | Market calendar for market-hours checks. Defaults to `XHKG` for HK and `NYSE` for US. |
Expand Down Expand Up @@ -204,7 +204,7 @@ IAM: the Cloud Run service account needs **Secret Manager Admin** (or Secret Acc

这个仓库通过 `QuantPlatformKit` 复用 LongPort token 处理、上下文初始化、账户快照、行情读取和下单逻辑。Cloud Run 直接部署这个仓库。
LongBridge 的账户身份按 `paper`、`HK`、`SG` 三个维度建模。
`LongBridgePlatform` 现在可直接执行 `UsEquityStrategies` 里的 `runtime_enabled` `us_equity` 策略,同时带有 `HkEquityStrategies` 里的港股 eligible-but-disabled profile:`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation` `hk_listed_global_etf_rotation`。这些港股 profile 当前仅用于框架和 feed/dry-run 兼容性检查,未 enabled。仓库本身继续保留 LongPort 运行时、token 刷新、执行和通知流程。
`LongBridgePlatform` 现在可直接执行 `UsEquityStrategies` 里的 `runtime_enabled` `us_equity` 策略,同时带有 `HkEquityStrategies` 里的港股 profile:`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation` 仍是 eligible-but-disabled,`hk_listed_global_etf_rotation` 已 runtime-enabled。生产环境仍保持原策略,除非单独变更 `RUNTIME_TARGET_JSON` / `STRATEGY_PROFILE`。仓库本身继续保留 LongPort 运行时、token 刷新、执行和通知流程。

策略说明放在 [`UsEquityStrategies`](https://github.com/QuantStrategyLab/UsEquityStrategies) 和 [`HkEquityStrategies`](https://github.com/QuantStrategyLab/HkEquityStrategies);港股 snapshot artifact 由 [`HkEquitySnapshotPipelines`](https://github.com/QuantStrategyLab/HkEquitySnapshotPipelines) 生成。下面这些章节只保留 LongBridge 运行时、profile 启用状态、部署和凭据说明。

Expand Down Expand Up @@ -233,7 +233,7 @@ LongBridge 的账户身份按 `paper`、`HK`、`SG` 三个维度建模。
| `hk_blue_chip_leader_rotation` | HK Blue Chip Leader Rotation | Yes | No | `hk_equity` | 仅架构占位,暂未 runtime-enabled |
| `hk_index_mean_reversion` | HK Index Mean Reversion | Yes | No | `hk_equity` | market-history 研究候选,暂未 runtime-enabled |
| `hk_etf_regime_rotation` | HK ETF Regime Rotation | Yes | No | `hk_equity` | market-history 研究候选,暂未 runtime-enabled |
| `hk_listed_global_etf_rotation` | HK-listed Global ETF Rotation | Yes | No | `hk_equity` | 波动率目标 market-history 研究候选,暂未 runtime-enabled |
| `hk_listed_global_etf_rotation` | HK-listed Global ETF Rotation | Yes | Yes | `hk_equity` | runtime-enabled;生产环境保持原策略直到显式 rollout |

本地可直接查看当前矩阵:

Expand Down Expand Up @@ -261,7 +261,7 @@ Telegram 通知包含结构化的调仓和心跳消息,支持中英文切换
| `LONGPORT_APP_SECRET` | 是 | LongPort OpenAPI 应用密钥(用于刷新 Token);建议从当前部署对应区域的 Secret Manager 密钥注入,例如 `longport-app-secret-paper` / `longport-app-secret-hk` / `longport-app-secret-sg` |
| `LONGPORT_SECRET_NAME` | 否 | Secret Manager 中的密钥名称(默认: `longport_token_paper`) |
| `ACCOUNT_PREFIX` | 否 | 通知/日志前缀,区分账户环境(默认: `DEFAULT`) |
| `STRATEGY_PROFILE` | 是 | 策略档位选择。每个部署都要显式设置;已启用值包括 `global_etf_confidence_vol_gate`、`global_etf_rotation`、`mega_cap_leader_rotation_top50_balanced`、`russell_1000_multi_factor_defensive`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement` 和 `tqqq_growth_income` |
| `STRATEGY_PROFILE` | 是 | 策略档位选择。每个部署都要显式设置;已启用值包括 `global_etf_confidence_vol_gate`、`global_etf_rotation`、`mega_cap_leader_rotation_top50_balanced`、`russell_1000_multi_factor_defensive`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement`、`tqqq_growth_income` 和 `hk_listed_global_etf_rotation`;生产 Cloud Run 保持原配置,除非显式 rollout |
| `ACCOUNT_REGION` | 否 | 平台化部署时的账户区域标记(如 `PAPER`、`HK`、`SG`;默认按 `ACCOUNT_PREFIX` / `DEFAULT` 推断) |
| `LONGBRIDGE_MARKET` | 否 | 市场范围。`ACCOUNT_REGION=HK` 时默认 `HK`,其他情况默认 `US`。 |
| `LONGBRIDGE_MARKET_CALENDAR` | 否 | 市场开闭市检查用的日历。港股默认 `XHKG`,美股默认 `NYSE`。 |
Expand Down
8 changes: 4 additions & 4 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 元数据:`hk_blue_chip_leader_rotation` 是架构占位,`hk_index_mean_reversion`、`hk_etf_regime_rotation` 和 `hk_listed_global_etf_rotation` 是 `market_history` 研究候选。这些 profile 都只用于框架 wiring、feed/dry-run 兼容性检查和尚未 runtime-enabled。整体仍沿用美股策略的分层方式:
平台运行时已具备港股市场维度,并接入 `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`。整体仍沿用美股策略的分层方式:

1. [`HkEquityStrategies`](https://github.com/QuantStrategyLab/HkEquityStrategies) 提供 `hk_equity` 策略定义、运行入口和 LongBridge runtime adapter。
2. [`HkEquitySnapshotPipelines`](https://github.com/QuantStrategyLab/HkEquitySnapshotPipelines) 产出 snapshot-backed profile 的特征快照、manifest、ranking 和 release summary。
Expand All @@ -31,7 +31,7 @@ QuantStrategyLab 现有平台仓库里,能做港股股票交易运行时接入
| `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 | eligible but disabled |
| `hk_listed_global_etf_rotation` | `hk_equity` | `market_history` | `weight` | not required | runtime-enabled; not deployed by default |

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

Expand Down Expand Up @@ -74,6 +74,6 @@ LONGBRIDGE_TRADING_CURRENCY=HKD
## 风险和注意事项

- `XHKG` 是否可用取决于部署环境里的 `pandas_market_calendars` 版本;如不可用,可用 `LONGBRIDGE_MARKET_CALENDAR` 临时覆盖。
- `hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation`、`hk_listed_global_etf_rotation` 当前均未启用;不要把这些 profile 写入生产 Cloud Run。
- `market_history` 研究候选后续真正启用前,需要先用 LongBridge HK 行情 feed 对 `02800`、`03033`、`02822`、`02840`、`03110`、`03188`、`02834`、`03175` 做 dry-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 投入生产前,需要先用 LongBridge HK 行情 feed 对 `02800`、`03033`、`02822`、`02840`、`03110`、`03188`、`02834`、`03175` 做 dry-run 校验,不提交真实订单。
- LongBridge 下单仍保持整数股规则;如果未来港股策略涉及碎股或特殊交易单位,需要在策略层明确 lot-size 约束后再扩展。
2 changes: 2 additions & 0 deletions notifications/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"strategy_name_tech_communication_pullback_enhancement": "科技通信回调增强",
"strategy_name_qqq_tech_enhancement": "科技通信回调增强",
"strategy_name_mega_cap_leader_rotation_top50_balanced": "Mega Cap Top50 平衡龙头轮动",
"strategy_name_hk_listed_global_etf_rotation": "港股上市全球 ETF 轮动",
"strategy_plugin_line": "🧩 插件:{plugin} | 状态:{route} | 提醒:{action}",
"strategy_plugin_alert_subject": "🚨 策略插件告警:{plugin} | {route}",
"strategy_plugin_alert_title": "🚨 【策略插件告警】",
Expand Down Expand Up @@ -218,6 +219,7 @@
"strategy_name_tech_communication_pullback_enhancement": "Tech/Communication Pullback Enhancement",
"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_hk_listed_global_etf_rotation": "HK-listed Global ETF Rotation",
"strategy_plugin_line": "🧩 Plugin: {plugin} | status: {route} | notice: {action}",
"strategy_plugin_alert_subject": "🚨 Strategy plugin alert: {plugin} | {route}",
"strategy_plugin_alert_title": "🚨 【Strategy Plugin Alert】",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ flask
gunicorn
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@v0.7.35
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@v0.7.49
hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@400ef6145bff0b89b46ec00ebb235987ac499a61
hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@71141ce9e8a343cec8e2140994071eea66422bc6

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Route HK orders with the configured suffix

With this pin, the HK package now makes hk_listed_global_etf_rotation runtime-enabled, so load_platform_runtime_settings accepts it and sets symbol_suffix=.HK for ACCOUNT_REGION=HK. The execution path still ignores that suffix: execute_rebalance_cycle hard-codes order symbols as f"{symbol}.US" in the sell/buy submission branches (for example application/execution_service.py lines 704, 724, 969, and 988), and build_execution_port forwards the symbol directly to LongBridge. Any explicit HK rollout that tries to trade 02800, 03033, etc. will therefore submit invalid/wrong .US symbols instead of .HK, so the profile should not be enabled until order symbol formatting is parameterized by the runtime suffix.

Useful? React with 👍 / 👎.

pandas
requests
pytz
Expand Down
2 changes: 2 additions & 0 deletions tests/test_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ def test_supported_strategy_profiles_have_translated_names(self):
en_name = build_strategy_display_name(build_translator("en"))
self.assertEqual(zh_name("global_etf_confidence_vol_gate"), "全球 ETF 置信波动门控")
self.assertEqual(en_name("global_etf_confidence_vol_gate"), "Global ETF Confidence Vol Gate")
self.assertEqual(zh_name("hk_listed_global_etf_rotation"), "港股上市全球 ETF 轮动")
self.assertEqual(en_name("hk_listed_global_etf_rotation"), "HK-listed Global ETF Rotation")

for profile in SUPPORTED_STRATEGY_PROFILES:
self.assertNotEqual(zh_name(profile), profile)
Expand Down
28 changes: 24 additions & 4 deletions tests/test_runtime_config_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@
}
)
OPTIONAL_LONGBRIDGE_PROFILES = frozenset({"global_etf_confidence_vol_gate"})
HK_RUNTIME_ENABLED_PROFILES = frozenset({"hk_listed_global_etf_rotation"})
HK_DISABLED_PROFILES = frozenset(
{
"hk_blue_chip_leader_rotation",
"hk_index_mean_reversion",
"hk_etf_regime_rotation",
"hk_listed_global_etf_rotation",
}
)


def expected_longbridge_enabled_profiles(actual_profiles) -> frozenset[str]:
actual = frozenset(actual_profiles)
return BASE_LONGBRIDGE_PROFILES | (OPTIONAL_LONGBRIDGE_PROFILES & actual)
return BASE_LONGBRIDGE_PROFILES | HK_RUNTIME_ENABLED_PROFILES | (OPTIONAL_LONGBRIDGE_PROFILES & actual)


def expected_longbridge_profiles(actual_profiles) -> frozenset[str]:
Expand Down Expand Up @@ -643,7 +643,7 @@ def test_platform_profile_status_matrix_matches_current_longbridge_rollout(self)
"display_name": "HK-listed Global ETF Rotation",
"domain": "hk_equity",
"eligible": True,
"enabled": False,
"enabled": True,
"platform": "longbridge",
},
)
Expand All @@ -669,7 +669,7 @@ def test_loads_feature_snapshot_env_for_tech_profile(self):
self.assertEqual(settings.strategy_config_path, "/workspace/configs/tech.json")
self.assertEqual(settings.strategy_config_source, "env")

def test_rejects_hk_profiles_until_runtime_enabled(self):
def test_rejects_disabled_hk_profiles(self):
for profile in sorted(HK_DISABLED_PROFILES):
with self.subTest(profile=profile):
with patch.dict(
Expand All @@ -685,6 +685,26 @@ def test_rejects_hk_profiles_until_runtime_enabled(self):
with self.assertRaisesRegex(ValueError, "Unsupported STRATEGY_PROFILE"):
load_platform_runtime_settings(project_id_resolver=lambda: "project-1")

def test_accepts_runtime_enabled_hk_global_etf_rotation(self):
with patch.dict(
os.environ,
{
"RUNTIME_TARGET_JSON": runtime_target_json("hk_listed_global_etf_rotation"),
"ACCOUNT_REGION": "HK",
},
clear=True,
):
settings = load_platform_runtime_settings(project_id_resolver=lambda: "project-1")

self.assertEqual(settings.strategy_profile, "hk_listed_global_etf_rotation")
self.assertEqual(settings.strategy_display_name, "HK-listed Global ETF Rotation")
self.assertEqual(settings.strategy_domain, "hk_equity")
self.assertEqual(settings.market, HK_MARKET)
self.assertEqual(settings.market_calendar, HK_MARKET_CALENDAR)
self.assertEqual(settings.market_timezone, HK_MARKET_TIMEZONE)
self.assertEqual(settings.symbol_suffix, HK_SYMBOL_SUFFIX)
self.assertEqual(settings.trading_currency, HK_TRADING_CURRENCY)

def test_derives_feature_snapshot_paths_from_artifact_root(self):
with TemporaryDirectory() as tmp_dir:
with patch.dict(
Expand Down