Files
quant-trading/CLAUDE.md
Gahow Wang 83495bcd23 chore(deploy): keep start scripts and systemd units in deploy/
The three services become quant-trading-monitor, quant-trading-api and
quant-trading-vite, run from /home/gahow/projects/quant-trading. Their
units were previously untracked files in ~/.config/systemd/user.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 11:42:40 +08:00

8.5 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

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

# Backtesting
uv run python main.py                    # Run US backtest (default)
uv run python main.py --market cn        # Run China A-share backtest
uv run python main.py --capital 50000    # Custom starting capital
uv run python main.py --top-n 20         # Override stock selection count
uv run python main.py --years 5          # Backtest last N years only
uv run python main.py --no-plot          # Skip matplotlib charts
uv run python main.py --fixed-fee 2.0    # Add $2 per-trade fixed fee
uv run python main.py --execution open-close  # Signal on open, execute at close

# Daily trading simulator
uv run python trader.py auto --market us --strategy recovery_mom_top10   # Single daily run (for cron)
uv run python trader.py morning --market us --strategy recovery_mom_top10  # Morning: generate orders
uv run python trader.py evening --market us --strategy recovery_mom_top10  # Evening: record execution
uv run python trader.py monitor                                            # Monitor ALL markets & strategies (for tmux)
uv run python trader.py monitor --market us                                # Monitor US only
uv run python trader.py status  --market us --strategy recovery_mom_top10  # Portfolio status
uv run python trader.py simulate --market us --strategy recovery_mom_top10 --start 2026-01-01 --end 2026-04-01  # Historical replay
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)

# 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

Universe provider (universe.py): Dynamically fetches index constituents (S&P 500 from Wikipedia, CSI 300 from Wikipedia) and converts to Yahoo Finance ticker format. Constituent lists are cached daily in data/universe_*.json. New markets are added by registering in UNIVERSES dict.

Data manager (data_manager.py): Persistent price storage in data/{market}.csv (close) and data/{market}_open.csv (open). First run downloads 10 years of history; subsequent runs append only new trading days (fast bulk fetch for gaps ≤7 days). New tickers from index rebalances are backfilled automatically. Tickers with >50% missing data are dropped. Pass with_open=True to also maintain open price files.

Backtest engine (main.py): Orchestrates data loading, strategy execution, and visualization. The backtest() function is vectorized — it takes a strategy and price DataFrame, applies transaction costs (proportional + optional fixed per-trade fee) via turnover, and returns an equity curve. Supports two execution modes: close (classic) and open-close (signal on open prices, execute at close).

Daily trader (trader.py): Live/forward-testing system with persistent portfolio state in data/trader_{market}_{strategy}.json. The auto subcommand runs both signal generation and execution in a single invocation — designed for cron. The simulate subcommand replays a date range day-by-day with realistic portfolio tracking (fractional shares, cash, commissions). Available strategies: recovery_mom_top10, recovery_mom_top20, momentum, momentum_quality, dual_momentum, inverse_vol, trend_following, buy_and_hold, plus 32 factor-combo strategies (fc_{signal}_{freq} — see strategies/factor_combo.py).

Strategy protocol (strategies/base.py): All strategies inherit from Strategy ABC and implement generate_signals(data) → DataFrame where the returned DataFrame contains portfolio weights (rows = dates, columns = assets, values sum to ~1.0 per row). Each strategy is responsible for applying its own 1-day lag via .shift(1) to avoid lookahead bias — the backtest engine does not shift.

Strategies:

  • buy_and_hold.py — Equal-weight static allocation
  • momentum.py — Cross-sectional momentum (12-1 month factor), selects top_n winners
  • inverse_vol.py — Inverse-volatility (risk parity) weighting
  • multi_factor.py — Combines momentum + value factors with benchmark MA timing filter
  • mean_reversion.py — Short-term mean reversion
  • trend_following.py — MA crossover + momentum trend filter
  • dual_momentum.py — Absolute + relative momentum
  • momentum_quality.py — Momentum + return consistency + low drawdown
  • adaptive_momentum.py — Momentum weighted by inverse volatility
  • recovery_momentum.py — Recovery (price/63d low) + 12-1mo momentum composite. Best US performer.
  • factor_combo.py — Configurable factor-combination strategies with daily/weekly/biweekly/monthly rebalancing. US champions: rec_mfilt+deep_upvol (50.7% CAGR monthly), ma200+mom7m+rec126, rec_mfilt+ma200, mom7m+rec126. CN champions: up_cap+quality_mom (26.1% CAGR monthly), down_resil+qual_mom, rec63+mom_gap, up_cap+mom_gap. All registered in trader.py as fc_{signal}_{freq} (e.g., fc_rec_mfilt_deep_upvol_monthly). 32 new strategies total.

Metrics (metrics.py): Standalone functions for portfolio analytics (Sharpe, Sortino, Calmar, max drawdown, etc.). summary() prints a formatted report and returns a dict.

Key Conventions

  • 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, 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

Three systemd --user services, defined in deploy/systemd/, run from /home/gahow/projects/quant-trading:

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
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

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:

uv run python trader.py compare              # US strategies
uv run python trader.py compare --market cn  # CN strategies

Alternative: cron

Run daily after market close. The auto command is idempotent — safe to re-run:

# US market: 5pm ET weekdays
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 /home/gahow/projects/quant-trading && uv run python trader.py auto --market cn --strategy inverse_vol >> data/cron.log 2>&1