Skip to content

Commit c987c23

Browse files
committed
Document LongBridge strategy cadences
1 parent 31c4d45 commit c987c23

3 files changed

Lines changed: 41 additions & 2 deletions

File tree

README.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,24 @@ Check the current matrix locally:
4343
python3 scripts/print_strategy_profile_status.py
4444
```
4545

46+
### Runtime cadence
47+
48+
Strategy cadence is owned by the strategy profile, but the actual broker run is
49+
triggered by Cloud Scheduler. Keep the Cloud Scheduler job aligned with the
50+
selected `STRATEGY_PROFILE` for each Cloud Run service:
51+
52+
| Profile | Intended cadence | Recommended Cloud Scheduler | Notes |
53+
| --- | --- | --- | --- |
54+
| `global_etf_rotation` | quarterly rebalance + daily canary | weekdays near US close, e.g. `45 15 * * 1-5` in `America/New_York` | Non-rebalance days should only act on the canary emergency path. |
55+
| `soxl_soxx_trend_income` | daily | weekdays near US close, e.g. `45 15 * * 1-5` in `America/New_York` | Trend/income value-mode profile. |
56+
| `tqqq_growth_income` | daily | weekdays near US close, e.g. `45 15 * * 1-5` in `America/New_York` | Current SG line. |
57+
| `russell_1000_multi_factor_defensive` | monthly | first few calendar days after month end, e.g. `45 15 1-7 * *` in `America/New_York` | Consumes monthly feature snapshots from `UsEquitySnapshotPipelines`. |
58+
| `tech_communication_pullback_enhancement` | monthly | first few calendar days after month end, e.g. `45 15 1-7 * *` in `America/New_York` | Current HK line. LongBridge constrains this profile to the first trading day after the monthly snapshot to avoid month-internal rebalancing. |
59+
60+
The upstream snapshot/data workflows live in `UsEquitySnapshotPipelines` and run
61+
monthly. Cloud Scheduler only invokes the broker runtime; it does not generate
62+
new feature snapshots.
63+
4664
**Layers**
4765

4866
- **Trading:** SOXL / SOXX / BOXX
@@ -193,7 +211,7 @@ Important:
193211
2. Create secret `longport_token_hk` for HK / `longport_token_sg` for SG (or your custom `LONGPORT_SECRET_NAME`) in Secret Manager and add your LongPort access token as the first version.
194212
3. Set the required env vars above on the Cloud Run service.
195213
4. Deploy the app to Cloud Run (e.g. `gcloud run deploy` from repo root with Dockerfile or buildpack).
196-
5. Create a Cloud Scheduler job that POSTs to the Cloud Run URL on a schedule (e.g. `45 15 * * 1-5` for ~15 min before US market close on weekdays).
214+
5. Create a Cloud Scheduler job that POSTs to the Cloud Run URL on a schedule. Use the [runtime cadence](#runtime-cadence) table: daily profiles usually use `45 15 * * 1-5`, while monthly snapshot profiles use a first-week monthly candidate window such as `45 15 1-7 * *`.
197215

198216
IAM: the Cloud Run service account needs **Secret Manager Admin** (or Secret Accessor for the configured `LONGPORT_SECRET_NAME`, `LONGPORT_APP_KEY_SECRET_NAME`, and `LONGPORT_APP_SECRET_SECRET_NAME`, such as `longport_token_hk`, `longport-app-key-hk`, `longport-app-secret-hk`) and **Logs Writer**. Build/deploy typically uses a separate account with Artifact Registry Writer, Cloud Run Admin, Service Account User.
199217

@@ -244,6 +262,22 @@ IAM: the Cloud Run service account needs **Secret Manager Admin** (or Secret Acc
244262
python3 scripts/print_strategy_profile_status.py
245263
```
246264

265+
### 策略执行频率
266+
267+
策略频率由策略档位决定,但实际券商执行是 Cloud Scheduler 触发的。
268+
每个 Cloud Run 服务的 Cloud Scheduler 需要和当前 `STRATEGY_PROFILE` 对齐:
269+
270+
| Profile | 目标频率 | 建议 Cloud Scheduler | 说明 |
271+
| --- | --- | --- | --- |
272+
| `global_etf_rotation` | 季度调仓 + 每日 canary 防守检查 | 美股临近收盘的工作日,例如 `45 15 * * 1-5`,时区 `America/New_York` | 非调仓日原则上只在 canary 紧急防守路径动作。 |
273+
| `soxl_soxx_trend_income` | 日频 | 美股临近收盘的工作日,例如 `45 15 * * 1-5`,时区 `America/New_York` | 趋势/收益 value-mode 策略。 |
274+
| `tqqq_growth_income` | 日频 | 美股临近收盘的工作日,例如 `45 15 * * 1-5`,时区 `America/New_York` | 当前 SG 线路。 |
275+
| `russell_1000_multi_factor_defensive` | 月频 | 月末之后前几个自然日,例如 `45 15 1-7 * *`,时区 `America/New_York` | 消费 `UsEquitySnapshotPipelines` 生成的月度 feature snapshot。 |
276+
| `tech_communication_pullback_enhancement` | 月频 | 月末之后前几个自然日,例如 `45 15 1-7 * *`,时区 `America/New_York` | 当前 HK 线路。LongBridge 会把该策略限制在月度 snapshot 之后第一个交易日执行,避免月内重复调仓。 |
277+
278+
上游数据刷新和 feature snapshot 发布在 `UsEquitySnapshotPipelines` 里,按月运行。
279+
Cloud Scheduler 只负责触发券商运行时,不负责生成新的 feature snapshot。
280+
247281
**层级**
248282

249283
- **交易层:** SOXL / SOXX / BOXX
@@ -394,7 +428,7 @@ Secret Manager 中需存在 `LONGPORT_SECRET_NAME` 指定的密钥(默认: `lo
394428
2. 在 Secret Manager 中为 HK 创建 `longport_token_hk`、为 SG 创建 `longport_token_sg`(或使用你自定义的 `LONGPORT_SECRET_NAME`),并将 LongPort access token 作为第一个版本写入。
395429
3. 在 Cloud Run 服务上配置上述环境变量。
396430
4. 部署至 Cloud Run(如从仓库根目录执行 `gcloud run deploy`)。
397-
5. 创建 Cloud Scheduler 定时任务,POST 到 Cloud Run URL(如 `45 15 * * 1-5`工作日美股收盘前约 15 分钟)
431+
5. 创建 Cloud Scheduler 定时任务,POST 到 Cloud Run URL。按上面的[策略执行频率](#策略执行频率)配置:日频策略通常用 `45 15 * * 1-5`月频 snapshot 策略用类似 `45 15 1-7 * *` 的月初候选窗口
398432

399433
IAM: Cloud Run 服务账号需要 **Secret Manager Admin**(或当前 `LONGPORT_SECRET_NAME``LONGPORT_APP_KEY_SECRET_NAME``LONGPORT_APP_SECRET_SECRET_NAME` 对应 secret 的 Secret Accessor,例如 `longport_token_hk``longport-app-key-hk``longport-app-secret-hk`)和 **Logs Writer** 权限。
400434

strategy_runtime.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121

2222
_FEATURE_SNAPSHOT_INPUT = "feature_snapshot"
23+
_SINGLE_EXECUTION_WINDOW_PROFILES = frozenset({"tech_communication_pullback_enhancement"})
2324

2425

2526
@dataclass(frozen=True)
@@ -135,6 +136,8 @@ def _evaluate_feature_snapshot_strategy(
135136
evaluation_as_of = datetime.now(timezone.utc)
136137
runtime_config = dict(runtime_config)
137138
runtime_config.setdefault("run_as_of", evaluation_as_of)
139+
if self.profile in _SINGLE_EXECUTION_WINDOW_PROFILES:
140+
runtime_config.setdefault("runtime_execution_window_trading_days", 1)
138141

139142
guard_result = load_feature_snapshot_guarded(
140143
feature_snapshot_path,

tests/test_strategy_runtime.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ def test_feature_snapshot_runtime_loads_snapshot_into_context(self):
219219
self.assertEqual(entrypoint.ctx.portfolio.total_equity, 1000.0)
220220
self.assertIn("run_as_of", entrypoint.ctx.runtime_config)
221221
self.assertEqual(entrypoint.ctx.runtime_config["run_as_of"], entrypoint.ctx.as_of)
222+
self.assertEqual(entrypoint.ctx.runtime_config["runtime_execution_window_trading_days"], 1)
222223
self.assertEqual(load_snapshot.call_args.kwargs["run_as_of"], entrypoint.ctx.as_of)
223224
self.assertEqual(result.metadata["managed_symbols"], ("AAPL", "MSFT", "BOXX"))
224225
self.assertEqual(result.metadata["status_icon"], "🧲")
@@ -267,6 +268,7 @@ def test_feature_snapshot_runtime_loads_russell_snapshot_into_context(self):
267268
)
268269

269270
self.assertEqual(entrypoint.ctx.market_data["feature_snapshot"][1]["symbol"], "AAPL")
271+
self.assertNotIn("runtime_execution_window_trading_days", entrypoint.ctx.runtime_config)
270272
self.assertEqual(result.metadata["managed_symbols"], ("AAPL", "MSFT", "BOXX"))
271273
self.assertEqual(result.metadata["status_icon"], "📏")
272274

0 commit comments

Comments
 (0)