From dafd8130312adcf8db130bf8bf6933a5836c0ddf Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Fri, 17 Apr 2026 22:32:04 +0800 Subject: [PATCH 1/2] Add top50 balanced profile support --- README.md | 10 ++++--- notifications/telegram.py | 2 ++ tests/test_runtime_config_support.py | 44 ++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 35a8b93..27aa1df 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,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 LongBridge runtime can execute all eight live `us_equity` profiles from `UsEquityStrategies`; `LongBridgePlatform` keeps the LongPort runtime, token refresh, execution, and notification flow. +The LongBridge runtime can execute all nine live `us_equity` profiles from `UsEquityStrategies`; `LongBridgePlatform` keeps the LongPort runtime, token refresh, execution, and notification flow. Full strategy documentation now lives in [`UsEquityStrategies`](https://github.com/QuantStrategyLab/UsEquityStrategies). The sections below focus on LongBridge runtime behavior, profile enablement, deployment, and credentials. This runtime matrix is the authoritative enablement source for LongBridge. `UsEquityStrategies` carries strategy-layer logic, cadence, compatibility, and metadata. @@ -35,6 +35,7 @@ Platform execution no longer depends on `strategy/allocation.py` or hard-coded s | `russell_1000_multi_factor_defensive` | Russell 1000 Multi-Factor | Yes | Yes | `us_equity` | enabled feature-snapshot stock baseline | | `mega_cap_leader_rotation_aggressive` | Mega Cap Leader Rotation Aggressive | Yes | Yes | `us_equity` | selectable aggressive monthly feature-snapshot leader rotation | | `mega_cap_leader_rotation_dynamic_top20` | Mega Cap Leader Rotation Dynamic Top20 | Yes | Yes | `us_equity` | selectable monthly feature-snapshot leader rotation | +| `mega_cap_leader_rotation_top50_balanced` | Mega Cap Leader Rotation Top50 Balanced | Yes | Yes | `us_equity` | selectable balanced Top50 monthly leader rotation | | `dynamic_mega_leveraged_pullback` | Dynamic Mega Leveraged Pullback | Yes | Yes | `us_equity` | selectable 2x mega-cap pullback line | | `soxl_soxx_trend_income` | SOXL/SOXX Semiconductor Trend Income | Yes | Yes | `us_equity` | current SG deployment | | `tqqq_growth_income` | TQQQ Growth Income | Yes | Yes | `us_equity` | selectable growth line | @@ -64,7 +65,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-hk` / `longport-app-secret-sg` | | `LONGPORT_SECRET_NAME` | No | Secret Manager secret name for LongPort token (default: `longport_token_hk`) | | `ACCOUNT_PREFIX` | No | Alert/log prefix for account/environment (default: `DEFAULT`) | -| `STRATEGY_PROFILE` | Yes | Strategy profile selector. Set explicitly per deployment; enabled values include `dynamic_mega_leveraged_pullback`, `global_etf_rotation`, `mega_cap_leader_rotation_aggressive`, `mega_cap_leader_rotation_dynamic_top20`, `russell_1000_multi_factor_defensive`, `soxl_soxx_trend_income`, `tech_communication_pullback_enhancement`, and `tqqq_growth_income` | +| `STRATEGY_PROFILE` | Yes | Strategy profile selector. Set explicitly per deployment; enabled values include `dynamic_mega_leveraged_pullback`, `global_etf_rotation`, `mega_cap_leader_rotation_aggressive`, `mega_cap_leader_rotation_dynamic_top20`, `mega_cap_leader_rotation_top50_balanced`, `russell_1000_multi_factor_defensive`, `soxl_soxx_trend_income`, `tech_communication_pullback_enhancement`, and `tqqq_growth_income` | | `ACCOUNT_REGION` | No | Account region marker for platform-style deployment (e.g. `HK`, `SG`; defaults to `ACCOUNT_PREFIX` / `DEFAULT`) | | `LONGBRIDGE_DRY_RUN_ONLY` | No | Set to `true` to keep the selected deployment in dry-run mode. | | `INCOME_THRESHOLD_USD` | No | Optional override for the `tqqq_growth_income` income-layer threshold. Leave unset to use the strategy package default. | @@ -158,7 +159,7 @@ IAM: the Cloud Run service account needs **Secret Manager Admin** (or Secret Acc 基于 LongPort OpenAPI 和 Google Cloud Run 的量化交易系统。 这个仓库通过 `QuantPlatformKit` 复用 LongPort token 处理、上下文初始化、账户快照、行情读取和下单逻辑。Cloud Run 直接部署这个仓库。 -`LongBridgePlatform` 现在可直接执行 `UsEquityStrategies` 里的全部 8 条 live `us_equity` 策略:`dynamic_mega_leveraged_pullback`、`global_etf_rotation`、`mega_cap_leader_rotation_aggressive`、`mega_cap_leader_rotation_dynamic_top20`、`russell_1000_multi_factor_defensive`、`soxl_soxx_trend_income`、`tqqq_growth_income` 和 `tech_communication_pullback_enhancement`;仓库本身继续保留 LongPort 运行时、token 刷新、执行和通知流程。 +`LongBridgePlatform` 现在可直接执行 `UsEquityStrategies` 里的全部 9 条 live `us_equity` 策略:`dynamic_mega_leveraged_pullback`、`global_etf_rotation`、`mega_cap_leader_rotation_aggressive`、`mega_cap_leader_rotation_dynamic_top20`、`mega_cap_leader_rotation_top50_balanced`、`russell_1000_multi_factor_defensive`、`soxl_soxx_trend_income`、`tqqq_growth_income` 和 `tech_communication_pullback_enhancement`;仓库本身继续保留 LongPort 运行时、token 刷新、执行和通知流程。 完整策略说明现在放在 [`UsEquityStrategies`](https://github.com/QuantStrategyLab/UsEquityStrategies)。下面这些章节只保留 LongBridge 运行时、profile 启用状态、部署和凭据说明。 @@ -181,6 +182,7 @@ IAM: the Cloud Run service account needs **Secret Manager Admin** (or Secret Acc | `russell_1000_multi_factor_defensive` | Russell 1000 Multi-Factor | Yes | Yes | `us_equity` | 已启用的 feature-snapshot 个股基线 | | `mega_cap_leader_rotation_aggressive` | Mega Cap Leader Rotation Aggressive | Yes | Yes | `us_equity` | 可选的激进月度 feature-snapshot 龙头轮动线 | | `mega_cap_leader_rotation_dynamic_top20` | Mega Cap Leader Rotation Dynamic Top20 | Yes | Yes | `us_equity` | 可选的月度 feature-snapshot 龙头轮动线 | +| `mega_cap_leader_rotation_top50_balanced` | Mega Cap Leader Rotation Top50 Balanced | Yes | Yes | `us_equity` | 可选的 Top50 平衡月度龙头轮动线 | | `dynamic_mega_leveraged_pullback` | Dynamic Mega Leveraged Pullback | Yes | Yes | `us_equity` | 可选的 2x 龙头回调线 | | `soxl_soxx_trend_income` | SOXL/SOXX 半导体趋势收益 | Yes | Yes | `us_equity` | 当前 SG 部署线路 | | `tqqq_growth_income` | TQQQ 增长收益 | Yes | Yes | `us_equity` | 可选增长线路 | @@ -210,7 +212,7 @@ Telegram 通知包含结构化的调仓和心跳消息,支持中英文切换 | `LONGPORT_APP_SECRET` | 是 | LongPort OpenAPI 应用密钥(用于刷新 Token);建议从当前部署对应区域的 Secret Manager 密钥注入,例如 `longport-app-secret-hk` / `longport-app-secret-sg` | | `LONGPORT_SECRET_NAME` | 否 | Secret Manager 中的密钥名称(默认: `longport_token_hk`) | | `ACCOUNT_PREFIX` | 否 | 通知/日志前缀,区分账户环境(默认: `DEFAULT`) | -| `STRATEGY_PROFILE` | 是 | 策略档位选择。每个部署都要显式设置;已启用值包括 `dynamic_mega_leveraged_pullback`、`global_etf_rotation`、`mega_cap_leader_rotation_aggressive`、`mega_cap_leader_rotation_dynamic_top20`、`russell_1000_multi_factor_defensive`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement` 和 `tqqq_growth_income` | +| `STRATEGY_PROFILE` | 是 | 策略档位选择。每个部署都要显式设置;已启用值包括 `dynamic_mega_leveraged_pullback`、`global_etf_rotation`、`mega_cap_leader_rotation_aggressive`、`mega_cap_leader_rotation_dynamic_top20`、`mega_cap_leader_rotation_top50_balanced`、`russell_1000_multi_factor_defensive`、`soxl_soxx_trend_income`、`tech_communication_pullback_enhancement` 和 `tqqq_growth_income` | | `ACCOUNT_REGION` | 否 | 平台化部署时的账户区域标记(如 `HK`、`SG`;默认按 `ACCOUNT_PREFIX` / `DEFAULT` 推断) | | `LONGBRIDGE_DRY_RUN_ONLY` | 否 | 设为 `true` 时,该部署保持 dry-run。 | | `INCOME_THRESHOLD_USD` | 否 | 可选的 `tqqq_growth_income` 收入层启动阈值覆盖。不填时使用策略包默认值。 | diff --git a/notifications/telegram.py b/notifications/telegram.py index fccf3ca..2bb42f1 100644 --- a/notifications/telegram.py +++ b/notifications/telegram.py @@ -77,6 +77,7 @@ "strategy_name_qqq_tech_enhancement": "科技通信回调增强", "strategy_name_mega_cap_leader_rotation_aggressive": "Mega Cap 激进龙头轮动", "strategy_name_mega_cap_leader_rotation_dynamic_top20": "Mega Cap 动态 Top20 龙头轮动", + "strategy_name_mega_cap_leader_rotation_top50_balanced": "Mega Cap Top50 平衡龙头轮动", "strategy_name_dynamic_mega_leveraged_pullback": "Mega Cap 2x 回调策略", }, "en": { @@ -141,6 +142,7 @@ "strategy_name_qqq_tech_enhancement": "Tech/Communication Pullback Enhancement", "strategy_name_mega_cap_leader_rotation_aggressive": "Mega Cap Leader Rotation Aggressive", "strategy_name_mega_cap_leader_rotation_dynamic_top20": "Mega Cap Leader Rotation Dynamic Top20", + "strategy_name_mega_cap_leader_rotation_top50_balanced": "Mega Cap Leader Rotation Top50 Balanced", "strategy_name_dynamic_mega_leveraged_pullback": "Dynamic Mega Leveraged Pullback", }, } diff --git a/tests/test_runtime_config_support.py b/tests/test_runtime_config_support.py index d9abd18..5c1b063 100644 --- a/tests/test_runtime_config_support.py +++ b/tests/test_runtime_config_support.py @@ -71,6 +71,7 @@ def test_platform_supported_profiles_are_filtered_by_registry(self): "global_etf_rotation", "mega_cap_leader_rotation_aggressive", "mega_cap_leader_rotation_dynamic_top20", + "mega_cap_leader_rotation_top50_balanced", "russell_1000_multi_factor_defensive", "tqqq_growth_income", "soxl_soxx_trend_income", @@ -88,6 +89,7 @@ def test_platform_eligible_profiles_are_exposed_by_capability_matrix(self): "global_etf_rotation", "mega_cap_leader_rotation_aggressive", "mega_cap_leader_rotation_dynamic_top20", + "mega_cap_leader_rotation_top50_balanced", "russell_1000_multi_factor_defensive", "tqqq_growth_income", "soxl_soxx_trend_income", @@ -180,6 +182,7 @@ def test_platform_profile_status_matrix_matches_current_longbridge_rollout(self) "dynamic_mega_leveraged_pullback", "mega_cap_leader_rotation_aggressive", "mega_cap_leader_rotation_dynamic_top20", + "mega_cap_leader_rotation_top50_balanced", "russell_1000_multi_factor_defensive", "tqqq_growth_income", "soxl_soxx_trend_income", @@ -213,6 +216,12 @@ def test_platform_profile_status_matrix_matches_current_longbridge_rollout(self) self.assertTrue(by_profile["mega_cap_leader_rotation_dynamic_top20"]["eligible"]) self.assertTrue(by_profile["mega_cap_leader_rotation_dynamic_top20"]["enabled"]) self.assertEqual(by_profile["mega_cap_leader_rotation_dynamic_top20"]["display_name"], "Mega Cap Leader Rotation Dynamic Top20") + self.assertTrue(by_profile["mega_cap_leader_rotation_top50_balanced"]["eligible"]) + self.assertTrue(by_profile["mega_cap_leader_rotation_top50_balanced"]["enabled"]) + self.assertEqual( + by_profile["mega_cap_leader_rotation_top50_balanced"]["display_name"], + "Mega Cap Leader Rotation Top50 Balanced", + ) self.assertTrue(by_profile["mega_cap_leader_rotation_aggressive"]["eligible"]) self.assertTrue(by_profile["mega_cap_leader_rotation_aggressive"]["enabled"]) self.assertEqual(by_profile["mega_cap_leader_rotation_aggressive"]["display_name"], "Mega Cap Leader Rotation Aggressive") @@ -300,6 +309,10 @@ def test_print_strategy_profile_status_json_matches_registry(self): self.assertEqual(by_profile["mega_cap_leader_rotation_dynamic_top20"]["input_mode"], "feature_snapshot") self.assertTrue(by_profile["mega_cap_leader_rotation_dynamic_top20"]["requires_snapshot_artifacts"]) self.assertFalse(by_profile["mega_cap_leader_rotation_dynamic_top20"]["requires_strategy_config_path"]) + self.assertEqual(by_profile["mega_cap_leader_rotation_top50_balanced"]["profile_group"], "snapshot_backed") + self.assertEqual(by_profile["mega_cap_leader_rotation_top50_balanced"]["input_mode"], "feature_snapshot") + self.assertTrue(by_profile["mega_cap_leader_rotation_top50_balanced"]["requires_snapshot_artifacts"]) + self.assertFalse(by_profile["mega_cap_leader_rotation_top50_balanced"]["requires_strategy_config_path"]) self.assertEqual(by_profile["dynamic_mega_leveraged_pullback"]["profile_group"], "snapshot_backed") self.assertEqual( by_profile["dynamic_mega_leveraged_pullback"]["input_mode"], @@ -425,6 +438,37 @@ def test_print_strategy_switch_env_plan_for_mega_cap_dynamic_top20(self): "mega_cap_leader_rotation_dynamic_top20_feature_snapshot_latest.csv", ) + def test_print_strategy_switch_env_plan_for_mega_cap_top50_balanced(self): + result = subprocess.run( + [ + sys.executable, + str(SWITCH_PLAN_SCRIPT_PATH), + "--profile", + "mega_cap_leader_rotation_top50_balanced", + "--account-region", + "hk", + "--json", + ], + check=True, + capture_output=True, + text=True, + ) + + plan = json.loads(result.stdout) + self.assertEqual(plan["canonical_profile"], "mega_cap_leader_rotation_top50_balanced") + self.assertEqual(plan["set_env"]["ACCOUNT_REGION"], "HK") + self.assertEqual(plan["set_env"]["ACCOUNT_PREFIX"], "HK") + self.assertEqual(plan["profile_group"], "snapshot_backed") + self.assertEqual(plan["input_mode"], "feature_snapshot") + self.assertTrue(plan["requires_snapshot_artifacts"]) + self.assertFalse(plan["requires_strategy_config_path"]) + 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"], + "mega_cap_leader_rotation_top50_balanced_feature_snapshot_latest.csv", + ) + def test_print_strategy_switch_env_plan_for_dynamic_mega_leveraged_pullback_sg(self): result = subprocess.run( [ From 97500e62df5a542114f8764dd9247a740002a6f2 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Fri, 17 Apr 2026 22:43:12 +0800 Subject: [PATCH 2/2] Translate small account warning notes --- notifications/telegram.py | 4 ++++ tests/test_notifications.py | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/notifications/telegram.py b/notifications/telegram.py index 2bb42f1..d5025a3 100644 --- a/notifications/telegram.py +++ b/notifications/telegram.py @@ -36,6 +36,8 @@ "order_filled": "✅ 订单成交 | {symbol} {side} {qty}股 均价 ${price}(订单号: {order_id})", "order_partial": "⚠️ 订单部分成交 | {symbol} {side} 已成交 {executed}/{qty}股 均价 ${price}(订单号: {order_id})", "order_error": "❌ 订单异常 | {symbol} {side} {qty}股 已{status}(订单号: {order_id})原因: {reason}", + "small_account_warning_note": "小账户提示:净值 {portfolio_equity} 低于建议 {min_recommended_equity};{reason}", + "small_account_warning_reason_integer_shares_min_position_value_may_prevent_backtest_replication": "整数股和最小仓位限制可能导致实盘无法完全复现回测", "order_id_suffix": "(订单号: {order_id})", "error_title": "🚨 【策略异常】", "buy_skipped": "⚪️ [买入跳过] {detail}", @@ -101,6 +103,8 @@ "order_filled": "✅ Order Filled | {symbol} {side} {qty} shares avg ${price} (ID: {order_id})", "order_partial": "⚠️ Partial Fill | {symbol} {side} filled {executed}/{qty} shares avg ${price} (ID: {order_id})", "order_error": "❌ Order Error | {symbol} {side} {qty} shares {status} (ID: {order_id}) reason: {reason}", + "small_account_warning_note": "small account warning: portfolio equity {portfolio_equity} is below recommended {min_recommended_equity}; {reason}", + "small_account_warning_reason_integer_shares_min_position_value_may_prevent_backtest_replication": "integer-share minimum position sizing may prevent backtest replication", "order_id_suffix": "[order_id={order_id}]", "error_title": "🚨 【Strategy Error】", "buy_skipped": "⚪️ [Buy skipped] {detail}", diff --git a/tests/test_notifications.py b/tests/test_notifications.py index 4170de6..e9fede5 100644 --- a/tests/test_notifications.py +++ b/tests/test_notifications.py @@ -41,6 +41,17 @@ def test_build_translator_supports_chinese(self): ), "SOXX 站上 140 日门槛线,持有 SOXL 70.0% + SOXX 20.0%", ) + self.assertEqual( + translate( + "small_account_warning_note", + portfolio_equity="$0", + min_recommended_equity="$1,000", + reason=translate( + "small_account_warning_reason_integer_shares_min_position_value_may_prevent_backtest_replication" + ), + ), + "小账户提示:净值 $0 低于建议 $1,000;整数股和最小仓位限制可能导致实盘无法完全复现回测", + ) def test_build_strategy_display_name_supports_i18n(self): zh_translate = build_translator("zh")