chore: manage env with uv (pyproject + lockfile)
Migrate dependency management from requirements.txt to uv. Runtime deps move to pyproject.toml with pytest in the dev group; uv.lock pins the resolved set. Docs updated to use `uv sync` / `uv run`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,19 +6,23 @@ A modular Chinese A-share quant research framework. Daily frequency only (Phase
|
|||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
|
The env is managed with **uv**. `uv sync` creates `.venv` from `pyproject.toml` + `uv.lock`; `uv run <cmd>` runs inside it (no manual activation needed).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt # install deps
|
uv sync # create/refresh .venv from the lockfile (incl. dev group)
|
||||||
python3 -m pytest tests/ -v # all tests
|
uv run python -m pytest tests/ -v # all tests
|
||||||
python3 -m pytest tests/test_alpha.py -v # single file (test_alpha is network-free)
|
uv run python -m pytest tests/test_alpha.py -v # single file (test_alpha is network-free)
|
||||||
python3 -m pytest tests/test_alpha.py::test_evaluate_alpha_keys -v # single test
|
uv run python -m pytest tests/test_alpha.py::test_evaluate_alpha_keys -v # single test
|
||||||
|
|
||||||
# Pipeline — each phase is independent: reads parquet, writes parquet.
|
# Pipeline — each phase is independent: reads parquet, writes parquet.
|
||||||
python3 cli.py data download --universe csi500 --start-date 2017-01-01 # → data/daily_bars/csi500/ (month-partitioned)
|
uv run python cli.py data download --universe csi500 --start-date 2017-01-01 # → data/daily_bars/csi500/ (month-partitioned)
|
||||||
python3 cli.py alpha reversal --data-path data/daily_bars/<universe> # --data-path is the dataset DIR
|
uv run python cli.py alpha reversal --data-path data/daily_bars/<universe> # --data-path is the dataset DIR
|
||||||
python3 cli.py alpha eval --alpha-path alphas/<file>.pq --data-path data/daily_bars/<universe>
|
uv run python cli.py alpha eval --alpha-path alphas/<file>.pq --data-path data/daily_bars/<universe>
|
||||||
python3 cli.py combo combine --alpha-paths a.pq,b.pq --combo-name eq --method equal_weight
|
uv run python cli.py combo combine --alpha-paths a.pq,b.pq --combo-name eq --method equal_weight
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Add a runtime dep with `uv add <pkg>`, a dev/test dep with `uv add --dev <pkg>` (both update `pyproject.toml` + `uv.lock`).
|
||||||
|
|
||||||
Note: `tests/test_downloader.py` hits the network (live baostock/akshare); `tests/test_alpha.py` is pure and fast.
|
Note: `tests/test_downloader.py` hits the network (live baostock/akshare); `tests/test_alpha.py` is pure and fast.
|
||||||
|
|
||||||
## Architecture: one decoupled pipeline
|
## Architecture: one decoupled pipeline
|
||||||
@@ -57,9 +61,9 @@ Each alpha is a class subclassing `BaseAlpha` (`pipeline/alpha/base.py`), living
|
|||||||
- **External alphas** (authored outside this repo) are the point of the design: write a `@register_alpha class MyAlpha(BaseAlpha)` in any `.py` file, then register it at runtime with `--alpha-module path/to/file.py` (or a dotted module path). See `examples/alphas/mean_reversion.py` for a working example, and `tests/test_alpha.py::test_load_external_alpha_module`.
|
- **External alphas** (authored outside this repo) are the point of the design: write a `@register_alpha class MyAlpha(BaseAlpha)` in any `.py` file, then register it at runtime with `--alpha-module path/to/file.py` (or a dotted module path). See `examples/alphas/mean_reversion.py` for a working example, and `tests/test_alpha.py::test_load_external_alpha_module`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cli.py alpha list # registered alpha types
|
uv run python cli.py alpha list # registered alpha types
|
||||||
python3 cli.py alpha list --alpha-module my_alpha.py # incl. an external one
|
uv run python cli.py alpha list --alpha-module my_alpha.py # incl. an external one
|
||||||
python3 cli.py alpha compute --alpha-module my_alpha.py \
|
uv run python cli.py alpha compute --alpha-module my_alpha.py \
|
||||||
--alpha-type my_alpha --alpha-name run1 --param decay=0.9 --data-path <data>.pq
|
--alpha-type my_alpha --alpha-name run1 --param decay=0.9 --data-path <data>.pq
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -39,36 +39,38 @@ Data comes from **baostock (primary)** with **akshare (fallback)**.
|
|||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
The env is managed with [uv](https://docs.astral.sh/uv/). `uv sync` builds `.venv` from `pyproject.toml` + `uv.lock`; prefix commands with `uv run` (no manual activation needed).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install -r requirements.txt
|
uv sync
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Download daily bars for a few symbols (writes a month-partitioned dataset).
|
# 1. Download daily bars for a few symbols (writes a month-partitioned dataset).
|
||||||
python3 cli.py data download \
|
uv run python cli.py data download \
|
||||||
--universe sh600000,sz000001,sh600519 \
|
--universe sh600000,sz000001,sh600519 \
|
||||||
--start-date 2024-01-01 --end-date 2024-03-31 \
|
--start-date 2024-01-01 --end-date 2024-03-31 \
|
||||||
--output-dir data/daily_bars
|
--output-dir data/daily_bars
|
||||||
|
|
||||||
# 2. Compute an alpha (position weights) from that data.
|
# 2. Compute an alpha (position weights) from that data.
|
||||||
# --data-path is the dataset DIRECTORY ({output-dir}/{universe}).
|
# --data-path is the dataset DIRECTORY ({output-dir}/{universe}).
|
||||||
python3 cli.py alpha reversal \
|
uv run python cli.py alpha reversal \
|
||||||
--data-path "data/daily_bars/sh600000,sz000001,sh600519"
|
--data-path "data/daily_bars/sh600000,sz000001,sh600519"
|
||||||
|
|
||||||
# 3. Evaluate it (return / Sharpe / turnover / drawdown).
|
# 3. Evaluate it (return / Sharpe / turnover / drawdown).
|
||||||
python3 cli.py alpha eval \
|
uv run python cli.py alpha eval \
|
||||||
--alpha-path alphas/reversal_5d.pq \
|
--alpha-path alphas/reversal_5d.pq \
|
||||||
--data-path "data/daily_bars/sh600000,sz000001,sh600519"
|
--data-path "data/daily_bars/sh600000,sz000001,sh600519"
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
python3 -m pytest tests/ -v # tests/test_alpha.py is network-free; test_downloader.py hits the network
|
uv run python -m pytest tests/ -v # tests/test_alpha.py is network-free; test_downloader.py hits the network
|
||||||
```
|
```
|
||||||
|
|
||||||
## CLI reference
|
## CLI reference
|
||||||
|
|
||||||
All commands are subcommands of `python3 cli.py`. Add `--help` to any of them.
|
All commands are subcommands of `uv run python cli.py`. Add `--help` to any of them.
|
||||||
|
|
||||||
### `data download` — fetch daily bars → partitioned parquet dataset
|
### `data download` — fetch daily bars → partitioned parquet dataset
|
||||||
|
|
||||||
@@ -93,8 +95,8 @@ set. Symbols use the internal `sh600000` / `sz000001` form (exchange prefix + co
|
|||||||
### `alpha list` — show registered alpha types
|
### `alpha list` — show registered alpha types
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cli.py alpha list
|
uv run python cli.py alpha list
|
||||||
python3 cli.py alpha list --alpha-module path/to/my_alpha.py # include an external alpha
|
uv run python cli.py alpha list --alpha-module path/to/my_alpha.py # include an external alpha
|
||||||
```
|
```
|
||||||
|
|
||||||
### `alpha compute` — alpha class → weights parquet
|
### `alpha compute` — alpha class → weights parquet
|
||||||
@@ -114,7 +116,7 @@ Only the params an alpha's `__init__` accepts are forwarded, so passing extras
|
|||||||
(e.g. `--vol-window` to a reversal alpha) is harmless.
|
(e.g. `--vol-window` to a reversal alpha) is harmless.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cli.py alpha compute \
|
uv run python cli.py alpha compute \
|
||||||
--data-path <data>.pq \
|
--data-path <data>.pq \
|
||||||
--alpha-type reversal_vol --alpha-name rv_5_20 \
|
--alpha-type reversal_vol --alpha-name rv_5_20 \
|
||||||
--lookback 5 --vol-window 20
|
--lookback 5 --vol-window 20
|
||||||
@@ -123,14 +125,14 @@ python3 cli.py alpha compute \
|
|||||||
Shortcuts for the two most common built-ins:
|
Shortcuts for the two most common built-ins:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cli.py alpha reversal --data-path <data>.pq --lookback 5
|
uv run python cli.py alpha reversal --data-path <data>.pq --lookback 5
|
||||||
python3 cli.py alpha reversal-vol --data-path <data>.pq --lookback 5 --vol-window 20
|
uv run python cli.py alpha reversal-vol --data-path <data>.pq --lookback 5 --vol-window 20
|
||||||
```
|
```
|
||||||
|
|
||||||
### `alpha eval` — score an alpha as a portfolio
|
### `alpha eval` — score an alpha as a portfolio
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cli.py alpha eval --alpha-path alphas/<name>.pq --data-path <data>.pq
|
uv run python cli.py alpha eval --alpha-path alphas/<name>.pq --data-path <data>.pq
|
||||||
```
|
```
|
||||||
|
|
||||||
Interprets the weights as a portfolio and reports cumulative return, annual
|
Interprets the weights as a portfolio and reports cumulative return, annual
|
||||||
@@ -148,7 +150,7 @@ position weights, not return predictors.
|
|||||||
| `--output-dir` | `combos` | Output directory |
|
| `--output-dir` | `combos` | Output directory |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cli.py combo combine \
|
uv run python cli.py combo combine \
|
||||||
--alpha-paths alphas/reversal_5d.pq,alphas/reversal_vol_5d_20d.pq \
|
--alpha-paths alphas/reversal_5d.pq,alphas/reversal_vol_5d_20d.pq \
|
||||||
--combo-name eq --method equal_weight
|
--combo-name eq --method equal_weight
|
||||||
```
|
```
|
||||||
@@ -166,9 +168,9 @@ directory) to stdout, without writing a throwaway script.
|
|||||||
| `--info` | off | Show shape + dtypes instead of the rows |
|
| `--info` | off | Show shape + dtypes instead of the rows |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cli.py pqcat alphas/reversal_5d.pq # dump all rows
|
uv run python cli.py pqcat alphas/reversal_5d.pq # dump all rows
|
||||||
python3 cli.py pqcat data/daily_bars/csi500 --info # shape + dtypes
|
uv run python cli.py pqcat data/daily_bars/csi500 --info # shape + dtypes
|
||||||
python3 cli.py pqcat data/daily_bars/csi500 -n 10 -c symbol_id,date,close,vwap
|
uv run python cli.py pqcat data/daily_bars/csi500 -n 10 -c symbol_id,date,close,vwap
|
||||||
```
|
```
|
||||||
|
|
||||||
**Standalone command.** `tools/pqcat.py` has no repo dependencies, so it can be
|
**Standalone command.** `tools/pqcat.py` has no repo dependencies, so it can be
|
||||||
@@ -195,7 +197,7 @@ volume over a time range.
|
|||||||
| `-c, --columns` | `close,volume` | Comma-separated bar columns to show |
|
| `-c, --columns` | `close,volume` | Comma-separated bar columns to show |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cli.py alphaview \
|
uv run python cli.py alphaview \
|
||||||
--data-path data/daily_bars/csi500 \
|
--data-path data/daily_bars/csi500 \
|
||||||
--alpha-path alphas/reversal_5d.pq,alphas/momentum_5d.pq \
|
--alpha-path alphas/reversal_5d.pq,alphas/momentum_5d.pq \
|
||||||
--symbol sh600000 --start-date 2024-01-01 --end-date 2024-03-31 \
|
--symbol sh600000 --start-date 2024-01-01 --end-date 2024-03-31 \
|
||||||
@@ -260,7 +262,7 @@ with `--alpha-module` (a `.py` path or an importable dotted module). See the
|
|||||||
worked example in `examples/alphas/mean_reversion.py`:
|
worked example in `examples/alphas/mean_reversion.py`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 cli.py alpha compute \
|
uv run python cli.py alpha compute \
|
||||||
--alpha-module examples/alphas/mean_reversion.py \
|
--alpha-module examples/alphas/mean_reversion.py \
|
||||||
--alpha-type mean_reversion --alpha-name mr20 \
|
--alpha-type mean_reversion --alpha-name mr20 \
|
||||||
--param window=20 \
|
--param window=20 \
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
[project]
|
||||||
|
name = "chinese-equity-quant"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "A modular Chinese A-share quant research framework (daily frequency)."
|
||||||
|
requires-python = ">=3.10"
|
||||||
|
dependencies = [
|
||||||
|
"backtrader>=1.9.76.123",
|
||||||
|
"akshare>=1.14.0",
|
||||||
|
"baostock>=0.8.8",
|
||||||
|
"pandas>=2.0.0",
|
||||||
|
"matplotlib>=3.7.0",
|
||||||
|
"click>=8.0.0",
|
||||||
|
"pyarrow>=14.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"pytest>=7.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
package = false
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
backtrader>=1.9.76.123
|
|
||||||
akshare>=1.14.0
|
|
||||||
baostock>=0.8.8
|
|
||||||
pandas>=2.0.0
|
|
||||||
matplotlib>=3.7.0
|
|
||||||
pytest>=7.0.0
|
|
||||||
click>=8.0.0
|
|
||||||
pyarrow>=14.0.0
|
|
||||||
Reference in New Issue
Block a user