From bbf8e0dc342cb499e1e7d9a7df8f98e5b9a2ad76 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Thu, 4 Jun 2026 01:50:51 +0800 Subject: [PATCH] Bump strategy package pins and HK runtime profiles --- .../build-hk-low-vol-snapshot-artifacts.yml | 16 ++--- .github/workflows/ci.yml | 4 +- .github/workflows/sync-cloud-run-env.yml | 2 +- docs/hk_equity_runtime.md | 30 +++++----- notifications/telegram.py | 6 -- requirements.txt | 6 +- scripts/print_strategy_profile_status.py | 2 +- scripts/print_strategy_switch_env_plan.py | 2 +- tests/test_notifications.py | 8 +-- tests/test_rebalance_service.py | 2 +- tests/test_request_handling.py | 6 +- tests/test_runtime_config_support.py | 58 +++++++++---------- tests/test_runtime_strategy_adapters.py | 2 +- tests/test_sync_cloud_run_env_workflow.sh | 2 +- 14 files changed, 70 insertions(+), 76 deletions(-) diff --git a/.github/workflows/build-hk-low-vol-snapshot-artifacts.yml b/.github/workflows/build-hk-low-vol-snapshot-artifacts.yml index 5314a25..34c4d07 100644 --- a/.github/workflows/build-hk-low-vol-snapshot-artifacts.yml +++ b/.github/workflows/build-hk-low-vol-snapshot-artifacts.yml @@ -11,10 +11,10 @@ on: profile: description: "HK snapshot profile to build." required: true - default: hk_low_vol_dividend_quality + default: hk_low_vol_dividend_quality_snapshot type: choice options: - - hk_low_vol_dividend_quality + - hk_low_vol_dividend_quality_snapshot data_source_mode: description: "Source used to generate the factor snapshot." required: true @@ -49,12 +49,12 @@ on: artifact_dir: description: "Artifact output directory inside HkEquitySnapshotPipelines." required: false - default: data/output/hk_low_vol_dividend_quality + default: data/output/hk_low_vol_dividend_quality_snapshot type: string gcs_prefix: description: "Optional GCS prefix for validated runtime artifacts." required: false - default: gs://qsl-runtime-logs-interactivebrokersquant/strategy-artifacts/hk_equity/hk_low_vol_dividend_quality + default: gs://qsl-runtime-logs-interactivebrokersquant/strategy-artifacts/hk_equity/hk_low_vol_dividend_quality_snapshot type: string execute_publish: description: "Actually upload validated artifacts to GCS. false only prints the publish plan." @@ -141,7 +141,7 @@ jobs: set -euo pipefail case "${PROFILE}" in - hk_low_vol_dividend_quality) ;; + hk_low_vol_dividend_quality_snapshot) ;; *) echo "Unsupported HK snapshot profile: ${PROFILE}" >&2 exit 1 @@ -205,8 +205,8 @@ jobs: generated_dir="data/input/generated/${PROFILE}" artifact_dir="${ARTIFACT_DIR_INPUT:-data/output/${PROFILE}}" mkdir -p "${generated_dir}" "${artifact_dir}" - snapshot_uri="${GCS_PREFIX%/}/hk_low_vol_dividend_quality_factor_snapshot_latest.csv" - manifest_uri="${GCS_PREFIX%/}/hk_low_vol_dividend_quality_factor_snapshot_latest.csv.manifest.json" + snapshot_uri="${GCS_PREFIX%/}/hk_low_vol_dividend_quality_snapshot_factor_snapshot_latest.csv" + manifest_uri="${GCS_PREFIX%/}/hk_low_vol_dividend_quality_snapshot_factor_snapshot_latest.csv.manifest.json" { echo "artifact_dir=${SNAPSHOT_REPO_DIR}/${artifact_dir}" echo "generated_input_dir=${SNAPSHOT_REPO_DIR}/${generated_dir}" @@ -390,7 +390,7 @@ jobs: echo "Suggested longbridge-hk environment values for dry-run runtime:" echo echo "\`\`\`bash" - echo "STRATEGY_PROFILE=hk_low_vol_dividend_quality" + echo "STRATEGY_PROFILE=hk_low_vol_dividend_quality_snapshot" echo "LONGBRIDGE_DRY_RUN_ONLY=true" echo "LONGBRIDGE_FEATURE_SNAPSHOT_PATH=${{ steps.build.outputs.snapshot_gcs_uri }}" echo "LONGBRIDGE_FEATURE_SNAPSHOT_MANIFEST_PATH=${{ steps.build.outputs.manifest_gcs_uri }}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ed65d9..3155102 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,8 +68,8 @@ jobs: assert CallableNotificationPort assert CallablePortfolioPort - assert resolve_canonical_profile("tech_communication_pullback_enhancement") == "tech_communication_pullback_enhancement" - assert resolve_hk_canonical_profile("hk_listed_global_etf_rotation") == "hk_listed_global_etf_rotation" + assert resolve_canonical_profile("mega_cap_leader_rotation_top50_balanced") == "mega_cap_leader_rotation_top50_balanced" + assert resolve_hk_canonical_profile("hk_global_etf_tactical_rotation") == "hk_global_etf_tactical_rotation" PY - name: Install editable shared repositories diff --git a/.github/workflows/sync-cloud-run-env.yml b/.github/workflows/sync-cloud-run-env.yml index 97d32f9..1c46ff8 100644 --- a/.github/workflows/sync-cloud-run-env.yml +++ b/.github/workflows/sync-cloud-run-env.yml @@ -231,7 +231,7 @@ jobs: json.dumps( { "platform_id": "longbridge", - "strategy_profile": "hk_listed_global_etf_rotation", + "strategy_profile": "hk_global_etf_tactical_rotation", "deployment_selector": "hk-verify", "account_scope": "hk-verify", "execution_mode": "paper", diff --git a/docs/hk_equity_runtime.md b/docs/hk_equity_runtime.md index 3e45b82..c4a9ce8 100644 --- a/docs/hk_equity_runtime.md +++ b/docs/hk_equity_runtime.md @@ -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` 策略定义、运行入口和 LongBridge runtime adapter。 2. [`HkEquitySnapshotPipelines`](https://github.com/QuantStrategyLab/HkEquitySnapshotPipelines) 产出 snapshot-backed profile 的特征快照、manifest、ranking 和 release summary。 @@ -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` 前不会出现在平台可选列表: @@ -73,7 +73,7 @@ LONGBRIDGE_TRADING_CURRENCY=HKD ```bash python scripts/print_strategy_switch_env_plan.py \ - --profile hk_listed_global_etf_rotation \ + --profile hk_global_etf_tactical_rotation \ --account-region hk \ --dry-run-only \ --deployment-selector hk-verify \ @@ -84,7 +84,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`。 - `ACCOUNT_REGION=HK`、`ACCOUNT_PREFIX=HK`、`LONGBRIDGE_DRY_RUN_ONLY=true`。 - `LONGBRIDGE_MARKET=HK` / `XHKG` / `Asia/Hong_Kong` / `.HK` / `HKD`。 - `remove_if_present`:清理 snapshot/config 相关环境变量,因为该 profile 直接使用 `market_history`。 @@ -92,9 +92,9 @@ python scripts/print_strategy_switch_env_plan.py \ 打印计划不会直接修改服务配置;只有执行 Cloud Run env 更新/部署命令才会改变服务。 -## 生成 `hk_low_vol_dividend_quality` snapshot artifacts +## 生成 `hk_low_vol_dividend_quality_snapshot` snapshot artifacts -`hk_low_vol_dividend_quality` 是 snapshot-backed 策略,Cloud Run 切到这个 profile 前必须先有经过校验的 feature snapshot 和 manifest。`LongBridgePlatform` 提供一个手动桥接 workflow,使用本仓库已经允许的 `longbridge-hk` WIF 发布 artifact。默认数据源是 `public_yfinance_staging`,不依赖 LongBridge 历史行情权限;如果账号已开通对应 HK market-data entitlement,也可以切到 `longbridge_openapi_staging`。 +`hk_low_vol_dividend_quality_snapshot` 是 snapshot-backed 策略,Cloud Run 切到这个 profile 前必须先有经过校验的 feature snapshot 和 manifest。`LongBridgePlatform` 提供一个手动桥接 workflow,使用本仓库已经允许的 `longbridge-hk` WIF 发布 artifact。默认数据源是 `public_yfinance_staging`,不依赖 LongBridge 历史行情权限;如果账号已开通对应 HK market-data entitlement,也可以切到 `longbridge_openapi_staging`。 手动生成并只打印 GCS 发布计划: @@ -102,7 +102,7 @@ python scripts/print_strategy_switch_env_plan.py \ gh workflow run build-hk-low-vol-snapshot-artifacts.yml \ --repo QuantStrategyLab/LongBridgePlatform \ -f snapshot_ref=main \ - -f profile=hk_low_vol_dividend_quality \ + -f profile=hk_low_vol_dividend_quality_snapshot \ -f data_source_mode=public_yfinance_staging \ -f allow_research_defaults=false \ -f execute_publish=false @@ -114,20 +114,20 @@ gh workflow run build-hk-low-vol-snapshot-artifacts.yml \ gh workflow run build-hk-low-vol-snapshot-artifacts.yml \ --repo QuantStrategyLab/LongBridgePlatform \ -f snapshot_ref=main \ - -f profile=hk_low_vol_dividend_quality \ + -f profile=hk_low_vol_dividend_quality_snapshot \ -f data_source_mode=public_yfinance_staging \ -f allow_research_defaults=false \ - -f gcs_prefix=gs://qsl-runtime-logs-interactivebrokersquant/strategy-artifacts/hk_equity/hk_low_vol_dividend_quality \ + -f gcs_prefix=gs://qsl-runtime-logs-interactivebrokersquant/strategy-artifacts/hk_equity/hk_low_vol_dividend_quality_snapshot \ -f execute_publish=true ``` 发布后,HK dry-run runtime 需要至少配置: ```bash -STRATEGY_PROFILE=hk_low_vol_dividend_quality +STRATEGY_PROFILE=hk_low_vol_dividend_quality_snapshot LONGBRIDGE_DRY_RUN_ONLY=true -LONGBRIDGE_FEATURE_SNAPSHOT_PATH=gs://qsl-runtime-logs-interactivebrokersquant/strategy-artifacts/hk_equity/hk_low_vol_dividend_quality/hk_low_vol_dividend_quality_factor_snapshot_latest.csv -LONGBRIDGE_FEATURE_SNAPSHOT_MANIFEST_PATH=gs://qsl-runtime-logs-interactivebrokersquant/strategy-artifacts/hk_equity/hk_low_vol_dividend_quality/hk_low_vol_dividend_quality_factor_snapshot_latest.csv.manifest.json +LONGBRIDGE_FEATURE_SNAPSHOT_PATH=gs://qsl-runtime-logs-interactivebrokersquant/strategy-artifacts/hk_equity/hk_low_vol_dividend_quality_snapshot/hk_low_vol_dividend_quality_snapshot_factor_snapshot_latest.csv +LONGBRIDGE_FEATURE_SNAPSHOT_MANIFEST_PATH=gs://qsl-runtime-logs-interactivebrokersquant/strategy-artifacts/hk_equity/hk_low_vol_dividend_quality_snapshot/hk_low_vol_dividend_quality_snapshot_factor_snapshot_latest.csv.manifest.json ``` 注意:`allow_research_defaults=true` 只允许做研究 smoke,不允许发布到 GCS,也不能作为 live-enable 证据。public yfinance 数据源用于让 snapshot artifact 生成和券商执行解耦;它仍需要按策略证据包记录数据源、生成时间和 broker dry-run 结果。 @@ -137,7 +137,7 @@ LONGBRIDGE_FEATURE_SNAPSHOT_MANIFEST_PATH=gs://qsl-runtime-logs-interactivebroke 仓库的 `Deploy Cloud Run` workflow 支持手动 `workflow_dispatch` 目标 `hk-verify`。这个目标只启用 HK matrix deployment,PAPER / SG 会跳过,并设置或更新独立港股 dry-run 服务: - `CLOUD_RUN_SERVICE=longbridge-quant-hk-verify-service`(可通过输入改名) -- `STRATEGY_PROFILE=hk_listed_global_etf_rotation` +- `STRATEGY_PROFILE=hk_global_etf_tactical_rotation` - `ACCOUNT_REGION=HK`、`ACCOUNT_PREFIX=HK` - `RUNTIME_TARGET_JSON.execution_mode=paper`、`dry_run_only=true` - `LONGBRIDGE_DRY_RUN_ONLY=true` @@ -177,6 +177,6 @@ gh workflow run sync-cloud-run-env.yml \ ## 风险和注意事项 - `XHKG` 是否可用取决于部署环境里的 `pandas_market_calendars` 版本;如不可用,可用 `LONGBRIDGE_MARKET_CALENDAR` 临时覆盖。 -- `hk_listed_global_etf_rotation` 已在策略包 `runtime_enabled`,可由 LongBridge HK Cloud Run 通过运行时环境选择;`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation` 仍不进入平台可选列表。 +- `hk_global_etf_tactical_rotation` 已在策略包 `runtime_enabled`,可由 LongBridge HK Cloud Run 通过运行时环境选择;`hk_blue_chip_leader_rotation`、`hk_index_mean_reversion`、`hk_etf_regime_rotation` 仍不进入平台可选列表。 - 港股 `market_history` profile 运行后,需要持续用 LongBridge HK 行情 feed 对 `02800`、`03033`、`02822`、`02840`、`03110`、`03188`、`02834`、`03175` 做行情、价差、lot-size 和订单预览/执行结果复核。 - LongBridge 下单仍保持整数股规则;如果未来港股策略涉及碎股或特殊交易单位,需要在策略层明确 lot-size 约束后再扩展。 diff --git a/notifications/telegram.py b/notifications/telegram.py index b5eab5a..c1ab9eb 100644 --- a/notifications/telegram.py +++ b/notifications/telegram.py @@ -101,11 +101,8 @@ "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_name_hk_global_etf_tactical_rotation": "港股全球 ETF 战术轮动", - "strategy_name_hk_high_dividend_low_vol_trend": "港股高股息低波趋势", "strategy_name_hk_dividend_gold_defensive_rotation": "港股股息黄金防守轮动", - "strategy_name_hk_low_vol_dividend_quality": "港股低波股息质量", "strategy_name_hk_low_vol_dividend_quality_snapshot": "港股低波股息质量快照", "strategy_plugin_line": "🧩 插件:{plugin} | 状态:{route} | 提醒:{action}", "strategy_plugin_alert_subject": "🚨 策略插件告警:{plugin} | {route}", @@ -224,11 +221,8 @@ "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_name_hk_global_etf_tactical_rotation": "HK Global ETF Tactical Rotation", - "strategy_name_hk_high_dividend_low_vol_trend": "HK High Dividend Low-Volatility Trend", "strategy_name_hk_dividend_gold_defensive_rotation": "HK Dividend-Gold Defensive Rotation", - "strategy_name_hk_low_vol_dividend_quality": "HK Low-Volatility Dividend Quality", "strategy_name_hk_low_vol_dividend_quality_snapshot": "HK Low-Vol Dividend Quality Snapshot", "strategy_plugin_line": "🧩 Plugin: {plugin} | status: {route} | notice: {action}", "strategy_plugin_alert_subject": "🚨 Strategy plugin alert: {plugin} | {route}", diff --git a/requirements.txt b/requirements.txt index a96b3c6..9327b80 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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-runtime-adapter-kwargs +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 requests pytz diff --git a/scripts/print_strategy_profile_status.py b/scripts/print_strategy_profile_status.py index 71e0c4e..8767560 100644 --- a/scripts/print_strategy_profile_status.py +++ b/scripts/print_strategy_profile_status.py @@ -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 diff --git a/scripts/print_strategy_switch_env_plan.py b/scripts/print_strategy_switch_env_plan.py index 882e8d9..f9b33f8 100644 --- a/scripts/print_strategy_switch_env_plan.py +++ b/scripts/print_strategy_switch_env_plan.py @@ -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 diff --git a/tests/test_notifications.py b/tests/test_notifications.py index 5ef63a3..8425171 100644 --- a/tests/test_notifications.py +++ b/tests/test_notifications.py @@ -108,10 +108,10 @@ 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") - self.assertEqual(zh_name("hk_high_dividend_low_vol_trend"), "港股高股息低波趋势") - self.assertEqual(en_name("hk_high_dividend_low_vol_trend"), "HK High Dividend Low-Volatility Trend") + self.assertEqual(zh_name("hk_global_etf_tactical_rotation"), "港股全球 ETF 战术轮动") + self.assertEqual(en_name("hk_global_etf_tactical_rotation"), "HK Global ETF Tactical Rotation") + self.assertEqual(zh_name("hk_dividend_gold_defensive_rotation"), "港股股息黄金防守轮动") + self.assertEqual(en_name("hk_dividend_gold_defensive_rotation"), "HK Dividend-Gold Defensive Rotation") for profile in SUPPORTED_STRATEGY_PROFILES: self.assertNotEqual(zh_name(profile), profile) diff --git a/tests/test_rebalance_service.py b/tests/test_rebalance_service.py index bb3031b..0f2d170 100644 --- a/tests/test_rebalance_service.py +++ b/tests/test_rebalance_service.py @@ -312,7 +312,7 @@ def test_execute_rebalance_cycle_hk_dry_run_uses_hk_suffix_without_broker_submit estimated_symbols = [] prices = {"02800.HK": 30.0, "03033.HK": 20.0} plan = _build_plan( - strategy_profile="hk_listed_global_etf_rotation", + strategy_profile="hk_global_etf_tactical_rotation", strategy_symbols=("02800", "03033"), risk_symbols=("02800", "03033"), targets={"02800": 90000.0, "03033": 70000.0}, diff --git a/tests/test_request_handling.py b/tests/test_request_handling.py index 80b6e65..0f01f42 100644 --- a/tests/test_request_handling.py +++ b/tests/test_request_handling.py @@ -608,7 +608,7 @@ def test_notification_delivery_log_summary_records_sent_dry_run_without_raw_text payload = module._build_notification_delivery_log_for_report( platform="longbridge", - 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, @@ -626,7 +626,7 @@ def test_notification_delivery_log_summary_records_sent_dry_run_without_raw_text self.assertEqual(payload["notification_event_type"], "hk_snapshot_live_enablement_dry_run") self.assertEqual(payload["notification_correlation_id"], "run-001") self.assertEqual(payload["locales"], ["en", "zh-Hans"]) - self.assertEqual(payload["profile"], "hk_low_vol_dividend_quality") + self.assertEqual(payload["profile"], "hk_low_vol_dividend_quality_snapshot") self.assertEqual(payload["platform"], "longbridge") self.assertEqual(payload["orders_previewed"], 2) self.assertTrue(payload["notification_redacts_sensitive_fields"]) @@ -637,7 +637,7 @@ def test_notification_delivery_log_summary_stays_empty_without_sent_event(self): payload = module._build_notification_delivery_log_for_report( platform="longbridge", - 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, diff --git a/tests/test_runtime_config_support.py b/tests/test_runtime_config_support.py index ba375f7..430a920 100644 --- a/tests/test_runtime_config_support.py +++ b/tests/test_runtime_config_support.py @@ -63,9 +63,9 @@ OPTIONAL_LONGBRIDGE_PROFILES = frozenset({"global_etf_confidence_vol_gate"}) HK_RUNTIME_ENABLED_PROFILES = frozenset( { - "hk_high_dividend_low_vol_trend", - "hk_listed_global_etf_rotation", - "hk_low_vol_dividend_quality", + "hk_dividend_gold_defensive_rotation", + "hk_global_etf_tactical_rotation", + "hk_low_vol_dividend_quality_snapshot", } ) HK_DISABLED_PROFILES = frozenset( @@ -605,10 +605,10 @@ def test_platform_profile_status_matrix_matches_current_longbridge_rollout(self) "Mega Cap Leader Rotation Top50 Balanced", ) self.assertEqual( - by_profile["hk_listed_global_etf_rotation"], + by_profile["hk_global_etf_tactical_rotation"], { - "canonical_profile": "hk_listed_global_etf_rotation", - "display_name": "HK-listed Global ETF Rotation", + "canonical_profile": "hk_global_etf_tactical_rotation", + "display_name": "HK Global ETF Tactical Rotation", "domain": "hk_equity", "eligible": True, "enabled": True, @@ -616,10 +616,10 @@ def test_platform_profile_status_matrix_matches_current_longbridge_rollout(self) }, ) self.assertEqual( - by_profile["hk_high_dividend_low_vol_trend"], + by_profile["hk_dividend_gold_defensive_rotation"], { - "canonical_profile": "hk_high_dividend_low_vol_trend", - "display_name": "HK High Dividend Low-Volatility Trend", + "canonical_profile": "hk_dividend_gold_defensive_rotation", + "display_name": "HK Dividend-Gold Defensive Rotation", "domain": "hk_equity", "eligible": True, "enabled": True, @@ -663,8 +663,8 @@ def test_rejects_disabled_hk_profiles(self): def test_accepts_runtime_enabled_hk_profiles(self): expected_names = { - "hk_listed_global_etf_rotation": "HK-listed Global ETF Rotation", - "hk_high_dividend_low_vol_trend": "HK High Dividend Low-Volatility Trend", + "hk_global_etf_tactical_rotation": "HK Global ETF Tactical Rotation", + "hk_dividend_gold_defensive_rotation": "HK Dividend-Gold Defensive Rotation", } for profile, display_name in expected_names.items(): with self.subTest(profile=profile): @@ -749,17 +749,17 @@ def test_print_strategy_profile_status_json_matches_registry(self): self.assertFalse(by_profile["mega_cap_leader_rotation_top50_balanced"]["requires_strategy_config_path"]) for profile in ("hk_index_mean_reversion", "hk_etf_regime_rotation", "hk_blue_chip_leader_rotation"): self.assertNotIn(profile, by_profile) - for profile in HK_RUNTIME_ENABLED_PROFILES - {"hk_low_vol_dividend_quality"}: + for profile in HK_RUNTIME_ENABLED_PROFILES - {"hk_low_vol_dividend_quality_snapshot"}: self.assertEqual(by_profile[profile]["profile_group"], "direct_runtime_inputs") self.assertEqual(by_profile[profile]["input_mode"], "market_history") self.assertFalse(by_profile[profile]["requires_snapshot_artifacts"]) self.assertFalse(by_profile[profile]["requires_snapshot_manifest_path"]) self.assertFalse(by_profile[profile]["requires_strategy_config_path"]) - self.assertEqual(by_profile["hk_low_vol_dividend_quality"]["profile_group"], "snapshot_backed") - self.assertEqual(by_profile["hk_low_vol_dividend_quality"]["input_mode"], "feature_snapshot") - self.assertTrue(by_profile["hk_low_vol_dividend_quality"]["requires_snapshot_artifacts"]) - self.assertTrue(by_profile["hk_low_vol_dividend_quality"]["requires_snapshot_manifest_path"]) - self.assertFalse(by_profile["hk_low_vol_dividend_quality"]["requires_strategy_config_path"]) + self.assertEqual(by_profile["hk_low_vol_dividend_quality_snapshot"]["profile_group"], "snapshot_backed") + self.assertEqual(by_profile["hk_low_vol_dividend_quality_snapshot"]["input_mode"], "feature_snapshot") + self.assertTrue(by_profile["hk_low_vol_dividend_quality_snapshot"]["requires_snapshot_artifacts"]) + self.assertTrue(by_profile["hk_low_vol_dividend_quality_snapshot"]["requires_snapshot_manifest_path"]) + self.assertFalse(by_profile["hk_low_vol_dividend_quality_snapshot"]["requires_strategy_config_path"]) self.assertFalse( by_profile["russell_1000_multi_factor_defensive"]["requires_strategy_config_path"] ) @@ -779,12 +779,12 @@ def test_print_strategy_profile_status_table_contains_expected_headers(self): self.assertIn("requires_snapshot_artifacts", result.stdout) self.assertIn("soxl_soxx_trend_income", result.stdout) self.assertIn("global_etf_rotation", result.stdout) - self.assertIn("hk_listed_global_etf_rotation", result.stdout) - self.assertIn("hk_high_dividend_low_vol_trend", result.stdout) + self.assertIn("hk_global_etf_tactical_rotation", result.stdout) + self.assertIn("hk_dividend_gold_defensive_rotation", result.stdout) self.assertIn("russell_1000_multi_factor_defensive", result.stdout) self.assertIn("Global ETF Rotation", result.stdout) - self.assertIn("HK-listed Global ETF Rotation", result.stdout) - self.assertIn("HK High Dividend Low-Volatility Trend", result.stdout) + self.assertIn("HK Global ETF Tactical Rotation", result.stdout) + self.assertIn("HK Dividend-Gold Defensive Rotation", result.stdout) self.assertIn("Russell 1000 Multi-Factor", result.stdout) self.assertIn("Mega Cap Leader Rotation Top50 Balanced", result.stdout) self.assertNotIn("Tech/Communication Pullback Enhancement", result.stdout) @@ -839,7 +839,7 @@ def test_print_strategy_switch_env_plan_for_hk_global_etf_dry_run(self): sys.executable, str(SWITCH_PLAN_SCRIPT_PATH), "--profile", - "hk_listed_global_etf_rotation", + "hk_global_etf_tactical_rotation", "--account-region", "hk", "--dry-run-only", @@ -858,7 +858,7 @@ def test_print_strategy_switch_env_plan_for_hk_global_etf_dry_run(self): plan = json.loads(result.stdout) self.assertEqual(plan["platform"], "longbridge") - self.assertEqual(plan["canonical_profile"], "hk_listed_global_etf_rotation") + self.assertEqual(plan["canonical_profile"], "hk_global_etf_tactical_rotation") self.assertEqual(plan["domain"], HK_EQUITY_DOMAIN) self.assertEqual(plan["set_env"]["ACCOUNT_REGION"], "HK") self.assertEqual(plan["set_env"]["ACCOUNT_PREFIX"], "HK") @@ -989,13 +989,13 @@ def test_print_strategy_switch_env_plan_for_mega_cap_top50_balanced(self): "mega_cap_leader_rotation_top50_balanced_feature_snapshot_latest.csv", ) - def test_print_strategy_switch_env_plan_for_hk_low_vol_dividend_quality(self): + def test_print_strategy_switch_env_plan_for_hk_low_vol_dividend_quality_snapshot(self): result = subprocess.run( [ sys.executable, str(SWITCH_PLAN_SCRIPT_PATH), "--profile", - "hk_low_vol_dividend_quality", + "hk_low_vol_dividend_quality_snapshot", "--account-region", "hk", "--dry-run-only", @@ -1007,21 +1007,21 @@ def test_print_strategy_switch_env_plan_for_hk_low_vol_dividend_quality(self): ) plan = json.loads(result.stdout) - self.assertEqual(plan["canonical_profile"], "hk_low_vol_dividend_quality") + self.assertEqual(plan["canonical_profile"], "hk_low_vol_dividend_quality_snapshot") self.assertTrue(plan["enabled"]) self.assertEqual(plan["profile_group"], "snapshot_backed") self.assertEqual(plan["input_mode"], "feature_snapshot") - self.assertEqual(plan["snapshot_contract_version"], "hk_low_vol_dividend_quality.factor_snapshot.v1") + self.assertEqual(plan["snapshot_contract_version"], "hk_low_vol_dividend_quality_snapshot.factor_snapshot.v1") self.assertEqual(plan["set_env"]["LONGBRIDGE_DRY_RUN_ONLY"], "true") self.assertEqual(plan["set_env"]["LONGBRIDGE_FEATURE_SNAPSHOT_PATH"], "") self.assertEqual(plan["set_env"]["LONGBRIDGE_FEATURE_SNAPSHOT_MANIFEST_PATH"], "") self.assertEqual( plan["hints"]["feature_snapshot_filename"], - "hk_low_vol_dividend_quality_factor_snapshot_latest.csv", + "hk_low_vol_dividend_quality_snapshot_factor_snapshot_latest.csv", ) self.assertEqual( plan["hints"]["feature_snapshot_manifest_filename"], - "hk_low_vol_dividend_quality_factor_snapshot_latest.csv.manifest.json", + "hk_low_vol_dividend_quality_snapshot_factor_snapshot_latest.csv.manifest.json", ) def test_print_strategy_switch_env_plan_rejects_hk_disabled_profiles(self): diff --git a/tests/test_runtime_strategy_adapters.py b/tests/test_runtime_strategy_adapters.py index 4a47998..f60949b 100644 --- a/tests/test_runtime_strategy_adapters.py +++ b/tests/test_runtime_strategy_adapters.py @@ -84,7 +84,7 @@ def load_market_history(_broker_client, symbol): adapters = build_runtime_strategy_adapters( strategy_runtime=SimpleNamespace(evaluate=lambda **_kwargs: None), - strategy_profile="hk_listed_global_etf_rotation", + strategy_profile="hk_global_etf_tactical_rotation", strategy_runtime_config={"universe_symbols": ("02800", "02834")}, available_inputs=("market_history",), benchmark_symbol="QQQ", diff --git a/tests/test_sync_cloud_run_env_workflow.sh b/tests/test_sync_cloud_run_env_workflow.sh index 0d8baab..11a79f0 100644 --- a/tests/test_sync_cloud_run_env_workflow.sh +++ b/tests/test_sync_cloud_run_env_workflow.sh @@ -17,7 +17,7 @@ grep -Fq -- '- hk-verify' "$workflow_file" grep -Fq 'INPUT_DEPLOY_IMAGE: ${{ inputs.deploy_image }}' "$workflow_file" grep -Fq 'Apply HK verify-only dispatch defaults' "$workflow_file" grep -Fq 'hk-verify targets only the HK deployment' "$workflow_file" -grep -Fq '"strategy_profile": "hk_listed_global_etf_rotation"' "$workflow_file" +grep -Fq '"strategy_profile": "hk_global_etf_tactical_rotation"' "$workflow_file" grep -Fq 'echo "LONGBRIDGE_DRY_RUN_ONLY=true"' "$workflow_file" grep -Fq 'echo "LONGBRIDGE_MARKET=HK"' "$workflow_file" grep -Fq 'echo "LONGBRIDGE_SYMBOL_SUFFIX=.HK"' "$workflow_file"