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
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
directory: "/python"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codex_pr_review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
OPENAI_MODEL: ${{ vars.OPENAI_MODEL || 'gpt-5.4-mini' }}
CODEX_AUDIT_SERVICE_URL: ${{ secrets.CODEX_AUDIT_SERVICE_URL }}
CODEX_AUDIT_SERVICE_AUDIENCE: ${{ vars.CODEX_AUDIT_SERVICE_AUDIENCE || 'quant-codex-audit' }}
run: python scripts/run_codex_pr_review.py
run: python python/scripts/run_codex_pr_review.py

- name: Upload review diagnostics
if: always()
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codex_review_gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
id: gate
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: python scripts/gate_codex_app_review.py
run: python python/scripts/gate_codex_app_review.py

- name: Upload gate diagnostics
if: always()
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/deploy-strategy-switch-console.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ on:
paths:
- ".github/workflows/deploy-strategy-switch-console.yml"
- "platform-config.json"
- "scripts/build_config.py"
- "scripts/sync_strategy_switch_page_asset.py"
- "python/scripts/build_config.py"
- "python/scripts/sync_strategy_switch_page_asset.py"
- "web/strategy-switch-console/**"
workflow_dispatch:
inputs:
Expand Down Expand Up @@ -54,9 +54,9 @@ jobs:
- name: Build config & assets from platform-config.json
run: |
set -euo pipefail
python3 scripts/build_platform_config.py
python3 scripts/inject_platform_config.py
python3 scripts/sync_strategy_switch_page_asset.py
python3 python/scripts/build_platform_config.py
python3 python/scripts/inject_platform_config.py
python3 python/scripts/sync_strategy_switch_page_asset.py

- name: Validate Worker assets
continue-on-error: true
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/manual-strategy-switch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ jobs:
id: platform
run: |
set -euo pipefail
repo="$(python3 scripts/runtime_settings.py repository "${PLATFORM}")"
repo="$(python3 python/scripts/runtime_settings.py repository "${PLATFORM}")"
echo "repository=${repo}" >> "$GITHUB_OUTPUT"

- name: Fetch existing service targets
Expand Down Expand Up @@ -302,14 +302,14 @@ jobs:
if [ -s "${EXISTING_SERVICE_TARGETS_JSON_FILE:-}" ]; then
args+=(--existing-service-targets-json-file "${EXISTING_SERVICE_TARGETS_JSON_FILE}")
fi
python3 scripts/build_runtime_switch.py "${args[@]}"
python3 scripts/runtime_settings.py validate "${target_file}"
python3 python/scripts/build_runtime_switch.py "${args[@]}"
python3 python/scripts/runtime_settings.py validate "${target_file}"
echo "TARGET_FILE=${target_file}" >> "$GITHUB_ENV"

- name: Preview assignments
run: |
set -euo pipefail
python3 scripts/runtime_settings.py render "${TARGET_FILE}" --format json --redact-values > "${RUNNER_TEMP}/assignments.json"
python3 python/scripts/runtime_settings.py render "${TARGET_FILE}" --format json --redact-values > "${RUNNER_TEMP}/assignments.json"
python - <<'PY' "${TARGET_FILE}" "${RUNNER_TEMP}/assignments.json" >> "$GITHUB_STEP_SUMMARY"
import json
import sys
Expand All @@ -336,7 +336,7 @@ jobs:

- name: Apply GitHub variable updates
if: env.APPLY_SWITCH == 'true'
run: python3 scripts/runtime_settings.py apply "${TARGET_FILE}" --yes
run: python3 python/scripts/runtime_settings.py apply "${TARGET_FILE}" --yes

- name: Dispatch platform sync workflow
if: env.APPLY_SWITCH == 'true' && env.TRIGGER_PLATFORM_SYNC == 'true'
Expand Down Expand Up @@ -374,7 +374,7 @@ jobs:
import urllib.request

root = os.environ.get("GITHUB_WORKSPACE") or os.getcwd()
sys.path.insert(0, os.path.join(root, "scripts"))
sys.path.insert(0, os.path.join(root, "python", "scripts"))
import runtime_settings

base_url = os.environ["STRATEGY_SWITCH_CONSOLE_URL"].rstrip("/")
Expand Down
37 changes: 24 additions & 13 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ permissions:
contents: read

jobs:
validate:
python:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
Expand All @@ -18,9 +18,6 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- uses: actions/setup-node@v6
with:
node-version: "22"
- name: Check whitespace
run: |
set -euo pipefail
Expand All @@ -31,23 +28,37 @@ jobs:
git diff-tree --check --no-commit-id --root -r HEAD
fi
- name: Validate platform config
run: python3 scripts/build_config.py --check
run: python3 python/scripts/build_config.py --check
- name: Validate runtime targets
run: python3 scripts/runtime_settings.py validate
- name: Run unit tests
run: python3 -m unittest discover -s tests -v
run: python3 python/scripts/runtime_settings.py validate
- name: Run Python unit tests
run: python3 -m unittest discover -s python/tests -v
- name: Checkout internal dependency consumer repos
env:
GH_TOKEN: ${{ github.token }}
run: bash scripts/checkout_internal_dependency_consumers.sh --output-root ..
run: bash python/shell/checkout_internal_dependency_consumers.sh --output-root ..
- name: Report internal dependency matrix
run: python3 scripts/check_internal_dependency_matrix.py --projects-root .. --json --strict --require-consumer-files
run: python3 python/scripts/check_internal_dependency_matrix.py --projects-root .. --json --strict --require-consumer-files

js:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: "22"
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Validate strategy switch web assets
run: |
set -euo pipefail
python3 scripts/build_config.py --check
python3 scripts/build_config.py
python3 scripts/sync_strategy_switch_page_asset.py
python3 python/scripts/build_config.py --check
python3 python/scripts/build_config.py
python3 python/scripts/sync_strategy_switch_page_asset.py
git diff --exit-code -- web/strategy-switch-console/page_asset.js web/strategy-switch-console/strategy_profiles_asset.js
jq empty web/strategy-switch-console/strategy-profiles.example.json
node --experimental-default-type=module tests/strategy_switch_worker_validation.mjs
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,23 @@ It supports the system but does not decide which strategy should be live. Strate

## Repository layout

- `tests/`: unit, contract, and regression tests.
- `python/`: Python tooling (scripts, tests, pyproject.toml) — validation, code generation, deployment scripts.
- `web/`: JavaScript web app (Cloudflare Workers strategy switch console).
- `schemas/`: JSON Schema files shared by both Python and JS.
- `tests/`: JavaScript unit/integration tests.
- `.github/workflows/`: CI, scheduled jobs, release, or deployment workflows.
- `scripts/`: operator scripts and local helpers.
- `docs/ARCHITECTURE.md`: Detailed architecture documentation.

## Quick start

```bash
python3 scripts/runtime_settings.py validate
python3 -m unittest discover -s tests -v
python3 python/scripts/runtime_settings.py validate
python3 -m unittest discover -s python/tests -v
```

## Manual Strategy Switch

`.github/workflows/manual-strategy-switch.yml` provides a central manual switch entrypoint. It builds a transient runtime target from workflow inputs, validates it with `scripts/runtime_settings.py`, and writes GitHub variables into the target platform repository. It currently supports `longbridge`, `ibkr`, `schwab`, and `firstrade`.
`.github/workflows/manual-strategy-switch.yml` provides a central manual switch entrypoint. It builds a transient runtime target from workflow inputs, validates it with `python/scripts/runtime_settings.py`, and writes GitHub variables into the target platform repository. It currently supports `longbridge`, `ibkr`, `schwab`, and `firstrade`.

Recommended flow:

Expand Down
13 changes: 8 additions & 5 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,23 @@ QuantRuntimeSettings 是 QuantStrategyLab 的运行配置包。为 QuantStrategy

## 仓库结构

- `tests/`:单元测试、契约测试和回归测试。
- `python/`:Python 工具链(脚本、测试、pyproject.toml)— 校验、代码生成、部署工具。
- `web/`:JavaScript Web 应用(Cloudflare Workers 策略切换控制台)。
- `schemas/`:JSON Schema 文件,Python 和 JS 共享。
- `tests/`:JavaScript 单元测试和集成测试。
- `.github/workflows/`:CI、定时任务、发布或部署 workflow。
- `scripts/`:运维脚本和本地辅助工具
- `docs/ARCHITECTURE.md`:详细架构文档

## 快速开始

```bash
python3 scripts/runtime_settings.py validate
python3 -m unittest discover -s tests -v
python3 python/scripts/runtime_settings.py validate
python3 -m unittest discover -s python/tests -v
```

## 一键切换策略

`.github/workflows/manual-strategy-switch.yml` 提供手动触发的中控切换入口。它会根据表单参数生成运行目标,复用 `scripts/runtime_settings.py` 校验并写入目标平台仓库的 GitHub variables。当前支持 `longbridge`、`ibkr`、`schwab`、`firstrade`。
`.github/workflows/manual-strategy-switch.yml` 提供手动触发的中控切换入口。它会根据表单参数生成运行目标,复用 `python/scripts/runtime_settings.py` 校验并写入目标平台仓库的 GitHub variables。当前支持 `longbridge`、`ibkr`、`schwab`、`firstrade`。

推荐流程:

Expand Down
148 changes: 148 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# QuantRuntimeSettings Architecture

## Overview

QuantRuntimeSettings is a **config-driven** runtime settings package that serves as the central control plane for QuantStrategyLab deployments. It defines versioned strategy-to-platform assignments and hosts a Cloudflare Workers-based strategy switch console.

The repository has a **three-tier architecture** built around a single source of truth:

```
platform-config.json (single source of truth)
|
v
Python scripts (validation, code generation, deployment tooling)
|
v
Generated assets (config.js, page_asset.js, strategy_profiles_asset.js)
|
v
Web application (Cloudflare Worker + frontend SPA)
```

---

## Directory Layout

```
.
├── platform-config.json # Central configuration (single source of truth)
├── internal_dependency_matrix.json # Internal git dependency pin tracking
├── python/ # Python tooling (tests, CI, scripts)
│ ├── pyproject.toml # Python project definition & linter config
│ ├── scripts/ # Build & validation scripts
│ │ ├── build_config.py # Full build pipeline
│ │ ├── build_platform_config.py # Generate config.js from platform-config.json
│ │ ├── build_runtime_switch.py # Build transient runtime targets
│ │ ├── runtime_settings.py # Core validation & assignment engine
│ │ ├── check_internal_dependency_matrix.py
│ │ ├── gate_codex_app_review.py # PR merge gate
│ │ ├── inject_platform_config.py # Inject config into index.html
│ │ ├── run_codex_pr_review.py # Codex AI PR review
│ │ └── sync_strategy_switch_page_asset.py
│ ├── tests/ # Python unit tests
│ │ ├── test_runtime_settings.py
│ │ └── test_internal_dependency_matrix.py
│ └── shell/ # Shell scripts (Python ecosystem)
│ └── checkout_internal_dependency_consumers.sh
├── web/ # JavaScript web application
│ └── strategy-switch-console/ # Cloudflare Workers app
│ ├── worker.js # Worker backend (OAuth, routing, KV)
│ ├── index.html # SPA shell
│ ├── app.js # Frontend JavaScript
│ ├── app.css # Frontend styles
│ ├── config.js # Generated: Platform config constants
│ ├── page_asset.js # Generated: Embedded index.html
│ ├── strategy_profiles_asset.js # Generated: Strategy catalog
│ ├── app_css.js # Generated: Embedded styles
│ ├── app_js.js # Generated: Embedded JS
│ └── wrangler.toml.example # Cloudflare Workers config template
├── schemas/ # Shared JSON Schema (consumed by both)
│ └── runtime-target.schema.json # Runtime target validation schema
├── tests/ # JavaScript tests
│ ├── strategy_switch_worker_validation.mjs
│ └── test_cash_financing.js
├── docs/ # Documentation
├── examples/targets/ # Example runtime targets per platform
├── prompts/ # LLM prompt templates
└── .github/workflows/ # CI/CD workflows
├── validate.yml # Python + JS validation (split jobs)
├── deploy-strategy-switch-console.yml
├── manual-strategy-switch.yml
├── codex_pr_review.yml
└── codex_review_gate.yml
```

---

## Tier 1: Source of Truth — `platform-config.json`

Defines the entire runtime configuration universe:

- **4 domains**: `us_equity`, `hk_equity`, `cn_equity`, `crypto`
- **6 platforms**: `longbridge`, `ibkr`, `schwab`, `firstrade`, `qmt`, `binance`
- **18 strategy profiles** with features: income layer, option overlay, DCA, combo
- **Platform capabilities, CSS theming, default accounts, repositories, variable scopes**

Never hardcode platform or strategy data in frontend code — regenerate from this file.

---

## Tier 2: Python Tooling (`python/`)

The `python/` directory contains all Python code, organized as a self-contained project with its own `pyproject.toml`.

**Key scripts:**

| Script | Purpose |
|--------|---------|
| `build_config.py` | Full pipeline: validate config, generate strategy profiles, inject into index.html |
| `build_platform_config.py` | Generate `config.js` (ES module) from `platform-config.json` |
| `runtime_settings.py` | Core engine: validate targets, render variables, apply via `gh` CLI |
| `build_runtime_switch.py` | Build transient runtime targets for manual strategy switch |
| `inject_platform_config.py` | Inject platform config globals into `index.html` |
| `sync_strategy_switch_page_asset.py` | Embed HTML/JSON as ES module assets for Worker deployment |

**Dependency boundary:** Python scripts consume `schemas/runtime-target.schema.json`, `platform-config.json`, and write to `web/strategy-switch-console/`. They do **not** depend on the JavaScript code.

---

## Tier 3: Web Application (`web/`)

A Cloudflare Workers-based strategy switch console. Built with vanilla JS (no framework) and deployed via Wrangler.

**Key files:**

| File | Role |
|------|------|
| `worker.js` | Backend: OAuth, session management, config serving, switch dispatch, KV caching |
| `index.html` | SPA shell with bilingual (zh/en) UI, platform selection, strategy configuration |
| `app.js` | Frontend form logic, i18n, summary panel |
| `config.js` (generated) | Platform config constants consumed by both frontend and worker |

**Dependency boundary:** The web app consumes generated assets (`config.js`, `page_asset.js`) and reads `platform-config.json` indirectly via the Worker API. It does **not** depend on Python scripts at runtime.

---

## CI/CD: Independent Validation

The `validate.yml` workflow runs **two independent jobs**:

1. **`python`** — Python tests, config validation, runtime target validation, dependency matrix checks
2. **`js`** — JS module syntax checks, Worker asset validation, SPA integration tests

Neither job depends on the other. This ensures that a change to Python scripts doesn't need to wait for JS tests, and vice versa.

---

## Change Guide

- **Add a platform/strategy**: Edit `platform-config.json`, then run `python3 python/scripts/build_config.py` to regenerate all derived files.
- **Modify build logic**: Edit files in `python/scripts/`, run `python3 -m unittest discover -s python/tests`.
- **Modify web UI**: Edit files in `web/strategy-switch-console/`, run `node tests/strategy_switch_worker_validation.mjs`.
- **Update runner**: Run both Python and JS validation locally before committing.
File renamed without changes.
File renamed without changes.
8 changes: 4 additions & 4 deletions scripts/build_config.py → python/scripts/build_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"""Build pipeline: platform-config.json → all derived files.

Usage:
python3 scripts/build_config.py # full build
python3 scripts/build_config.py --check # only validate config
python3 python/scripts/build_config.py # full build
python3 python/scripts/build_config.py --check # only validate config

Adds/modifies:
web/strategy-switch-console/strategy-profiles.example.json
Expand All @@ -20,7 +20,7 @@
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
ROOT = Path(__file__).resolve().parents[2]
CONFIG_PATH = ROOT / "platform-config.json"
STRATEGY_PROFILES_PATH = ROOT / "web" / "strategy-switch-console" / "strategy-profiles.example.json"
STRATEGY_PROFILES_ASSET = ROOT / "web" / "strategy-switch-console" / "strategy_profiles_asset.js"
Expand Down Expand Up @@ -207,7 +207,7 @@ def inject_into_index_html(config: dict) -> None:

def run_sync_script() -> None:
"""Run the existing sync script to regenerate page_asset.js + strategy_profiles_asset.js."""
sync_script = ROOT / "scripts" / "sync_strategy_switch_page_asset.py"
sync_script = ROOT / "python" / "scripts" / "sync_strategy_switch_page_asset.py"
if sync_script.exists():
subprocess.run([sys.executable, str(sync_script)], cwd=ROOT, check=True)
print(" Ran sync_strategy_switch_page_asset.py")
Expand Down
Loading
Loading