Skip to content

Commit 3f0f9bf

Browse files
author
QuantTradeAI Maintainer
committed
feat(cli): add backtest-model command with execution settings; save artifacts; tests and docs
1 parent dc16f26 commit 3f0f9bf

File tree

13 files changed

+1058
-272
lines changed

13 files changed

+1058
-272
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,4 @@ cython_debug/
172172

173173
data/
174174
models/
175+
reports/

README.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ poetry install
1515
# Fetch data for all symbols
1616
poetry run quanttradeai fetch-data
1717

18-
# Run complete training pipeline
19-
poetry run quanttradeai train
20-
21-
# Evaluate a saved model
22-
poetry run quanttradeai evaluate -m models/trained/AAPL
18+
# Run complete training pipeline
19+
poetry run quanttradeai train
20+
21+
# Evaluate a saved model
22+
poetry run quanttradeai evaluate -m models/trained/AAPL
23+
24+
# Backtest a saved model (end-to-end)
25+
poetry run quanttradeai backtest-model -m models/experiments/<timestamp>/<SYMBOL> \
26+
-c config/model_config.yaml -b config/backtest_config.yaml
2327
```
2428

2529
## ✨ Features
@@ -105,8 +109,12 @@ poetry run quanttradeai fetch-data
105109
# Run complete training pipeline
106110
poetry run quanttradeai train
107111

108-
# Evaluate a trained model
109-
poetry run quanttradeai evaluate -m models/trained/AAPL
112+
# Evaluate a trained model
113+
poetry run quanttradeai evaluate -m models/trained/AAPL
114+
115+
# Backtest a saved model with execution costs
116+
poetry run quanttradeai backtest-model -m models/experiments/<timestamp>/<SYMBOL> \
117+
-c config/model_config.yaml -b config/backtest_config.yaml
110118
```
111119

112120
### Python API

TEMP.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
PR Scope: Model-Integrated Backtesting CLI (backtest-model)
2+
3+
Summary
4+
- Add an end-to-end CLI subcommand `backtest-model` that loads a saved model, generates time-aware test predictions, converts them into trading signals, and runs the vectorized backtester with execution costs/slippage/liquidity. Persist metrics, equity curve, and (optional) trade ledger. This stitches the ML pipeline to the backtesting engine per the Phase 1 roadmap item “Enhanced Backtesting,” providing a single-command, reproducible evaluation of real PnL with costs.
5+
6+
Why This Now
7+
- Current state: Training/evaluation exists (classification metrics), and a powerful backtester exists, but they are decoupled. The README Roadmap emphasizes Enhanced Backtesting in Phase 1. Integrating model outputs with the backtester delivers immediate, decision-grade value and a clear demo path for users (max brownie points).
8+
- Benefits: Single command to quantify strategy viability; avoids confusion between classification scores vs. trading performance; leverages existing time-aware split, execution modeling, and config schemas.
9+
10+
Goals
11+
- Provide `poetry run quanttradeai backtest-model -m <model_dir> [-c <model_cfg>] [-b <bt_cfg>] [flags...]` that:
12+
- Loads model+scaler+feature_columns from `<model_dir>`.
13+
- Loads data via `model_config.yaml`, processes features, creates labels, and performs time-aware split using existing logic.
14+
- Uses the saved `feature_columns` to build X_test and generate predictions for the test window without mutating `feature_columns`.
15+
- Converts predictions to signals (-1/0/1) aligned to `Close` (and `Volume` for liquidity).
16+
- Runs `simulate_trades(..., execution=...)` and `compute_metrics(...)` with execution options from a `backtest_config.yaml` and/or CLI overrides.
17+
- Saves: `metrics.json`, `equity_curve.csv`, `ledger.csv` under `reports/backtests/<timestamp>/<symbol>/`.
18+
- Prints a concise summary to stdout.
19+
20+
Non-Goals
21+
- No new models or feature engineering changes.
22+
- No broker/exchange order execution integration.
23+
- No refactor of `MomentumClassifier` internals (we only read its saved `feature_columns`).
24+
25+
Design & Changes
26+
- CLI: Add a new subparser `backtest-model` in `quanttradeai/main.py` with args:
27+
- `-c/--config` (default `config/model_config.yaml`)
28+
- `-b/--backtest-config` (optional; default `config/backtest_config.yaml` if present)
29+
- `-m/--model-path` (required)
30+
- Optional overrides mirroring existing `backtest` command: `--cost-bps`, `--cost-fixed`, `--slippage-bps`, `--slippage-fixed`, `--liquidity-max-participation`
31+
- Implementation (new function `run_model_backtest`):
32+
1) Load `model_config.yaml` and create `DataLoader`/`DataProcessor`.
33+
2) Fetch data; for each configured symbol: process, label, time-aware split (reuse `time_aware_split`).
34+
3) Load trained model via `MomentumClassifier.load_model(model_path)`.
35+
4) Build `X_test` strictly from `model.feature_columns`; get `y_test` from split df; generate predictions via `model.predict(X_test)`.
36+
5) Construct a minimal DataFrame for backtesting: copy `test_df[['Close','Volume']]` + set `label = predictions`.
37+
6) Load backtest `execution` config (from `--backtest-config` or default), apply CLI overrides (same pattern as existing `backtest` subcommand).
38+
7) Call `simulate_trades(df_bt, execution=exec_cfg)` and `compute_metrics`.
39+
8) Persist artifacts under `reports/backtests/<timestamp>/<symbol>/`.
40+
9) Print concise summary (Sharpe, MDD, CAGR if available) to stdout.
41+
42+
Edge Handling
43+
- Feature column alignment: never call `prepare_data` after `load_model` (it would overwrite `feature_columns`). Select columns using `model.feature_columns` with exact order.
44+
- Missing `Volume`: if absent, inject a large constant volume to keep liquidity logic functional.
45+
- Label space: assumes training used {-1,0,1} from `generate_labels`. Predictions are used as-is; if binary {0,1}, we map `{0:0, 1:1}` and never emit -1.
46+
- Time windows: reuse `time_aware_split` rules (supports `data.test_start`/`data.test_end` or fallback to tail fraction).
47+
48+
Tests
49+
- Add `tests/integration/test_backtest_model_cli.py`:
50+
- Mocks `DataLoader.fetch_data` to return a tiny OHLCV frame; uses a trivial stub model saved to disk with known `feature_columns` and deterministic predictions.
51+
- Runs the CLI via `main.main()` with args for `backtest-model` and validates:
52+
- No exception, stdout contains “Sharpe”/“Max Drawdown”.
53+
- Artifacts created under `reports/backtests/...` with expected files.
54+
- Parametrize with/without backtest overrides to ensure they plumb through.
55+
56+
Docs
57+
- README “Usage” and docs/quick-reference.md: add a “Backtest a saved model” snippet and brief explanation of where outputs are saved.
58+
- docs/getting-started.md: add a short step after Train: “Backtest a trained model.”
59+
60+
Acceptance Criteria
61+
- `poetry run quanttradeai backtest-model -m models/experiments/<ts>/<SYM>` runs end-to-end without code edits, saves artifacts, and prints metrics.
62+
- Works with time-aware test windows if set; otherwise uses last `training.test_size` as test chronologically.
63+
- CLI overrides for costs/slippage/liquidity take effect in results.
64+
65+
Risks & Mitigations
66+
- Mismatch feature columns: enforce using saved `feature_columns` only; error clearly if missing any required column.
67+
- Intraday timeframes: labeling uses bar counts (forward_returns). That’s consistent with current behavior; we will document this and keep configuration of label horizon for a future PR.
68+
69+
Out of Scope (future PRs)
70+
- Configurable labeling horizon/threshold in YAML.
71+
- Multi-timeframe feature fusion (e.g., 1h + 1d features).
72+
- Portfolio-level multi-symbol backtest from model predictions.
73+

docs/getting-started.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,25 @@ This will:
4747
- Optimize hyperparameters automatically
4848
- Save trained models
4949

50-
### 3. Evaluate Results
51-
```bash
52-
# Evaluate a trained model
53-
poetry run quanttradeai evaluate -m models/trained/AAPL
54-
```
55-
56-
## 📊 Understanding the Output
50+
### 3. Evaluate Results
51+
```bash
52+
# Evaluate a trained model
53+
poetry run quanttradeai evaluate -m models/trained/AAPL
54+
```
55+
56+
### 4. Backtest a Saved Model
57+
```bash
58+
# Backtest a saved model on the configured test window (with execution costs)
59+
poetry run quanttradeai backtest-model -m models/experiments/<timestamp>/<SYMBOL> \
60+
-c config/model_config.yaml -b config/backtest_config.yaml
61+
```
62+
63+
This runs an end-to-end evaluation using the model’s saved `feature_columns` and the execution configuration. Artifacts are saved under `reports/backtests/<run_timestamp>/<SYMBOL>/`:
64+
- metrics.json: summary including Sharpe, drawdown, and CAGR (gross and net)
65+
- equity_curve.csv: equity curve time series
66+
- ledger.csv: per-trade fills and costs (when trades occur)
67+
68+
## 📊 Understanding the Output
5769

5870
After running the training pipeline, you'll find:
5971

docs/quick-reference.md

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
Common commands, patterns, and examples for QuantTradeAI.
44

5-
## 🚀 CLI Commands
6-
7-
```bash
8-
# Show help
9-
poetry run quanttradeai --help
5+
## 🚀 CLI Commands
6+
7+
```bash
8+
# Show help
9+
poetry run quanttradeai --help
1010

1111
# Fetch data
1212
poetry run quanttradeai fetch-data
@@ -18,10 +18,15 @@ poetry run quanttradeai train
1818
# Evaluate model
1919
poetry run quanttradeai evaluate -m models/trained/AAPL
2020

21-
# Run backtest
22-
poetry run quanttradeai backtest --config config/backtest_config.yaml
23-
poetry run quanttradeai backtest --cost-bps 5 --slippage-bps 10
24-
```
21+
# Run backtest
22+
poetry run quanttradeai backtest --config config/backtest_config.yaml
23+
poetry run quanttradeai backtest --cost-bps 5 --slippage-bps 10
24+
25+
# Backtest a saved model (end-to-end)
26+
poetry run quanttradeai backtest-model -m models/experiments/<timestamp>/<SYMBOL> \
27+
-c config/model_config.yaml -b config/backtest_config.yaml \
28+
--cost-bps 5 --slippage-fixed 0.01 --liquidity-max-participation 0.25
29+
```
2530

2631
## 📊 Python API Patterns
2732

@@ -62,16 +67,26 @@ classifier.train(X, y)
6267
classifier.save_model("models/trained/AAPL")
6368
```
6469

65-
### Backtesting
66-
```python
67-
from quanttradeai import simulate_trades, compute_metrics
70+
### Backtesting
71+
```python
72+
from quanttradeai import simulate_trades, compute_metrics
6873

6974
# Simulate trades
7075
df_trades = simulate_trades(df_labeled, stop_loss_pct=0.02, take_profit_pct=0.04)
7176

7277
# Calculate metrics
73-
metrics = compute_metrics(df_trades, risk_free_rate=0.02)
74-
```
78+
metrics = compute_metrics(df_trades, risk_free_rate=0.02)
79+
```
80+
81+
### Backtest a Saved Model
82+
```bash
83+
# Uses saved feature_columns and execution config to produce PnL metrics
84+
poetry run quanttradeai backtest-model -m models/experiments/<timestamp>/<SYMBOL> \
85+
-c config/model_config.yaml -b config/backtest_config.yaml
86+
87+
# Artifacts are saved under:
88+
# reports/backtests/<run_timestamp>/<SYMBOL>/{metrics.json,equity_curve.csv,ledger.csv}
89+
```
7590

7691
## 🔧 Technical Indicators
7792

0 commit comments

Comments
 (0)