Backtesting engine supporting 11 strategies across US (S&P 500) and CN (CSI 300) markets with open-to-close execution, proportional + fixed per-trade fees. Daily trader (trader.py) with auto/morning/evening/simulate/status commands and cron-friendly `auto` mode for unattended daily runs on a server. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
80 lines
5.5 KiB
Markdown
80 lines
5.5 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## 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.
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# 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 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
|
|
|
|
# Setup
|
|
uv sync # Install/sync dependencies
|
|
```
|
|
|
|
No test suite or linter is configured.
|
|
|
|
## 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`.
|
|
|
|
**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.
|
|
|
|
**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. Not checked into git (only `data/.gitkeep` is tracked).
|
|
- Python 3.12+, managed with `uv`.
|
|
- Do not show matplotlib figures when running backtests; use `--no-plot`.
|
|
|
|
## Server Deployment (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
|
|
|
|
# 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
|
|
```
|