diff --git a/CLAUDE.md b/CLAUDE.md index d753ade..13151e7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,14 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -Quantitative backtesting framework for comparing equity trading strategies across multiple markets. Supports US (S&P 500) and China A-shares (CSI 300). Uses Yahoo Finance data with persistent local CSV storage. Includes a daily trading simulator with automated cron support. +quant-trading: a quantitative backtesting framework and live forward-testing trader for equity strategies across US (S&P 500) and China A-shares (CSI 300), plus a web UI to browse backtests and live books. Uses Yahoo Finance data with persistent local CSV storage. + +The repository has two halves that share one data directory and one `.env`: + +- **Python engine** (repo root, `uv`): strategies, backtests, `trader.py`, research scripts. +- **Web UI and API** (`web/`, Node + React + Vite): the API spawns `uv run python bridge.py {list,backtest,live}` at the repo root and reads `data/precomputed/backtest_results.json`, written by `precompute_backtest.py`. + +`bridge.py`'s JSON output and `web/src/shared/strategyTypes.ts` are one contract: change both in the same commit. ## Commands @@ -30,11 +37,21 @@ uv run python trader.py simulate --market us --strategy recovery_mom_top10 --sta uv run python trader.py log --market us --strategy sim_recovery_mom_top10 --start 2026-03-01 # View daily log uv run python trader.py simulate --integer-shares --fixed-fee 2.0 ... # Integer shares mode +# Precompute the strategy page's backtests (writes data/precomputed/) +uv run python precompute_backtest.py + # Setup uv sync # Install/sync dependencies -``` +cp .env.example .env # Then fill IPADS_API_KEY and QUANT_MARKET_PROXY +(cd web && npm ci) -No test suite or linter is configured. +# Tests +uv run python -m unittest discover tests +(cd web && npm test && npm run build) + +# Web UI in development (API :8787, Vite :5173) +(cd web && npm run dev) +``` ## Architecture @@ -67,36 +84,44 @@ No test suite or linter is configured. - Strategies output **weights**, not buy/sell signals. Weights are normalized so each row sums to 1 (or 0 during warm-up). - Warm-up periods: each strategy zeros out its first N rows where indicators are undefined. -- `data/` contains persistent price CSVs, universe JSON caches, and trader state files. Not checked into git (only `data/.gitkeep` is tracked). +- `data/` contains persistent price CSVs, universe JSON caches, and trader state files, plus `data/precomputed/` (precomputed backtests) and `data/web/` (watchlist, per-stock cache, backtest result cache). Not checked into git (only `data/.gitkeep` and `data/sp500_history.json` are tracked). - Python 3.12+, managed with `uv`. - Do not show matplotlib figures when running backtests; use `--no-plot`. ## Server Deployment -### Option 1: tmux monitor (recommended) +Three `systemd --user` services, defined in `deploy/systemd/`, run from `/home/gahow/projects/quant-trading`: -Single process monitors both US and CN markets. Two phases per market daily — morning (open → signals) and evening (close → execute). All 9 strategies run for each market. +| Service | Script | Role | +|---|---|---| +| `quant-trading-monitor` | `deploy/start-monitor.sh` | `trader.py monitor`: morning/evening phases for US + CN, all live strategies | +| `quant-trading-api` | `deploy/start-web-api.sh` | Web API on `127.0.0.1:8787` | +| `quant-trading-vite` | `deploy/start-web-vite.sh` | Vite on `127.0.0.1:5174`, behind nginx on `:5443` | ```bash -tmux new -s quant -uv run python trader.py monitor # Both US + CN, all strategies -# Ctrl-B D to detach; tmux attach -t quant to reconnect +cp deploy/systemd/*.service ~/.config/systemd/user/ +systemctl --user daemon-reload +systemctl --user enable --now quant-trading-monitor quant-trading-api quant-trading-vite +journalctl --user -u quant-trading-monitor -f +``` -# After a month, compare: +The monitor catches up on startup, so restarting it between phases is safe. If it starts mid-day (after open, before close), it falls back to `auto` mode for the evening phase. + +Compare live books after a while: + +```bash uv run python trader.py compare # US strategies uv run python trader.py compare --market cn # CN strategies ``` -If monitor starts mid-day (after open, before close), it automatically falls back to `auto` mode for the evening phase. - -### Option 2: Cron +### Alternative: cron Run daily after market close. The `auto` command is idempotent — safe to re-run: ```bash # US market: 5pm ET weekdays -0 17 * * 1-5 cd /path/to/quant && uv run python trader.py auto --market us --strategy recovery_mom_top10 >> data/cron.log 2>&1 +0 17 * * 1-5 cd /home/gahow/projects/quant-trading && uv run python trader.py auto --market us --strategy recovery_mom_top10 >> data/cron.log 2>&1 # CN market: 4pm CST weekdays -0 16 * * 1-5 cd /path/to/quant && uv run python trader.py auto --market cn --strategy inverse_vol >> data/cron.log 2>&1 +0 16 * * 1-5 cd /home/gahow/projects/quant-trading && uv run python trader.py auto --market cn --strategy inverse_vol >> data/cron.log 2>&1 ``` diff --git a/scripts/start-monitor.sh b/deploy/start-monitor.sh similarity index 90% rename from scripts/start-monitor.sh rename to deploy/start-monitor.sh index 3cbae42..2d1c2c3 100755 --- a/scripts/start-monitor.sh +++ b/deploy/start-monitor.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Long-running live-trader monitor (US + CN, all strategies). -# Started by the quant-monitor.service systemd --user unit; replaces the +# Started by the quant-trading-monitor.service systemd --user unit; replaces the # old "tmux new -s quant; uv run python trader.py monitor" workflow. set -euo pipefail diff --git a/web/scripts/start-server.sh b/deploy/start-web-api.sh similarity index 87% rename from web/scripts/start-server.sh rename to deploy/start-web-api.sh index 77687f8..021e462 100755 --- a/web/scripts/start-server.sh +++ b/deploy/start-web-api.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../web" && pwd)" cd "${ROOT_DIR}" export PATH="/home/gahow/.local/bin:/home/gahow/.nvm/versions/node/v24.13.1/bin:$PATH" diff --git a/web/scripts/start-vite.sh b/deploy/start-web-vite.sh similarity index 83% rename from web/scripts/start-vite.sh rename to deploy/start-web-vite.sh index 8e72090..4128a5a 100755 --- a/web/scripts/start-vite.sh +++ b/deploy/start-web-vite.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../web" && pwd)" cd "${ROOT_DIR}" export PATH="/home/gahow/.nvm/versions/node/v24.13.1/bin:$PATH" diff --git a/deploy/systemd/quant-trading-api.service b/deploy/systemd/quant-trading-api.service new file mode 100644 index 0000000..daefab6 --- /dev/null +++ b/deploy/systemd/quant-trading-api.service @@ -0,0 +1,14 @@ +[Unit] +Description=Quant trading web API server +After=network-online.target + +[Service] +Type=simple +WorkingDirectory=/home/gahow/projects/quant-trading/web +ExecStart=/home/gahow/projects/quant-trading/deploy/start-web-api.sh +Restart=always +RestartSec=3 +Environment=NODE_ENV=production + +[Install] +WantedBy=default.target diff --git a/deploy/systemd/quant-trading-monitor.service b/deploy/systemd/quant-trading-monitor.service new file mode 100644 index 0000000..aaf099a --- /dev/null +++ b/deploy/systemd/quant-trading-monitor.service @@ -0,0 +1,14 @@ +[Unit] +Description=Quant live trader monitor (US + CN, all strategies) +After=network-online.target + +[Service] +Type=simple +WorkingDirectory=/home/gahow/projects/quant-trading +ExecStart=/home/gahow/projects/quant-trading/deploy/start-monitor.sh +Restart=always +RestartSec=10 +Environment=PYTHONUNBUFFERED=1 + +[Install] +WantedBy=default.target diff --git a/deploy/systemd/quant-trading-vite.service b/deploy/systemd/quant-trading-vite.service new file mode 100644 index 0000000..b01019a --- /dev/null +++ b/deploy/systemd/quant-trading-vite.service @@ -0,0 +1,13 @@ +[Unit] +Description=Quant trading web frontend (Vite dev server behind nginx) +After=network-online.target + +[Service] +Type=simple +WorkingDirectory=/home/gahow/projects/quant-trading/web +ExecStart=/home/gahow/projects/quant-trading/deploy/start-web-vite.sh +Restart=always +RestartSec=3 + +[Install] +WantedBy=default.target diff --git a/web/README.md b/web/README.md index 5ebc818..f36b3b8 100644 --- a/web/README.md +++ b/web/README.md @@ -1,6 +1,8 @@ -# Personal Stock Agent +# quant-trading web -统一个人股票监控 MVP,支持 A股、港股、美股自选股,按日生成监控报告。数据接口固定使用 IPADS Responses API,密钥从 `.env` 的 `IPADS_API_KEY` 读取。 +Web UI and API for the quant-trading repository: strategy backtests and live books (via `../bridge.py`), plus a personal watchlist agent. + +统一个人股票监控 MVP,支持 A股、港股、美股自选股,按日生成监控报告。数据接口固定使用 IPADS Responses API,密钥从仓库根目录 `.env` 的 `IPADS_API_KEY` 读取。 ## Run @@ -61,10 +63,6 @@ The response output text must be JSON matching the stock snapshot schema used by ## Local cache -Persistent app data defaults to `./data` and can be moved with: +Web state lives in the repo-level `data/web/` (see `src/server/paths.ts`): `watchlist.json`, per-stock snapshot/K-line/financial data under `cache/`, and backtest results under `strategy_cache/`. The strategy page reads `data/precomputed/backtest_results.json`, written by `precompute_backtest.py` at the repo root. -```env -STOCK_AGENT_DATA_DIR=/path/to/stock-agent-data -``` - -The backend stores watchlist data in `watchlist.json` and per-stock cached snapshot/K-line/financial data under `cache/`. +Production runs as systemd services; see "Server Deployment" in the root `CLAUDE.md`.