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: 1 addition & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ Platform execution no longer depends on `strategy/allocation.py` or hard-coded s
| `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 |
| `tech_communication_pullback_enhancement` | Tech/Communication Pullback Enhancement | Yes | Yes | `us_equity` | current HK feature-snapshot line |
| `mega_cap_leader_rotation_aggressive` | Mega Cap Leader Rotation Aggressive | Yes | No | `us_equity` | research-only archive |
| `mega_cap_leader_rotation_dynamic_top20` | Mega Cap Leader Rotation Dynamic Top20 | Yes | No | `us_equity` | research-only archive |
| `dynamic_mega_leveraged_pullback` | Dynamic Mega Leveraged Pullback | Yes | No | `us_equity` | research-only archive |

Check the current matrix locally:

Expand Down Expand Up @@ -160,7 +157,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` 里的 6 条 `runtime_enabled` `us_equity` 策略:`global_etf_rotation`、`mega_cap_leader_rotation_top50_balanced`、`russell_1000_multi_factor_defensive`、`soxl_soxx_trend_income`、`tqqq_growth_income` 和 `tech_communication_pullback_enhancement`;`dynamic_mega_leveraged_pullback`、`mega_cap_leader_rotation_aggressive`、`mega_cap_leader_rotation_dynamic_top20` 保留为 research-only 存档,不进入 LongBridge rollout。仓库本身继续保留 LongPort 运行时、token 刷新、执行和通知流程。
`LongBridgePlatform` 现在可直接执行 `UsEquityStrategies` 里的 6 条 `runtime_enabled` `us_equity` 策略:`global_etf_rotation`、`mega_cap_leader_rotation_top50_balanced`、`russell_1000_multi_factor_defensive`、`soxl_soxx_trend_income`、`tqqq_growth_income` 和 `tech_communication_pullback_enhancement`。较弱或重复的研究 profile 已从 LongBridge 可配置入口移除。仓库本身继续保留 LongPort 运行时、token 刷新、执行和通知流程。

完整策略说明现在放在 [`UsEquityStrategies`](https://github.com/QuantStrategyLab/UsEquityStrategies)。下面这些章节只保留 LongBridge 运行时、profile 启用状态、部署和凭据说明。

Expand All @@ -185,9 +182,6 @@ IAM: the Cloud Run service account needs **Secret Manager Admin** (or Secret Acc
| `soxl_soxx_trend_income` | SOXL/SOXX 半导体趋势收益 | Yes | Yes | `us_equity` | 当前 SG 部署线路 |
| `tqqq_growth_income` | TQQQ 增长收益 | Yes | Yes | `us_equity` | 可选增长线路 |
| `tech_communication_pullback_enhancement` | 科技通信回调增强 | Yes | Yes | `us_equity` | 当前 HK feature-snapshot 线路 |
| `mega_cap_leader_rotation_aggressive` | Mega Cap Leader Rotation Aggressive | Yes | No | `us_equity` | research-only 存档 |
| `mega_cap_leader_rotation_dynamic_top20` | Mega Cap Leader Rotation Dynamic Top20 | Yes | No | `us_equity` | research-only 存档 |
| `dynamic_mega_leveraged_pullback` | Dynamic Mega Leveraged Pullback | Yes | No | `us_equity` | research-only 存档 |

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

Expand Down
6 changes: 0 additions & 6 deletions notifications/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,7 @@
"strategy_name_russell_1000_multi_factor_defensive": "罗素1000多因子",
"strategy_name_tech_communication_pullback_enhancement": "科技通信回调增强",
"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": {
"rebalance_title": "🔔 【Trade Execution Report】",
Expand Down Expand Up @@ -176,10 +173,7 @@
"strategy_name_russell_1000_multi_factor_defensive": "Russell 1000 Multi-Factor",
"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_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
19 changes: 0 additions & 19 deletions tests/test_runtime_config_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,7 @@ def test_platform_eligible_profiles_are_exposed_by_capability_matrix(self):
get_eligible_profiles_for_platform(LONGBRIDGE_PLATFORM),
frozenset(
{
"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",
"tqqq_growth_income",
Expand Down Expand Up @@ -176,9 +173,6 @@ def test_platform_profile_status_matrix_matches_current_longbridge_rollout(self)
set(by_profile),
{
"global_etf_rotation",
"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",
Expand Down Expand Up @@ -210,21 +204,12 @@ def test_platform_profile_status_matrix_matches_current_longbridge_rollout(self)
self.assertTrue(by_profile["tech_communication_pullback_enhancement"]["eligible"])
self.assertTrue(by_profile["tech_communication_pullback_enhancement"]["enabled"])
self.assertEqual(by_profile["tech_communication_pullback_enhancement"]["display_name"], "Tech/Communication Pullback Enhancement")
self.assertTrue(by_profile["mega_cap_leader_rotation_dynamic_top20"]["eligible"])
self.assertFalse(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.assertFalse(by_profile["mega_cap_leader_rotation_aggressive"]["enabled"])
self.assertEqual(by_profile["mega_cap_leader_rotation_aggressive"]["display_name"], "Mega Cap Leader Rotation Aggressive")
self.assertTrue(by_profile["dynamic_mega_leveraged_pullback"]["eligible"])
self.assertFalse(by_profile["dynamic_mega_leveraged_pullback"]["enabled"])
self.assertEqual(by_profile["dynamic_mega_leveraged_pullback"]["display_name"], "Dynamic Mega Leveraged Pullback")

def test_loads_feature_snapshot_env_for_tech_profile(self):
with patch.dict(
Expand Down Expand Up @@ -302,9 +287,6 @@ def test_print_strategy_profile_status_json_matches_registry(self):
self.assertEqual(by_profile["tech_communication_pullback_enhancement"]["input_mode"], "feature_snapshot")
self.assertTrue(by_profile["tech_communication_pullback_enhancement"]["requires_snapshot_artifacts"])
self.assertTrue(by_profile["tech_communication_pullback_enhancement"]["requires_strategy_config_path"])
self.assertFalse(by_profile["mega_cap_leader_rotation_dynamic_top20"]["enabled"])
self.assertFalse(by_profile["mega_cap_leader_rotation_aggressive"]["enabled"])
self.assertFalse(by_profile["dynamic_mega_leveraged_pullback"]["enabled"])
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"])
Expand All @@ -328,7 +310,6 @@ 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("mega_cap_leader_rotation_dynamic_top20", result.stdout)
self.assertIn("russell_1000_multi_factor_defensive", result.stdout)
self.assertIn("Global ETF Rotation", result.stdout)
self.assertIn("Russell 1000 Multi-Factor", result.stdout)
Expand Down
44 changes: 17 additions & 27 deletions tests/test_strategy_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,19 @@ def evaluate(self, ctx):
return StrategyDecision(diagnostics={"signal_description": "broad risk on"})


class _DynamicMegaLeveragedEntrypoint:
class _MegaCapTop50Entrypoint:
manifest = StrategyManifest(
profile="dynamic_mega_leveraged_pullback",
profile="mega_cap_leader_rotation_top50_balanced",
domain="us_equity",
display_name="Dynamic Mega Leveraged Pullback",
display_name="Mega Cap Leader Rotation Top50 Balanced",
description="test entrypoint",
required_inputs=frozenset({"feature_snapshot", "market_history", "benchmark_history", "portfolio_snapshot"}),
required_inputs=frozenset({"feature_snapshot"}),
default_config={"safe_haven": "BOXX", "benchmark_symbol": "QQQ"},
)

def evaluate(self, ctx):
self.ctx = ctx
return StrategyDecision(diagnostics={"signal_description": "leveraged pullback"})
return StrategyDecision(diagnostics={"signal_description": "top50 balanced"})


def _build_runtime_settings(
Expand Down Expand Up @@ -366,27 +366,24 @@ def test_feature_snapshot_runtime_loads_russell_snapshot_into_context(self):
self.assertEqual(result.metadata["managed_symbols"], ("AAPL", "MSFT", "BOXX"))
self.assertEqual(result.metadata["status_icon"], "📏")

def test_feature_snapshot_runtime_keeps_hybrid_inputs_for_dynamic_mega_leveraged_pullback(self):
entrypoint = _DynamicMegaLeveragedEntrypoint()
def test_feature_snapshot_runtime_loads_mega_cap_top50_snapshot_into_context(self):
entrypoint = _MegaCapTop50Entrypoint()
runtime = strategy_runtime_module.LoadedStrategyRuntime(
entrypoint=entrypoint,
runtime_adapter=StrategyRuntimeAdapter(
status_icon="2x",
required_feature_columns=frozenset({"symbol", "underlying_symbol", "sector", "candidate_rank", "product_leverage", "product_available"}),
managed_symbols_extractor=lambda *_args, **_kwargs: ("AAPU", "BOXX"),
status_icon="👑",
required_feature_columns=frozenset({"symbol", "sector", "close"}),
managed_symbols_extractor=lambda *_args, **_kwargs: ("NVDA", "META", "BOXX"),
portfolio_input_name="portfolio_snapshot",
),
runtime_settings=_build_runtime_settings(
"dynamic_mega_leveraged_pullback",
feature_snapshot_path="gs://bucket/dynamic.csv",
"mega_cap_leader_rotation_top50_balanced",
feature_snapshot_path="gs://bucket/top50.csv",
),
merged_runtime_config={"safe_haven": "BOXX", "benchmark_symbol": "QQQ"},
logger=lambda _message: None,
)

def market_history_loader(*_args, **_kwargs):
return [1.0, 2.0, 3.0]

portfolio = PortfolioSnapshot(
as_of=datetime.now(timezone.utc),
total_equity=1000.0,
Expand All @@ -403,31 +400,24 @@ def market_history_loader(*_args, **_kwargs):
{
"frame": [
{
"symbol": "AAPU",
"underlying_symbol": "AAPL",
"symbol": "NVDA",
"sector": "Technology",
"candidate_rank": 1,
"product_leverage": 2.0,
"product_available": True,
"close": 880.0,
}
],
"metadata": {"snapshot_guard_decision": "proceed", "snapshot_as_of": "2026-04-08"},
},
)(),
):
result = runtime.evaluate(
market_history=market_history_loader,
benchmark_history=[{"close": 1.0, "high": 1.0, "low": 1.0}],
portfolio_snapshot=portfolio,
translator=lambda key, **_kwargs: key,
)

self.assertEqual(entrypoint.ctx.market_data["feature_snapshot"][0]["symbol"], "AAPU")
self.assertIs(entrypoint.ctx.market_data["market_history"], market_history_loader)
self.assertEqual(entrypoint.ctx.market_data["benchmark_history"][0]["close"], 1.0)
self.assertEqual(entrypoint.ctx.market_data["feature_snapshot"][0]["symbol"], "NVDA")
self.assertIs(entrypoint.ctx.portfolio, portfolio)
self.assertEqual(result.metadata["managed_symbols"], ("AAPU", "BOXX"))
self.assertEqual(result.metadata["status_icon"], "2x")
self.assertEqual(result.metadata["managed_symbols"], ("NVDA", "META", "BOXX"))
self.assertEqual(result.metadata["status_icon"], "👑")


if __name__ == "__main__":
Expand Down