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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The mainline runtime now follows one path only:
- `hk_blue_chip_leader_rotation` (architecture scaffold only; eligible but disabled)
- `hk_index_mean_reversion` (market-history research candidate; eligible but disabled)
- `hk_etf_regime_rotation` (market-history research candidate; eligible but disabled)
- `hk_listed_global_etf_rotation` (volatility-targeted market-history research candidate; eligible but disabled)
- `hk_listed_global_etf_rotation` (volatility-targeted market-history strategy; runtime-enabled, not deployed by default)


**IBKR profile status**
Expand All @@ -61,7 +61,7 @@ The mainline runtime now follows one path only:
| `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 @@ -113,7 +113,7 @@ For IBKR, keep `paper` as a single account-group entry. If you later add live ac
| `IBKR_CONNECT_ATTEMPTS` | No | Number of IBKR connection attempts before failing the cycle. Defaults to `3`. |
| `IBKR_CONNECT_RETRY_DELAY_SECONDS` | No | Delay between failed IBKR connection attempts. Defaults to `5`. |
| `IBKR_CLIENT_ID_RETRY_OFFSET` | No | Offset added to the configured `ib_client_id` on each retry, so a timed-out API handshake can retry with a fresh client id. Defaults to `100`. |
| `STRATEGY_PROFILE` | Yes | Strategy profile selector. Enabled values: `global_etf_rotation`, `russell_1000_multi_factor_defensive`, `tqqq_growth_income`, `soxl_soxx_trend_income`, `tech_communication_pullback_enhancement`, `mega_cap_leader_rotation_top50_balanced`, `nasdaq_sp500_smart_dca`. `hk_blue_chip_leader_rotation`, `hk_index_mean_reversion`, `hk_etf_regime_rotation`, and `hk_listed_global_etf_rotation` are present as eligible-but-disabled HK profiles and are not enabled. |
| `STRATEGY_PROFILE` | Yes | Strategy profile selector. Enabled values: `global_etf_rotation`, `russell_1000_multi_factor_defensive`, `tqqq_growth_income`, `soxl_soxx_trend_income`, `tech_communication_pullback_enhancement`, `mega_cap_leader_rotation_top50_balanced`, `nasdaq_sp500_smart_dca`, `hk_listed_global_etf_rotation`. `hk_blue_chip_leader_rotation`, `hk_index_mean_reversion`, and `hk_etf_regime_rotation` are eligible-but-disabled HK profiles; production Cloud Run keeps its configured profile until an explicit rollout changes it. |
| `ACCOUNT_GROUP` | Yes | Account-group selector. Set explicitly for each deployment. |
| `IBKR_MARKET` | No | Market scope. Defaults to `HK` when `ACCOUNT_GROUP` contains `hk`, otherwise `US`. |
| `IBKR_MARKET_CALENDAR` | No | Market calendar. Defaults to `XHKG` for HK and `NYSE` for US. |
Expand Down Expand Up @@ -453,7 +453,7 @@ IBKR 账户
| `IBKR_CONNECT_ATTEMPTS` | 否 | IBKR 连接失败前最多尝试次数。默认 `3`。 |
| `IBKR_CONNECT_RETRY_DELAY_SECONDS` | 否 | IBKR 连接重试间隔,单位秒。默认 `5`。 |
| `IBKR_CLIENT_ID_RETRY_OFFSET` | 否 | 每次重试时加到 `ib_client_id` 上的偏移量,用新的 client id 避开超时握手留下的卡住会话。默认 `100`。 |
| `STRATEGY_PROFILE` | 是 | 策略档位选择。当前已启用值:`global_etf_rotation`、`russell_1000_multi_factor_defensive`、`tqqq_growth_income`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement`、`mega_cap_leader_rotation_top50_balanced`、`nasdaq_sp500_smart_dca`。`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation`、`hk_listed_global_etf_rotation` 是 eligible-but-disabled 港股档位,未启用 |
| `STRATEGY_PROFILE` | 是 | 策略档位选择。当前已启用值:`global_etf_rotation`、`russell_1000_multi_factor_defensive`、`tqqq_growth_income`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement`、`mega_cap_leader_rotation_top50_balanced`、`nasdaq_sp500_smart_dca`、`hk_listed_global_etf_rotation`。`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation` 是 eligible-but-disabled 港股档位;生产 Cloud Run 保持原配置,除非显式 rollout |
| `ACCOUNT_GROUP` | 是 | 账号组选择器,每个部署都要显式设置。 |
| `IBKR_MARKET` | 否 | 市场范围。`ACCOUNT_GROUP` 包含 `hk` 时默认 `HK`,其他情况默认 `US`。 |
| `IBKR_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` 策略 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 @@ -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 @@ -86,5 +86,5 @@ IBKR_MARKET_DATA_SYMBOL_SUFFIX=.HK
- IBKR 港股实盘依赖账户权限、行情权限、Gateway 登录账户可见账号和交易许可;平台配置无法替代这些权限。
- 不同 IBKR 账户或区域对港股 symbol 格式可能有差异,首批上线前需要用 dry-run 和小范围 symbol 做实盘连接验证。
- `XHKG` 是否可用取决于部署环境里的 `pandas_market_calendars` 版本;如不可用,可用 `IBKR_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` 研究候选后续真正启用前,需要先用 IBKR 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 投入生产前,需要先用 IBKR HK 行情 feed 对 `02800`、`03033`、`02822`、`02840`、`03110`、`03188`、`02834`、`03175` 做 dry-run 校验,不提交真实订单。
2 changes: 2 additions & 0 deletions notifications/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
"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_tqqq_growth_income": "TQQQ 增长收益",
"strategy_name_soxl_soxx_trend_income": "SOXL/SOXX 半导体趋势收益",
},
Expand Down Expand Up @@ -277,6 +278,7 @@
"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_tqqq_growth_income": "TQQQ Growth Income",
"strategy_name_soxl_soxx_trend_income": "SOXL/SOXX Semiconductor Trend Income",
},
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
pandas
numpy
requests
Expand Down
2 changes: 2 additions & 0 deletions tests/test_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ 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"


def test_supported_strategy_profiles_have_translated_names():
Expand Down
25 changes: 22 additions & 3 deletions tests/test_runtime_config_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@
"soxl_soxx_trend_income",
"tech_communication_pullback_enhancement",
"tqqq_growth_income",
"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",
}
)
EXPECTED_IBKR_PROFILES = EXPECTED_IBKR_ENABLED_PROFILES | HK_DISABLED_PROFILES
Expand Down Expand Up @@ -588,7 +588,7 @@ def test_load_platform_runtime_settings_accepts_tech_communication_pullback_enha


@pytest.mark.parametrize("profile", sorted(HK_DISABLED_PROFILES))
def test_load_platform_runtime_settings_rejects_hk_profiles_until_runtime_enabled(monkeypatch, profile):
def test_load_platform_runtime_settings_rejects_disabled_hk_profiles(monkeypatch, profile):
monkeypatch.setenv("RUNTIME_TARGET_JSON", runtime_target_json(profile))
monkeypatch.setenv("ACCOUNT_GROUP", "hk-live")
monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_HK_GROUP_JSON)
Expand All @@ -599,6 +599,25 @@ def test_load_platform_runtime_settings_rejects_hk_profiles_until_runtime_enable
load_platform_runtime_settings(project_id_resolver=lambda: "project-1")


def test_load_platform_runtime_settings_accepts_runtime_enabled_hk_global_etf_rotation(monkeypatch):
monkeypatch.setenv("RUNTIME_TARGET_JSON", runtime_target_json("hk_listed_global_etf_rotation"))
monkeypatch.setenv("ACCOUNT_GROUP", "hk-live")
monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_HK_GROUP_JSON)

settings = load_platform_runtime_settings(project_id_resolver=lambda: "project-1")

assert settings.strategy_profile == "hk_listed_global_etf_rotation"
assert settings.strategy_display_name == "HK-listed Global ETF Rotation"
assert settings.strategy_domain == "hk_equity"
assert settings.strategy_target_mode == "weight"
assert settings.market == HK_MARKET
assert settings.market_calendar == HK_MARKET_CALENDAR
assert settings.market_currency == HK_MARKET_CURRENCY
assert settings.market_data_symbol_suffix == HK_MARKET_DATA_SYMBOL_SUFFIX
assert settings.market_exchange == HK_MARKET_EXCHANGE
assert settings.market_timezone == HK_MARKET_TIMEZONE


@pytest.mark.parametrize(
"archived_profile",
(
Expand Down Expand Up @@ -711,7 +730,7 @@ def test_platform_profile_status_matrix_matches_current_ibkr_rollout():
"display_name": "HK-listed Global ETF Rotation",
"domain": "hk_equity",
"eligible": True,
"enabled": False,
"enabled": True,
"platform": "ibkr",
}

Expand Down