|
| 1 | +# Strategy-Platform Configuration Specification |
| 2 | + |
| 3 | +## Single Source of Truth |
| 4 | + |
| 5 | +Every platform service has **one** canonical config entry-point: |
| 6 | + |
| 7 | +``` |
| 8 | +RUNTIME_TARGET_JSON = {"platform_id": "...", "strategy_profile": "...", ...} |
| 9 | +``` |
| 10 | + |
| 11 | +All other config values that reference the strategy name MUST derive from |
| 12 | +`RUNTIME_TARGET_JSON.strategy_profile` — either at code level or through the |
| 13 | +auto-sync layer described below. |
| 14 | + |
| 15 | +### Derived values (auto-synced on startup) |
| 16 | + |
| 17 | +| Config location | Field | Auto-sync | |
| 18 | +|---|---|---| |
| 19 | +| `SCHWAB_STRATEGY_PLUGIN_MOUNTS_JSON` | `.strategy_plugins[].strategy` | ✅ corrected on startup | |
| 20 | +| `STRATEGY_PLUGIN_MOUNTS_JSON` (IBKR, LB) | `.strategy_plugins[].strategy` | ✅ corrected on startup | |
| 21 | +| `MONITOR_DISPATCH_TARGETS_JSON` | `.targets[].strategy_profile` | ✅ corrected on startup (Schwab) | |
| 22 | +| `SCHWAB_MONITOR_DISPATCH_TARGETS_JSON` | `.targets[].strategy_profile` | ✅ corrected on startup (Schwab) | |
| 23 | + |
| 24 | +### Deprecated (do NOT set) |
| 25 | + |
| 26 | +- `STRATEGY_PROFILE` — was a standalone env var that duplicated `RUNTIME_TARGET_JSON.strategy_profile`. Removed in Schwab `runtime_config_support.py`. IBKR and LongBridge never had this fallback. |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Adding a New Strategy |
| 31 | + |
| 32 | +1. Add strategy definition to the shared catalog (`us_equity_strategies` or `hk_equity_strategies`) |
| 33 | +2. Set `compatible_platforms` to list which platforms support it |
| 34 | +3. Add to `runtime_enabled_profiles` for the rollout |
| 35 | +4. Each platform repo picks it up via `derive_enabled_profiles_for_platform()` — no per-platform code change needed unless the strategy requires special exclusions |
| 36 | +5. To deploy: update `RUNTIME_TARGET_JSON.strategy_profile` on the target service, and optionally add plugin mounts |
| 37 | + |
| 38 | +**Checklist:** |
| 39 | +``` |
| 40 | +[ ] strategy definition in shared catalog |
| 41 | +[ ] compatible_platforms includes target platform(s) |
| 42 | +[ ] runtime_enabled_profiles includes profile name |
| 43 | +[ ] platform's capability matrix supports required inputs/domain |
| 44 | +[ ] RUNTIME_TARGET_JSON.strategy_profile updated on target service |
| 45 | +[ ] plugin mounts JSON (if any) updated — or rely on auto-sync |
| 46 | +[ ] Scheduler jobs exist for the service (already there if service exists) |
| 47 | +``` |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## Adding a New Platform |
| 52 | + |
| 53 | +1. Create platform repo from template (copy an existing one) |
| 54 | +2. Implement `strategy_registry.py`: |
| 55 | + - Define `PLATFORM_CAPABILITY_MATRIX` (domains, inputs, capabilities) |
| 56 | + - Define `*_EXCLUDED_LIVE_PROFILES` (strategies not yet ready) |
| 57 | + - Derive `ELIGIBLE_STRATEGY_PROFILES` and `*_ENABLED_PROFILES` |
| 58 | +3. Implement `runtime_config_support.py`: |
| 59 | + - Define `PlatformRuntimeSettings` dataclass with all platform-specific fields |
| 60 | + - All non-default fields MUST appear BEFORE any field with a default value |
| 61 | + - Implement `load_platform_runtime_settings()` reading from env vars |
| 62 | +4. Implement broker adapters, market data ports, execution ports |
| 63 | +5. Add Cloud Scheduler jobs: |
| 64 | + - `{platform}-{strategy}-main`: `45 15 * * *` → `/run` |
| 65 | + - `{platform}-{strategy}-precheck`: `45 9 * * *` → `/dry-run` |
| 66 | + - `{platform}-{strategy}-backup`: `52 15 * * 1-5` → `/run` |
| 67 | +6. Set `RUNTIME_TARGET_JSON` on the Cloud Run service |
| 68 | +7. Wire into `MONITOR_DISPATCH_TARGETS_JSON` for cross-platform health checks |
| 69 | + |
| 70 | +**Platform dataclass rule:** |
| 71 | +```python |
| 72 | +@dataclass(frozen=True) |
| 73 | +class PlatformRuntimeSettings: |
| 74 | + # Required fields FIRST (no defaults) |
| 75 | + project_id: str | None |
| 76 | + secret_name: str |
| 77 | + strategy_profile: str |
| 78 | + # ... more required fields ... |
| 79 | + |
| 80 | + # Fields with defaults AFTER all required fields |
| 81 | + notification_channel: str = "telegram" |
| 82 | + dry_run_only: bool = False # ← note: False IS a valid default here |
| 83 | + # ... |
| 84 | +``` |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## Adding a New Plugin |
| 89 | + |
| 90 | +1. Add plugin definition with `signal_path`, `enabled`, `expected_mode` |
| 91 | +2. Add to `{PLATFORM}_STRATEGY_PLUGIN_MOUNTS_JSON` env var: |
| 92 | + ```json |
| 93 | + { |
| 94 | + "strategy_plugins": [{ |
| 95 | + "strategy": "<strategy_profile>", |
| 96 | + "plugin": "<plugin_name>", |
| 97 | + "signal_path": "gs://...", |
| 98 | + "enabled": true, |
| 99 | + "expected_mode": "shadow" |
| 100 | + }] |
| 101 | + } |
| 102 | + ``` |
| 103 | +3. The `strategy` field is auto-synced to match `RUNTIME_TARGET_JSON.strategy_profile` — you can set it to anything and it will be corrected on startup. Setting it correctly is still recommended for documentation. |
| 104 | + |
| 105 | +--- |
| 106 | + |
| 107 | +## Configuration Validation |
| 108 | + |
| 109 | +Before deploying, run: |
| 110 | +```bash |
| 111 | +# Check required env vars |
| 112 | +python scripts/check_required_env.py --platform=schwab --json |
| 113 | + |
| 114 | +# Check strategy-platform consistency |
| 115 | +python scripts/validate_platform_consistency.py |
| 116 | +``` |
| 117 | + |
| 118 | +These should be integrated into CI pipelines for all platform repos. |
| 119 | + |
| 120 | +--- |
| 121 | + |
| 122 | +## Deployment Checklist |
| 123 | + |
| 124 | +When changing a strategy's configuration: |
| 125 | + |
| 126 | +``` |
| 127 | +[ ] RUNTIME_TARGET_JSON updated (ONLY this is required) |
| 128 | +[ ] Deploy the service (Cloud Run picks up new env var) |
| 129 | +[ ] Verify: check Cloud Logging for "[config-sync]" messages |
| 130 | +[ ] Verify: trigger /dry-run via Scheduler or manual POST |
| 131 | +[ ] Verify: check execution report in GCS for expected strategy name |
| 132 | +``` |
| 133 | + |
| 134 | +The auto-sync layer handles everything else (plugin mounts, monitor targets). |
| 135 | + |
| 136 | +--- |
| 137 | + |
| 138 | +## Version History |
| 139 | + |
| 140 | +| Version | Date | Changes | |
| 141 | +|---|---|---| |
| 142 | +| 1.0 | 2026-06-30 | Initial spec: single source of truth, auto-sync, validation scripts | |
0 commit comments