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
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 |
Expand Down Expand Up @@ -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. |
Expand Down Expand Up @@ -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 启用状态、部署和凭据说明。

Expand All @@ -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` | 可选增长线路 |
Expand Down Expand Up @@ -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` 收入层启动阈值覆盖。不填时使用策略包默认值。 |
Expand Down
6 changes: 6 additions & 0 deletions notifications/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}",
Expand Down Expand Up @@ -77,6 +79,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": {
Expand All @@ -100,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}",
Expand Down Expand Up @@ -141,6 +146,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",
},
}
Expand Down
11 changes: 11 additions & 0 deletions tests/test_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
44 changes: 44 additions & 0 deletions tests/test_runtime_config_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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"],
Expand Down Expand Up @@ -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"], "<required>")
self.assertEqual(plan["set_env"]["LONGBRIDGE_FEATURE_SNAPSHOT_MANIFEST_PATH"], "<required>")
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(
[
Expand Down