|
| 1 | +# US equity live switch and rollback runbook |
| 2 | + |
| 3 | +This document is the operational runbook for switching live US equity strategy profiles on the current broker platforms. |
| 4 | + |
| 5 | +Use this after the shared package and platform code is already deployed. |
| 6 | + |
| 7 | +Do **not** use it to justify switching a profile that is not already supported by the platform status matrix. |
| 8 | + |
| 9 | +## Scope |
| 10 | + |
| 11 | +Current live US equity profiles: |
| 12 | + |
| 13 | +- `global_etf_rotation` |
| 14 | +- `tqqq_growth_income` |
| 15 | +- `soxl_soxx_trend_income` |
| 16 | +- `russell_1000_multi_factor_defensive` |
| 17 | +- `qqq_tech_enhancement` |
| 18 | + |
| 19 | +Current runtime platforms: |
| 20 | + |
| 21 | +- `ibkr` |
| 22 | +- `schwab` |
| 23 | +- `longbridge` |
| 24 | + |
| 25 | +For the current five-profile scope, all three platforms now report the full matrix as `eligible=true` and `enabled=true`. That means live switching is now an operational change, not a strategy-contract migration. |
| 26 | + |
| 27 | +## Standard switch path |
| 28 | + |
| 29 | +Use the same path every time: |
| 30 | + |
| 31 | +1. verify the target profile is `eligible=true` and `enabled=true` |
| 32 | +2. update the GitHub-managed runtime variables for the target service |
| 33 | +3. rerun or wait for `Sync Cloud Run Env` |
| 34 | +4. verify the Cloud Run env on the service |
| 35 | +5. verify the first heartbeat or execution notification |
| 36 | + |
| 37 | +Do not change service names as part of a strategy switch. |
| 38 | + |
| 39 | +## Service inventory |
| 40 | + |
| 41 | +| Platform | Service | Identity split | |
| 42 | +| --- | --- | --- | |
| 43 | +| IBKR | `interactive-brokers-quant-service` | `ACCOUNT_GROUP` | |
| 44 | +| Schwab | `charles-schwab-quant-service` | single service | |
| 45 | +| LongBridge HK | `longbridge-quant-hk-service` | `ACCOUNT_REGION=HK` | |
| 46 | +| LongBridge SG | `longbridge-quant-sg-service` | `ACCOUNT_REGION=SG` | |
| 47 | + |
| 48 | +## Step 1: verify the target profile before touching env |
| 49 | + |
| 50 | +Run the platform status script inside the platform repo. |
| 51 | + |
| 52 | +### IBKR |
| 53 | + |
| 54 | +```bash |
| 55 | +cd /Users/lisiyi/Projects/InteractiveBrokersPlatform |
| 56 | +PYTHONPATH=/Users/lisiyi/Projects/QuantPlatformKit/src:/Users/lisiyi/Projects/UsEquityStrategies/src:. \ |
| 57 | + .venv/bin/python scripts/print_strategy_profile_status.py --json |
| 58 | +``` |
| 59 | + |
| 60 | +### Schwab |
| 61 | + |
| 62 | +```bash |
| 63 | +cd /Users/lisiyi/Projects/CharlesSchwabPlatform |
| 64 | +PYTHONPATH=/Users/lisiyi/Projects/QuantPlatformKit/src:/Users/lisiyi/Projects/UsEquityStrategies/src:. \ |
| 65 | + /Users/lisiyi/Projects/LongBridgePlatform/.venv/bin/python scripts/print_strategy_profile_status.py --json |
| 66 | +``` |
| 67 | + |
| 68 | +### LongBridge |
| 69 | + |
| 70 | +```bash |
| 71 | +cd /Users/lisiyi/Projects/LongBridgePlatform |
| 72 | +PYTHONPATH=/Users/lisiyi/Projects/QuantPlatformKit/src:/Users/lisiyi/Projects/UsEquityStrategies/src:. \ |
| 73 | + .venv/bin/python scripts/print_strategy_profile_status.py --json |
| 74 | +``` |
| 75 | + |
| 76 | +Required result: |
| 77 | + |
| 78 | +- the target `canonical_profile` exists |
| 79 | +- `eligible` is `true` |
| 80 | +- `enabled` is `true` |
| 81 | + |
| 82 | +If any of those checks fail, stop. That is a code or rollout problem, not a live switch problem. |
| 83 | + |
| 84 | +## Step 2: know which extra envs the profile needs |
| 85 | + |
| 86 | +| Profile | Extra runtime inputs beyond `STRATEGY_PROFILE` | |
| 87 | +| --- | --- | |
| 88 | +| `global_etf_rotation` | none | |
| 89 | +| `tqqq_growth_income` | none | |
| 90 | +| `soxl_soxx_trend_income` | none | |
| 91 | +| `russell_1000_multi_factor_defensive` | feature snapshot path + snapshot manifest path | |
| 92 | +| `qqq_tech_enhancement` | feature snapshot path + snapshot manifest path + strategy config path | |
| 93 | + |
| 94 | +Notes: |
| 95 | + |
| 96 | +- `qqq_tech_enhancement` on IBKR may also keep a reconciliation output path when the deployment wants that artifact. |
| 97 | +- When switching away from a feature-snapshot profile, remove stale snapshot/config envs from the service instead of leaving them behind. |
| 98 | + |
| 99 | +## Step 3: update GitHub-managed runtime variables |
| 100 | + |
| 101 | +Preferred operational path: |
| 102 | + |
| 103 | +- update GitHub repository variables or environment variables |
| 104 | +- let `.github/workflows/sync-cloud-run-env.yml` apply the change |
| 105 | + |
| 106 | +### IBKR |
| 107 | + |
| 108 | +Required: |
| 109 | + |
| 110 | +- `STRATEGY_PROFILE` |
| 111 | +- `ACCOUNT_GROUP` |
| 112 | +- `IB_ACCOUNT_GROUP_CONFIG_SECRET_NAME` |
| 113 | + |
| 114 | +Optional: |
| 115 | + |
| 116 | +- `IBKR_DRY_RUN_ONLY` |
| 117 | + |
| 118 | +Feature-snapshot profiles additionally need: |
| 119 | + |
| 120 | +- `IBKR_FEATURE_SNAPSHOT_PATH` |
| 121 | +- `IBKR_FEATURE_SNAPSHOT_MANIFEST_PATH` |
| 122 | +- `IBKR_STRATEGY_CONFIG_PATH` for `qqq_tech_enhancement` |
| 123 | + |
| 124 | +Remove when not needed: |
| 125 | + |
| 126 | +- `IBKR_FEATURE_SNAPSHOT_PATH` |
| 127 | +- `IBKR_FEATURE_SNAPSHOT_MANIFEST_PATH` |
| 128 | +- `IBKR_STRATEGY_CONFIG_PATH` |
| 129 | +- `IBKR_RECONCILIATION_OUTPUT_PATH` |
| 130 | + |
| 131 | +### Schwab |
| 132 | + |
| 133 | +Required: |
| 134 | + |
| 135 | +- `STRATEGY_PROFILE` |
| 136 | + |
| 137 | +Optional: |
| 138 | + |
| 139 | +- `SCHWAB_DRY_RUN_ONLY` |
| 140 | + |
| 141 | +Feature-snapshot profiles additionally need: |
| 142 | + |
| 143 | +- `SCHWAB_FEATURE_SNAPSHOT_PATH` |
| 144 | +- `SCHWAB_FEATURE_SNAPSHOT_MANIFEST_PATH` |
| 145 | +- `SCHWAB_STRATEGY_CONFIG_PATH` when the chosen profile uses an external config file |
| 146 | + |
| 147 | +Remove when not needed: |
| 148 | + |
| 149 | +- `SCHWAB_FEATURE_SNAPSHOT_PATH` |
| 150 | +- `SCHWAB_FEATURE_SNAPSHOT_MANIFEST_PATH` |
| 151 | +- `SCHWAB_STRATEGY_CONFIG_PATH` |
| 152 | + |
| 153 | +### LongBridge |
| 154 | + |
| 155 | +Required: |
| 156 | + |
| 157 | +- `STRATEGY_PROFILE` |
| 158 | +- `ACCOUNT_PREFIX` |
| 159 | +- `ACCOUNT_REGION` |
| 160 | +- `LONGPORT_SECRET_NAME` |
| 161 | +- `LONGPORT_APP_KEY_SECRET_NAME` |
| 162 | +- `LONGPORT_APP_SECRET_SECRET_NAME` |
| 163 | + |
| 164 | +Optional: |
| 165 | + |
| 166 | +- `LONGBRIDGE_DRY_RUN_ONLY` |
| 167 | + |
| 168 | +Feature-snapshot profiles additionally need: |
| 169 | + |
| 170 | +- `LONGBRIDGE_FEATURE_SNAPSHOT_PATH` |
| 171 | +- `LONGBRIDGE_FEATURE_SNAPSHOT_MANIFEST_PATH` |
| 172 | +- `LONGBRIDGE_STRATEGY_CONFIG_PATH` |
| 173 | + |
| 174 | +Remove when not needed: |
| 175 | + |
| 176 | +- `LONGBRIDGE_FEATURE_SNAPSHOT_PATH` |
| 177 | +- `LONGBRIDGE_FEATURE_SNAPSHOT_MANIFEST_PATH` |
| 178 | +- `LONGBRIDGE_STRATEGY_CONFIG_PATH` |
| 179 | + |
| 180 | +## Step 4: rerun env sync and verify Cloud Run |
| 181 | + |
| 182 | +Wait for the platform workflow to finish: |
| 183 | + |
| 184 | +- `Sync Cloud Run Env` |
| 185 | + |
| 186 | +Then verify the service directly. |
| 187 | + |
| 188 | +### Example checks |
| 189 | + |
| 190 | +```bash |
| 191 | +gcloud run services describe interactive-brokers-quant-service \ |
| 192 | + --project interactivebrokersquant \ |
| 193 | + --region us-central1 \ |
| 194 | + --format='flattened(spec.template.spec.containers[0].env[])' |
| 195 | +``` |
| 196 | + |
| 197 | +```bash |
| 198 | +gcloud run services describe charles-schwab-quant-service \ |
| 199 | + --project charlesschwabquant \ |
| 200 | + --region us-central1 \ |
| 201 | + --format='flattened(spec.template.spec.containers[0].env[])' |
| 202 | +``` |
| 203 | + |
| 204 | +```bash |
| 205 | +gcloud run services describe longbridge-quant-hk-service \ |
| 206 | + --project longbridgequant \ |
| 207 | + --region asia-east2 \ |
| 208 | + --format='flattened(spec.template.spec.containers[0].env[])' |
| 209 | +``` |
| 210 | + |
| 211 | +```bash |
| 212 | +gcloud run services describe longbridge-quant-sg-service \ |
| 213 | + --project longbridgequant \ |
| 214 | + --region asia-southeast1 \ |
| 215 | + --format='flattened(spec.template.spec.containers[0].env[])' |
| 216 | +``` |
| 217 | + |
| 218 | +Verify: |
| 219 | + |
| 220 | +- `STRATEGY_PROFILE` matches the intended target |
| 221 | +- feature-snapshot envs exist only for feature-snapshot profiles |
| 222 | +- stale dry-run or artifact envs were removed when the new profile does not need them |
| 223 | + |
| 224 | +## Step 5: verify the first runtime output |
| 225 | + |
| 226 | +Do not stop at Cloud Run env. |
| 227 | + |
| 228 | +Verify the first heartbeat or execution notification shows: |
| 229 | + |
| 230 | +- the expected display name |
| 231 | +- the expected account prefix (`[HK]` / `[SG]` for LongBridge) |
| 232 | +- no stale strategy-specific service-name suffix in the LongBridge notification prefix |
| 233 | + |
| 234 | +If the profile uses feature snapshots, also verify: |
| 235 | + |
| 236 | +- the snapshot file exists at the configured path |
| 237 | +- the manifest matches the expected contract version |
| 238 | +- the managed symbols in the first notification match the intended strategy |
| 239 | + |
| 240 | +## Rollback rules |
| 241 | + |
| 242 | +Rollback is simple if you keep it operational: |
| 243 | + |
| 244 | +1. restore the last known good `STRATEGY_PROFILE` |
| 245 | +2. restore or remove the companion snapshot/config envs so they match that profile |
| 246 | +3. rerun `Sync Cloud Run Env` |
| 247 | +4. verify Cloud Run env again |
| 248 | +5. verify the next heartbeat or execution notification |
| 249 | + |
| 250 | +Do not use any of these as rollback mechanisms: |
| 251 | + |
| 252 | +- old service names |
| 253 | +- ad hoc local edits on Cloud Run |
| 254 | +- partially reverting only one feature-snapshot env |
| 255 | + |
| 256 | +If the service cannot start after a switch: |
| 257 | + |
| 258 | +1. revert the service env first |
| 259 | +2. only then investigate code or dependency issues |
| 260 | + |
| 261 | +## Recommended operator checklist |
| 262 | + |
| 263 | +For every live switch, record these five items in the change note or operator log: |
| 264 | + |
| 265 | +1. service name |
| 266 | +2. old profile |
| 267 | +3. new profile |
| 268 | +4. extra envs added or removed |
| 269 | +5. first successful heartbeat or execution timestamp |
0 commit comments