|
| 1 | +# Runtime Target Architecture |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +Make runtime selection explicit and stable across platforms by separating: |
| 6 | + |
| 7 | +- strategy selection |
| 8 | +- platform selection |
| 9 | +- account selection |
| 10 | +- deployment mode |
| 11 | + |
| 12 | +`STRATEGY_PROFILE` still exists as a compatibility selector, but the running service is now described primarily by `RuntimeTarget` and `RuntimeAssembly`. |
| 13 | + |
| 14 | +## Core idea |
| 15 | + |
| 16 | +The shared control-plane object is `RuntimeTarget`. |
| 17 | + |
| 18 | +It answers: |
| 19 | + |
| 20 | +- which platform is this? |
| 21 | +- which strategy implementation is selected? |
| 22 | +- is this paper or live? |
| 23 | +- which deployment selector is active? |
| 24 | +- which account selector is active? |
| 25 | +- which service is this bound to? |
| 26 | + |
| 27 | +The runtime target should flow through: |
| 28 | + |
| 29 | +- GitHub env sync |
| 30 | +- Cloud Run env |
| 31 | +- runtime logs |
| 32 | +- reports |
| 33 | +- deployment previews |
| 34 | + |
| 35 | +`RuntimeAssembly` is the internal bridge object that carries the deployment identity plus the runtime target into logging, reporting, and platform wiring. |
| 36 | + |
| 37 | +## Design patterns used |
| 38 | + |
| 39 | +### Strategy |
| 40 | + |
| 41 | +`strategy_profile` selects the strategy behavior: |
| 42 | + |
| 43 | +- signal generation |
| 44 | +- universe |
| 45 | +- cadence |
| 46 | +- sizing rules |
| 47 | + |
| 48 | +It must not own broker selection or deployment identity. |
| 49 | + |
| 50 | +### Bridge |
| 51 | + |
| 52 | +Platform and strategy evolve independently. |
| 53 | + |
| 54 | +- strategy axis: `global_etf_rotation`, `tqqq_growth_income`, ... |
| 55 | +- platform axis: LongBridge, IBKR, Schwab, PaperSignal |
| 56 | + |
| 57 | +`RuntimeTarget` is the bridge payload that keeps those axes separate. |
| 58 | + |
| 59 | +### Adapter |
| 60 | + |
| 61 | +Each platform still adapts unified ports to broker-specific APIs: |
| 62 | + |
| 63 | +- `ExecutionPort` |
| 64 | +- `PortfolioPort` |
| 65 | +- `MarketDataPort` |
| 66 | +- notification/report adapters |
| 67 | + |
| 68 | +Platform differences stay at the edge. |
| 69 | + |
| 70 | +### Abstract Factory |
| 71 | + |
| 72 | +A runtime factory assembles a runnable service from `RuntimeTarget` and `RuntimeAssembly`: |
| 73 | + |
| 74 | +- runtime config |
| 75 | +- broker adapter |
| 76 | +- reporting adapter |
| 77 | +- notification adapter |
| 78 | +- capability validation |
| 79 | + |
| 80 | +### Template Method |
| 81 | + |
| 82 | +GitHub sync and runtime startup follow the same high-level flow: |
| 83 | + |
| 84 | +1. resolve inputs |
| 85 | +2. resolve capability |
| 86 | +3. build runtime target |
| 87 | +4. sync env |
| 88 | +5. start service |
| 89 | +6. emit report |
| 90 | + |
| 91 | +### Facade |
| 92 | + |
| 93 | +External callers should prefer a small surface: |
| 94 | + |
| 95 | +- `runtime_target` |
| 96 | +- `strategy_profile` for compatibility |
| 97 | + |
| 98 | +Do not leak broker-specific wiring into external deployment steps. |
| 99 | + |
| 100 | +## Target module split |
| 101 | + |
| 102 | +### Shared package |
| 103 | + |
| 104 | +`QuantPlatformKit` |
| 105 | + |
| 106 | +Owns: |
| 107 | + |
| 108 | +- `RuntimeTarget` |
| 109 | +- runtime config helpers |
| 110 | +- shared ports and adapters |
| 111 | +- runtime report helpers |
| 112 | +- strategy contracts |
| 113 | + |
| 114 | +### Platform runtime repository |
| 115 | + |
| 116 | +Example repositories: |
| 117 | + |
| 118 | +- `LongBridgePlatform` |
| 119 | +- `InteractiveBrokersPlatform` |
| 120 | +- `CharlesSchwabPlatform` |
| 121 | + |
| 122 | +Own: |
| 123 | + |
| 124 | +- runtime entrypoints |
| 125 | +- platform adapters |
| 126 | +- deployment sync scripts |
| 127 | +- account selection and secret wiring |
| 128 | +- platform-specific reporting text |
| 129 | + |
| 130 | +### Strategy repository |
| 131 | + |
| 132 | +Future shared strategy repositories should own: |
| 133 | + |
| 134 | +- reusable strategy math |
| 135 | +- platform-independent signal logic |
| 136 | +- domain parameters |
| 137 | + |
| 138 | +They should not own: |
| 139 | + |
| 140 | +- Cloud Run entrypoints |
| 141 | +- broker auth |
| 142 | +- scheduler wiring |
| 143 | +- deployment secrets |
| 144 | + |
| 145 | +## RuntimeTarget invariants |
| 146 | + |
| 147 | +- `strategy_profile` is still required for compatibility and strategy routing. |
| 148 | +- `platform_id` is required. |
| 149 | +- `dry_run_only` determines `execution_mode`. |
| 150 | +- `account_selector` is optional and platform-dependent. |
| 151 | +- `account_scope` is optional and may mirror region or account-group semantics. |
| 152 | +- `service_name` is a deployment identity, not a strategy concept. |
| 153 | + |
| 154 | +## Platform-specific account rules |
| 155 | + |
| 156 | +### LongBridge |
| 157 | + |
| 158 | +- split by region |
| 159 | +- `account_scope` can mirror `HK` / `SG` |
| 160 | +- `deployment_selector` should reflect the active region |
| 161 | +- one service per region is the target shape |
| 162 | + |
| 163 | +### IBKR |
| 164 | + |
| 165 | +- split by account group |
| 166 | +- `account_selector` may contain one or more IB account identifiers |
| 167 | +- `ACCOUNT_GROUP` stays as the external runtime selector |
| 168 | + |
| 169 | +### Schwab |
| 170 | + |
| 171 | +- typically one service identity |
| 172 | +- `account_selector` may stay empty |
| 173 | +- `STRATEGY_PROFILE` remains the compatibility selector, not the main control plane |
| 174 | + |
| 175 | +### PaperSignal |
| 176 | + |
| 177 | +- paper/live is controlled by `dry_run_only` |
| 178 | +- strategy identity still flows through the same `RuntimeTarget` |
| 179 | + |
| 180 | +## Migration sequence |
| 181 | + |
| 182 | +1. keep `STRATEGY_PROFILE` working |
| 183 | +2. emit `RuntimeTarget` in runtime settings and reports |
| 184 | +3. emit `RUNTIME_TARGET_JSON` in GitHub env sync |
| 185 | +4. move docs and previews to runtime-target-first wording |
| 186 | +5. keep `strategy_profile` only as internal compatibility input |
| 187 | +6. keep `RuntimeAssembly` as the internal bridge for entrypoints and reports |
| 188 | +7. extract more shared orchestration once the target model is stable |
| 189 | + |
| 190 | +## Practical rule |
| 191 | + |
| 192 | +If a piece of code answers: |
| 193 | + |
| 194 | +- "which broker runtime is this?" |
| 195 | +- "which account or region is active?" |
| 196 | +- "is this paper or live?" |
| 197 | + |
| 198 | +then it belongs in the runtime target / runtime config layer, not in strategy code. |
0 commit comments