Skip to main content

quantlab

Python 3.13+ MIT License Factors: KunQuant Backtest: vectorbt

English | 简体中文

quantlab is a Python backend for quantitative equity research. It takes you from raw market data to a backtested portfolio in one pipeline: load prices into a clean panel, compute factors and labels, train a model that predicts future returns, turn the predictions into target weights, and backtest them. Every stage is driven by a small configuration object, so any run can be saved, rebuilt and repeated exactly.

The research workflow

The quantlab research workflow: data sources, dataset, factors and labels, return model, portfolio and backtest, with a research loop feeding evaluation back into the factor stage

A study in quantlab runs through six stages. Each stage is a root class in its own layer (quantlab/<layer>/base.py), takes the previous stage's output and hands on its own:

Stage What it does Main classes Output
1. Data sources Resumable downloads from WRDS (CRSP, TAQ), Sharadar, FRED, Tiingo and Alpaca, or your own DataFrame DataSourceRegistry, scripts/wrds/, scripts/sharadar/ Raw files
2. Dataset Turns raw bars into a panel; point-in-time universes, delisted stocks kept, resampling and merging MarketDataset, CrspStockDataset, FrameDataset Price panel
3. Factors and labels Compiled factor graphs (Alpha158, Alpha101, Barra-style exposures, neutralization) and forward-return labels Alpha158Stock, BarraStyle, Return Factor panel
4. Return model Tree models and neural networks behind one interface, seed and model ensembles, purged walk-forward CV XGBoostRegressor, RealMLPRegressor, GATsRegressor, SeedEnsemble Checkpoint, run.json
5. Portfolio Predictions to target weights: TopN, or mean-variance with a Ledoit-Wolf or USE4 factor risk model TopNConstructor, MeanVarianceOptimizer Target weights
6. Backtest vectorbt simulation with next-bar fills, fees, delisting settlement and a benchmark USEquityCrossectionSelectStockVectorBt Run directory, report.html

Research is rarely a straight line, so evaluation is built into three of the stages: Factor.analyze() writes an IC and quantile report for every factor, train_cv scores each walk-forward fold and a holdout, and every backtest splits its return into universe, selection and cost parts. What you learn there goes back into stage 3 as the next factor, label or model.

Why quantlab

  • One data contract. Every stage exchanges an xarray.Dataset on the two dimensions timestamp and symbol, a panel, stored on disk as Zarr. Models train on panels directly; there is no DataFrame conversion between stages, and any stage can be swapped without touching the others.
  • Free of look-ahead and survivorship bias by construction. Universes come from historical index membership or full-market listings that include delisted stocks; a signal formed at bar t fills at bar t+1's open; a delisted holding is settled at its last price; an order without a real fill price is rejected and the holding kept.
  • Reproducible runs. Each training and backtest run writes its configuration, data fingerprints and code version next to its results. rebuild() turns a run directory back into the objects that produced it and reruns them to the same equity curve.
  • Fast factors. KunQuant compiles factor formulas to native code and runs them over a whole history or bar by bar, so a factor written for research can later run on live data. Polars is there for quick batch experiments.
  • Bring your own data. A pandas or polars frame becomes a dataset through FrameDataset, and quantlab.api offers factors, labels, a factor report and a backtest as single function calls on frames.
  • Research-grade reports. An alphalens-style factor report, model metrics (IC, RankIC, ICIR) per split and per fold, and an HTML backtest report with in-sample and out-of-sample columns and a benchmark comparison.

quantlab is a research backend. It has no web front end and does not send orders to a broker.

Installation

quantlab needs Python 3.13 or newer, uv and a C++ compiler (KunQuant compiles factor code at run time).

pip install quantlab-py         # or: uv add quantlab-py
pip install 'quantlab-py[all]'  # with every optional extra except mosek

The distribution is named quantlab-py on PyPI (quantlab there is an unrelated project); the package is imported as quantlab.

Some components need an optional extra; importing one without it raises an ImportError that names the extra:

Extra Installs Needed by
optimize cvxpy MeanVarianceOptimizer
tabkit pytabkit RealMLPRegressor, XGBTDRegressor
wandb wandb WandbTracker
mlflow mlflow-skinny MlflowTracker
gbdt lightgbm, catboost LGBMRegressor, CatBoostRegressor, DoubleEnsembleRegressor
massive boto3 Massive flat-file downloads
mosek cvxpy, mosek MeanVarianceOptimizer with max_names (needs a MOSEK licence)
all every extra above except mosek

From source, with every extra and the development tools:

git clone https://github.com/ZhaorongDai/quantlab.git
cd quantlab
uv sync --all-extras

On macOS, xgboost needs Homebrew's OpenMP runtime (brew install libomp).

All model heads, neural-network and tree models alike, use a CUDA GPU when one is available and the CPU otherwise. See the installation guide for GPU and macOS notes.

A pipeline on Yahoo Finance data

examples/yahoo_us_equity.py runs the whole pipeline on free data, with no account and no credentials, in about twenty seconds on a laptop. It downloads ten years of daily bars for the 30 Dow Jones stocks and SPY with yfinance, which is not a quantlab dependency:

uv run --with yfinance python examples/yahoo_us_equity.py

1. Data. yfinance returns a pandas frame. FrameDataset holds it in memory as a panel, renaming the columns to the split- and dividend-adjusted fields the stock factors and the US-equity backtester read. Nothing is written to a Zarr store.

import yfinance as yf
from quantlab.dataset.memory import FrameDataset

wide = yf.download(DOW_30 + ["SPY"], start="2015-06-01", end="2025-01-01", auto_adjust=True)
bars = wide.stack(level="Ticker", future_stack=True).reset_index().dropna(subset=["Close"])
COLUMNS = {"Date": "timestamp", "Ticker": "symbol", "Open": "adjOpen", "High": "adjHigh",
           "Low": "adjLow", "Close": "adjClose", "Volume": "adjVolume"}
stocks, spy = bars[bars.Ticker != "SPY"], bars[bars.Ticker == "SPY"]
prices = FrameDataset(stocks, columns=COLUMNS)

2. Factors, label and model. The 169 Alpha158 factors and the 5-bar open-to-open forward return are computed with KunQuant, and an XGBoost model is trained on 2016 to 2021 and tested on 2022.

factor = Alpha158Stock(FactorConfig(dataset=prices, warmup_bars=60, mode="batch",
                                    data_columns=ADJUSTED, file_path=".../alpha158.zarr"))
label = Return(FactorConfig(dataset=prices, warmup_bars=0, mode="batch",
                            data_columns=("adjOpen",), kwargs={"n_forward_periods": 5},
                            file_path=".../ret_5.zarr"))
model = XGBoostRegressor(ModelConfig(
    factors=[factor], labels=[label], model_save_dir=".../models",
    factor_data_strategy="cal", label_data_strategy="cal",
    hyperparameters={"num_boost_round": 200, "max_depth": 3, "eta": 0.03},
    val_size=0.2, start_date="2016-01-01", end_date="2022-12-31",
    train_start="2016-01-01", train_end="2021-12-31",
    test_start="2022-01-01", test_end="2022-12-31",
))
model.collect()
checkpoint = model.train()

3. Portfolio and backtest. On 2023 and 2024, data the model never saw, every fifth bar the ten stocks with the highest predicted return are held in equal weights, against buy-and-hold SPY.

backtester = USEquityCrossectionSelectStockVectorBt(CrossSectionBacktestConfig(
    price_dataset=prices,
    benchmark_dataset=FrameDataset(spy, columns=COLUMNS),
    model=..., model_mode="load", checkpoint=str(checkpoint),
    start_date="2023-01-01", end_date="2024-12-31", output_dir=".../backtests",
    rebalance_periods=5,
    constructor=TopNConstructor(TopNConfig(direction="long_only", top_n=10)),
))
result = backtester.run()

The script prints:

72,420 rows for 30 stocks, 2,414 for SPY
Price panel: {'timestamp': 2414, 'symbol': 30}
169 factors; label ['ret_5']
2022 test: IC 0.0537, RankIC 0.0365
2023-2024             top-10       SPY
Total Return [%]       35.02     57.11
Sharpe Ratio            1.28      1.84
Max Drawdown [%]        9.54      9.97
Run directory, with the HTML report: output/yahoo_us_equity/backtests/USEquityCrossectionSelectStockVectorBt_<time>
Rebuilt from its run directory, same equity curve: True

and writes the backtest report, shown here in part:

Backtest report of a top-10 Dow 30 strategy against buy-and-hold SPY, 2023 to 2024

The strategy trails SPY over this window; the example is here to show the pipeline, not a strategy to trade. Its universe is today's Dow 30, so every stock in it is one that survived, and Yahoo's prices are not point-in-time. For research, use the CRSP or Sharadar universes below. Yahoo's adjusted prices also change in their last digits from one request to the next, so the script keeps the first download as output/yahoo_us_equity/bars.parquet and reads it on later runs.

More examples

The offline quick start builds a synthetic price panel and runs the same pipeline with no network access, in about half a minute:

uv run python examples/quickstart.py

examples/ has one runnable script per topic (building panels, training models, backtesting, data sources) and, for point-in-time research, wrds_us_equity/ (CRSP via WRDS) and sharadar_us_equity/ (Sharadar). The two figures below come from the WRDS examples.

Factor report

Factor.analyze() pairs every factor with every forward-return label and writes one alphalens-style figure per pair: the information coefficient (IC) over time, its distribution, monthly mean IC, returns by quantile, the long-short curve, turnover and rank autocorrelation at several lags, plus a summary table (with the Newey-West t-statistic and the long-short's return, volatility, Sharpe ratio and drawdown) and tidy CSVs. With two or more factors it also clusters them by their mean rank correlation. This is MIN5 from the Alpha158 set, the 5-day low relative to the close, against the 5-day open-to-open forward return on every common stock in CRSP, about 7,200 symbols including the delisted ones, 2012 to 2024.

Factor report for MIN5 against the 5-day forward return on the full US market

Backtest report

This is sp500_xgb_td.py: a long-only top-50 portfolio on the point-in-time S&P 500, rebalanced every 5 bars from an XGBoost model trained on 2012 to 2019, backtested out of sample on 2020 to 2024 against buy-and-hold SPY. Over this window the strategy trails SPY; the figure is here to show the report, not a result to copy.

Backtest report of a top-50 S&P 500 strategy against buy-and-hold SPY, 2020 to 2024

Credentials

quantlab reads credentials only from environment variables. They are never accepted on the command line and never written to a configuration file or a log.

Variable Used for
WRDS_USERNAME WRDS (CRSP and TAQ); the password is read from ~/.pgpass
SHARADAR_API_KEY Sharadar US equity prices, fundamentals and index membership
TIINGO_API_KEY Tiingo end-of-day US stock prices
APCA_API_KEY_ID, APCA_API_SECRET_KEY Alpaca bars, quotes and trades
WANDB_API_KEY Optional Weights & Biases tracking, when a config names a WandbTracker
MLFLOW_TRACKING_USERNAME, MLFLOW_TRACKING_PASSWORD or MLFLOW_TRACKING_TOKEN Optional MLflow tracking on a server that asks for credentials, when a config names an MlflowTracker (uv sync --extra mlflow)
QUANTLAB_DATA_DIR Optional root directory the library's config factories derive data paths from; the download scripts take --download-dir and --data-dir instead

The download scripts live in scripts/wrds/ and scripts/sharadar/, and each prints its options with --help, for example uv run python scripts/wrds/index.py --help. Tiingo, Alpaca and Binance have library interfaces only. The data sources guide explains where files are written and how to resume an interrupted download.

Documentation

The documentation is organised in three parts. Getting started covers installation and the quick start. The user guide has one page per pipeline stage: data sources, WRDS, datasets, universes, factors, models, portfolio construction and backtesting. The developer guide shows how to add your own data source, dataset, storage backend, factor, model or backtest rule, and explains the machinery that makes long jobs safe to interrupt.

If you already hold your data in pandas or polars DataFrames and want one capability, such as factors, forward returns, a factor report or a backtest, without the project's stores and configurations, start with the frame API guide (quantlab.api).

Every public class and function also has a docstring in the numpydoc format, readable with help() in Python.

Testing

The test suite runs offline and needs no credentials:

uv run pytest

The KunQuant factor tests compile C++ and take a few minutes. tests/test_crsp_rebuild_measurements.py measures a real CRSP store and fails with an explanatory message unless QUANTLAB_DATA_ROOT points at one; a plain uv run pytest never collects it, and it runs only when named on the command line.

Project status

quantlab is under active development, and its interfaces may still change. Event-driven backtesting with NautilusTrader, a service layer and a web front end are planned but not implemented.

Contributing

Bug reports, questions and pull requests are welcome. Please read CONTRIBUTING.md before opening a pull request.

License

quantlab is released under the MIT License.

Metadata

Release files for quantlab-py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for quantlab-py 0.1.0
File Size Uploaded Provenance
quantlab_py-0.1.0.tar.gz 2.6 MB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for quantlab-py 0.1.0
File Interpreter ABI Platform
quantlab_py-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 4.1 MB

Release files / quantlab_py-0.1.0.tar.gz

Download URL quantlab_py-0.1.0.tar.gz
Size 2.6 MB
Tags Source
SHA-256 checksum
How to use checksums
2444652b0ef2af6ddd72bfc082f44c3de0dd2f4408a9e175a7c56c08f9dc6f1c
BLAKE2b-256 checksum
How to use checksums
4d2d10b7a9ce22da73e9a4ae974201a6de466975d056c83136192d85d7c61d62
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Release files / quantlab_py-0.1.0-py3-none-any.whl

Download URL quantlab_py-0.1.0-py3-none-any.whl
Size 1.5 MB
Tags Python 3
SHA-256 checksum
How to use checksums
8888493a7b4fe97c021fadcf4a95e7eb8ea11f23089995fb8ebafb9404dcbe59
BLAKE2b-256 checksum
How to use checksums
e50f2b8f07b0f85d442f906f5d5dc89c07737656d8e0adff504bc554eb146fc3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Security for quantlab-py 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for quantlab_py-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page