Qlib is an open-source, AI-oriented quantitative investment platform. It lets you take a machine-learning idea — from a tree model to a deep network or a reinforcement-learning agent — all the way through the full quant pipeline: data processing, model training, signal generation, portfolio construction, back-testing, and analysis. This guide shows you how to install Qlib, prepare data, run complete research workflows, and build your own strategies.
Note
Qlib is distributed on PyPI under the name
pyqlib, but you import it in Python asqlib. Throughout this guide, "installpyqlib" and "importqlib" refer to the same package.
1. Quick Start
This section gets you from nothing to a back-tested model in a few commands. It assumes a working Python 3.8–3.12 environment.
1.1 Install Qlib
pip install pyqlib
Successfully installed pyqlib-<version>
1.2 Download market data
The example data set is China A-share daily data. Download it into the default data directory:
python -m qlib.cli.data qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn
[INFO] Downloading qlib_data to ~/.qlib/qlib_data/cn_data ...
[INFO] Data is downloaded and extracted.
Important
The official hosted dataset is temporarily disabled due to a stricter data-security policy. If the download above fails or returns empty data, use the community-maintained data set described in Section 3.3.
1.3 Run a complete workflow
Qlib ships ready-to-run model configurations. From the examples/ directory, run a LightGBM workflow with the qrun command:
cd examples
qrun benchmarks/LightGBM/workflow_config_lightgbm_Alpha158.yaml
qrun builds the dataset, trains the model, generates predictions, runs a back-test, and prints a performance summary:
'The following are analysis results of the excess return without cost.'
risk
mean 0.000708
std 0.005626
annualized_return 0.178316
information_ratio 1.996555
max_drawdown -0.081806
'The following are analysis results of the excess return with cost.'
risk
mean 0.000512
std 0.005626
annualized_return 0.128982
information_ratio 1.444287
max_drawdown -0.091078
Tip
Run
qrunfrom insideexamples/(or any directory that does not contain a folder namedqlib). Running from the repository root can cause Python to import the local source tree instead of the installed package.
That's the entire loop. The rest of this guide explains each piece so you can swap in your own models, data, and strategies.
2. Installation
2.1 Supported Python versions
| Python version | Install with pip |
Install from source | Plotting |
|---|---|---|---|
| 3.8 | ✅ | ✅ | ✅ |
| 3.9 | ✅ | ✅ | ✅ |
| 3.10 | ✅ | ✅ | ✅ |
| 3.11 | ✅ | ✅ | ✅ |
| 3.12 | ✅ | ✅ | ✅ |
2.2 Install methods
pip (stable)
pip install pyqlib
Installs the latest stable release. Recommended for most users.
From source (latest dev)
pip install numpy
pip install --upgrade cython
git clone https://github.com/microsoft/qlib.git && cd qlib
pip install . # or: pip install -e .[dev] for development
The main branch is under active development and may contain features not yet released to PyPI.
Docker
docker pull pyqlib/qlib_image_stable:stable
docker run -it --name qlib_container -v <local_dir>:/app pyqlib/qlib_image_stable:stable
A self-contained environment with Qlib and its build dependencies preinstalled.
Tip
Conda is recommended for managing your environment. Building Qlib outside of Conda sometimes fails because of missing C/C++ header files needed to compile Qlib's Cython extensions.
Warning
Apple Silicon (M1/M2): building the LightGBM wheel may fail due to a missing OpenMP dependency. Install it first with
brew install libomp, then re-runpip install ..
2.3 Optional dependency groups
Some features require extra packages installed via "extras":
# Graphical report analysis (notebooks, plotting)
python -m pip install .[analysis]
Note
Individual benchmark models under
examples/benchmarks/declare their ownrequirements.txt(for example, specifictorchortensorflowversions). Install those before running a particular model. The TFT model, for instance, requirestensorflow-gpu==1.15.0and only supports Python 3.6–3.7.
3. Data Preparation
Qlib stores market data in a compact binary format optimized for fast scientific computation. You can download a ready-made data set or build your own from raw sources.
3.1 Download ready-made data
As a module
# Daily (1d) China A-share data
python -m qlib.cli.data qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn
# 1-minute data
python -m qlib.cli.data qlib_data --target_dir ~/.qlib/qlib_data/cn_data_1min --region cn --interval 1min
From the source script
# Daily (1d) China A-share data
python scripts/get_data.py qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn
# 1-minute data
python scripts/get_data.py qlib_data --target_dir ~/.qlib/qlib_data/cn_data_1min --region cn --interval 1min
Common parameters for the qlib_data downloader:
| Parameter | Meaning | Default |
|---|---|---|
--target_dir |
Where to save the data | ~/.qlib/qlib_data/cn_data |
--region |
Market region: cn, us, in |
cn |
--interval |
Bar interval: 1d or 1min |
1d |
--version |
Data set version (v1/v2) |
v1 |
--delete_old |
Remove existing data in target_dir first |
True |
--exists_skip |
Skip download if data already exists | False |
Note
The published
examples/benchmarksresults were produced with thev1data set. If you want to reproduce benchmark numbers exactly, use--version v1.
3.2 Download a smaller sample
For a quick test you can pull a reduced "simple" data set:
python scripts/get_data.py qlib_data --name qlib_data_simple --target_dir ~/.qlib/qlib_data/cn_data --region cn
3.3 Community data source (recommended)
While the official dataset is paused, the community provides a compatible build:
wget https://github.com/chenditc/investment_data/releases/latest/download/qlib_bin.tar.gz
mkdir -p ~/.qlib/qlib_data/cn_data
tar -zxvf qlib_bin.tar.gz -C ~/.qlib/qlib_data/cn_data --strip-components=1
rm -f qlib_bin.tar.gz
qlib_bin.tar.gz 100%[==============================>] ... MB/s
3.4 Check data health
Before training, verify the data is complete and free of obvious anomalies:
python scripts/check_data_health.py check_data --qlib_dir ~/.qlib/qlib_data/cn_data
You can tune the thresholds the health check uses:
python scripts/check_data_health.py check_data \
--qlib_dir ~/.qlib/qlib_data/cn_data \
--missing_data_num 30055 \
--large_step_threshold_volume 94485 \
--large_step_threshold_price 20
3.5 Keep daily data up to date
Once you have a base data set, you can incrementally append new trading days from Yahoo Finance:
python scripts/data_collector/yahoo/collector.py update_data_to_bin \
--qlib_data_1d_dir ~/.qlib/qlib_data/cn_data \
--trading_date 2021-05-25 \
--end_date 2021-06-25
Caution
You cannot incrementally update the offline data set provided by Qlib — some fields were removed to reduce its size. To maintain a continuously updated data set, download raw data from scratch with the Yahoo collector and then update it incrementally. See Section 8 for the full collect → normalize → dump pipeline.
4. Running Models with qrun
qrun is the one-command entry point for the entire automatic quant research workflow. It reads a single YAML file that declares your data, model, training segments, strategy, and analysis records, then executes them end to end.
4.1 Anatomy of a workflow config
Here is the complete LightGBM/Alpha158 configuration, annotated. Every Qlib workflow follows this same shape.
qlib_init: # passed to qlib.init()
provider_uri: "~/.qlib/qlib_data/cn_data"
region: cn
market: &market csi300 # the stock universe
benchmark: &benchmark SH000300 # index used for excess-return analysis
data_handler_config: &data_handler_config
start_time: 2008-01-01
end_time: 2020-08-01
fit_start_time: 2008-01-01
fit_end_time: 2014-12-31
instruments: *market
port_analysis_config: &port_analysis_config
strategy:
class: TopkDropoutStrategy
module_path: qlib.contrib.strategy
kwargs:
signal: <PRED>
topk: 50 # hold the top 50 ranked stocks
n_drop: 5 # replace 5 each rebalance
backtest:
start_time: 2017-01-01
end_time: 2020-08-01
account: 100000000 # starting capital
benchmark: *benchmark
exchange_kwargs:
limit_threshold: 0.095 # price-limit filter (CN market)
deal_price: close # execution price
open_cost: 0.0005 # buy commission
close_cost: 0.0015 # sell commission
min_cost: 5 # minimum commission per trade
task:
model:
class: LGBModel
module_path: qlib.contrib.model.gbdt
kwargs:
loss: mse
learning_rate: 0.2
max_depth: 8
num_leaves: 210
num_threads: 20
colsample_bytree: 0.8879
subsample: 0.8789
lambda_l1: 205.6999
lambda_l2: 580.9768
dataset:
class: DatasetH
module_path: qlib.data.dataset
kwargs:
handler:
class: Alpha158
module_path: qlib.contrib.data.handler
kwargs: *data_handler_config
segments:
train: [2008-01-01, 2014-12-31]
valid: [2015-01-01, 2016-12-31]
test: [2017-01-01, 2020-08-01]
record:
- class: SignalRecord # save model predictions
module_path: qlib.workflow.record_temp
kwargs:
model: <MODEL>
dataset: <DATASET>
- class: SigAnaRecord # signal quality (IC, rank IC)
module_path: qlib.workflow.record_temp
kwargs:
ana_long_short: False
ann_scaler: 252
- class: PortAnaRecord # portfolio back-test analysis
module_path: qlib.workflow.record_temp
kwargs:
config: *port_analysis_config
The top-level sections are:
| Section | Purpose |
|---|---|
qlib_init |
Arguments forwarded to qlib.init() (data path, region, caches). |
market / benchmark |
The stock universe and the comparison index. |
data_handler_config |
Time ranges and the instrument universe for feature generation. |
port_analysis_config |
The trading strategy and back-test settings. |
task.model |
Which model to train, by class + module path + hyperparameters. |
task.dataset |
The dataset and feature handler, with train/valid/test splits. |
task.record |
What artifacts to produce (signals, signal analysis, portfolio analysis). |
Note
Qlib resolves every
class+module_path+kwargsblock into an object at runtime. The placeholders<MODEL>,<DATASET>, and<PRED>are filled in automatically —<MODEL>and<DATASET>with the trained model and dataset,<PRED>with the model's prediction. You don't set these yourself.
4.2 Run, debug, and reuse configs
Run a workflow:
qrun benchmarks/LightGBM/workflow_config_lightgbm_Alpha158.yaml
Run under the Python debugger:
python -m pdb qlib/cli/run.py examples/benchmarks/LightGBM/workflow_config_lightgbm_Alpha158.yaml
Name the experiment (otherwise it defaults to workflow):
qrun config.yaml my_experiment_name
Reuse a base config. Point BASE_CONFIG_PATH at another file and override only the fields you change:
qlib_init:
provider_uri: "~/.qlib/qlib_data/cn_data"
region: cn
BASE_CONFIG_PATH: "workflow_config_lightgbm_Alpha158_csi500.yaml"
market: csi300
Tip
Config files are rendered as Jinja2 templates before parsing. Any
{{ VAR }}placeholder is filled from a matching environment variable, so you can parameterize a single config across runs without editing it.
4.3 Run one or many benchmark models
Qlib bundles a large "model zoo" of published architectures, each with a ready config. Use run_all_model.py to run them:
# Run a single named model
python run_all_model.py run --models=lightgbm
# Run every model for 10 iterations each
python run_all_model.py run 10
Note
run_all_model.pycreates an isolated virtual environment per model (because each model pins different dependency versions) and removes it afterward, keeping only the results. It currently supports Linux only, and does not yet run the same model in parallel.
The available models include gradient-boosted trees and a broad set of neural architectures:
| Category | Models |
|---|---|
| Gradient boosting | XGBoost, LightGBM, CatBoost, DoubleEnsemble |
| Linear / MLP | Linear, MLP |
| Recurrent | LSTM, GRU, ALSTM, SFM, TCN, KRNN, Sandwich |
| Attention / Transformer | Transformer, Localformer, TFT, TRA, TabNet |
| Graph-based | GATs, HIST, IGMTF |
| Other | ADARNN, ADD, TCTS |
5. Building Workflows in Code
The automatic qrun workflow won't fit every research need. Qlib is fully modular, so you can assemble the same pipeline step by step in Python. This is the recommended path when you want to inspect intermediate data, customize the loop, or integrate Qlib into a larger program.
import qlib
from qlib.constant import REG_CN
from qlib.utils import init_instance_by_config, flatten_dict
from qlib.workflow import R
from qlib.workflow.record_temp import SignalRecord, PortAnaRecord, SigAnaRecord
from qlib.tests.config import CSI300_BENCH, CSI300_GBDT_TASK
# 1. Initialize Qlib
provider_uri = "~/.qlib/qlib_data/cn_data"
qlib.init(provider_uri=provider_uri, region=REG_CN)
# 2. Build the model and dataset from config dicts
model = init_instance_by_config(CSI300_GBDT_TASK["model"])
dataset = init_instance_by_config(CSI300_GBDT_TASK["dataset"])
# 3. (Optional) inspect the prepared data
example_df = dataset.prepare("train")
print(example_df.head())
# 4. Train, predict, and analyze inside an experiment
with R.start(experiment_name="workflow"):
R.log_params(**flatten_dict(CSI300_GBDT_TASK))
model.fit(dataset)
R.save_objects(**{"params.pkl": model})
recorder = R.get_recorder()
# Save predictions
sr = SignalRecord(model, dataset, recorder)
sr.generate()
# Analyze signal quality (IC, rank IC)
sar = SigAnaRecord(recorder)
sar.generate()
# Portfolio back-test
par = PortAnaRecord(recorder, port_analysis_config, "day")
par.generate()
feature ...
KMID KLEN KMID2 ... LABEL0
datetime instrument ...
2008-01-02 SH600000 0.013... -0.005... 0.002... ... 0.011...
Tip
The
with R.start(...)block is the heart of every code-driven workflow. Everything you log or save inside it is grouped under one recorder, which you can reload later by id. See Section 6.
5.1 The Model interface
Every Qlib model implements two methods:
| Method | Signature | Purpose |
|---|---|---|
fit |
model.fit(dataset) |
Train on the dataset's train/valid segments. |
predict |
model.predict(dataset, segment="test") |
Produce predictions for a segment (default test). |
Models that subclass ModelFT also support finetune(dataset) for continued training from a saved checkpoint.
6. Tracking Experiments with the Recorder
Qlib's experiment manager (R) wraps MLflow with a more intuitive, object-based API. An experiment groups related runs; each run is a recorder that stores parameters, metrics, and artifacts (models, predictions, reports).
6.1 Common recorder operations
from qlib.workflow import R
# Start an experiment and an auto-named recorder
with R.start(experiment_name="my_exp", recorder_name="run_1"):
R.log_params(learning_rate=0.01, max_depth=8) # log hyperparameters
R.log_metrics(train_loss=0.33, step=1) # log metrics over time
R.save_objects(**{"pred.pkl": predictions}) # save Python objects
rid = R.get_recorder().id # remember the run id
# Later: reload an artifact from a finished run
recorder = R.get_recorder(recorder_id=rid, experiment_name="my_exp")
pred = recorder.load_object("pred.pkl")
6.2 Recorder API reference
| Method | What it does |
|---|---|
R.start(experiment_name=..., recorder_name=..., resume=False) |
Context manager that starts (or resumes) an experiment + recorder. |
R.log_params(**kwargs) |
Log hyperparameters/config values. |
R.log_metrics(step=None, **kwargs) |
Log numeric metrics, optionally over training steps. |
R.save_objects(local_path=None, artifact_path=None, **kwargs) |
Persist Python objects or files as artifacts. |
R.load_object(name) |
Load a saved artifact from the active recorder. |
R.set_tags(**kwargs) |
Attach searchable tags to a run. |
R.get_recorder(recorder_id=..., experiment_name=...) |
Retrieve a specific recorder. |
R.list_experiments() |
Dictionary of all experiments. |
R.list_recorders(experiment_name=...) |
Dictionary of all recorders in an experiment. |
R.search_records(experiment_ids, order_by=[...]) |
Query runs as a pandas DataFrame. |
R.delete_exp(...) / R.delete_recorder(...) |
Remove experiments or runs. |
Important
Do not call
qlib.init()again while a recorder is active — Qlib raises aRecorderInitializationErrorto prevent silently moving your experiment's storage location.
Note
To resume a finished run, pass the exact same
experiment_nameandrecorder_name(orrecorder_id) plusresume=True. By default, experiment artifacts are stored under./mlrunsin your working directory.
6.3 Record templates
The record section of a workflow (and the classes you call in code) are record templates that compute and save standard research outputs:
| Record template | Produces |
|---|---|
SignalRecord |
The raw model predictions (the trading "signal"). |
SigAnaRecord |
Signal-quality metrics: Information Coefficient (IC), rank IC, long-short returns. |
PortAnaRecord |
A full portfolio back-test: returns, risk, and the analysis tables printed by qrun. |
7. Querying Data with the D Interface
D is Qlib's data-access object. After qlib.init(), use it to load calendars, instrument lists, and computed features.
import qlib
from qlib.data import D
from qlib.constant import REG_CN
qlib.init(provider_uri="~/.qlib/qlib_data/cn_data", region=REG_CN)
# Trading calendar
print(D.calendar(start_time="2010-01-01", end_time="2017-12-31", freq="day")[:2])
# Parse a market name into an instrument universe, then list members
instruments = D.instruments("csi500")
print(D.list_instruments(instruments=instruments,
start_time="2010-01-01", end_time="2017-12-31",
as_list=True)[:6])
# Load features (raw fields and on-the-fly expressions)
fields = ["$close", "$volume", "Ref($close, 1)", "Mean($close, 3)", "$high-$low"]
df = D.features(["SH600000"], fields,
start_time="2010-01-01", end_time="2017-12-31", freq="day")
print(df.head())
7.1 The D methods
| Method | Signature | Returns |
|---|---|---|
D.calendar |
D.calendar(start_time, end_time, freq="day", future=False) |
List of trading timestamps. |
D.instruments |
D.instruments(market="all", filter_pipe=None) |
A stock-pool configuration. |
D.list_instruments |
D.list_instruments(instruments, start_time, end_time, freq="day", as_list=False) |
The concrete instrument list/dict. |
D.features |
D.features(instruments, fields, start_time, end_time, freq="day") |
A pandas DataFrame of computed features. |
7.2 The expression language
Feature fields are written as expressions. A field prefixed with $ is a raw column; operators compute derived signals on the fly:
| Expression | Meaning |
|---|---|
$close, $volume, $high, $low |
Raw daily fields. |
Ref($close, 1) |
Yesterday's close (lag by 1 bar). |
Mean($close, 3) |
3-bar moving average of close. |
$high - $low |
Intraday range (arithmetic on fields). |
Tip
The expression engine is backed by caches. With
ExpressionCacheandDatasetCacheenabled, repeated feature queries are dramatically faster — Qlib's own benchmarks show feature construction dropping from ~184s (HDF5) to ~7s with both caches on a single CPU.
7.3 Pre-built feature sets: Alpha158 and Alpha360
You rarely write all your features by hand. Qlib ships two curated feature handlers used throughout the benchmarks:
| Dataset | US Market | China Market | Description |
|---|---|---|---|
Alpha158 |
✅ | ✅ | 158 engineered factors (price/volume patterns). |
Alpha360 |
✅ | ✅ | 360 raw normalized price/volume features over a lookback window. |
Both live in qlib.contrib.data.handler and are plugged into a DatasetH via the handler block shown in Section 4.1.
8. Building Your Own Data Set
If the ready-made data doesn't meet your needs, Qlib provides a three-stage pipeline — collect → normalize → dump — to turn raw CSVs into the Qlib binary format. Each market has a collector script under scripts/data_collector/.
8.1 Collect, normalize, dump (Yahoo example)
# 1. Download raw CSVs (one file per symbol)
python scripts/data_collector/yahoo/collector.py download_data \
--source_dir ~/.qlib/stock_data/source/cn_data \
--start 2020-01-01 --end 2020-12-31 --delay 1 --interval 1d --region CN
# 2. Normalize (adjust prices; scale first valid close to 1)
python scripts/data_collector/yahoo/collector.py normalize_data \
--source_dir ~/.qlib/stock_data/source/cn_data \
--normalize_dir ~/.qlib/stock_data/source/cn_1d_nor \
--region CN --interval 1d
# 3. Dump to Qlib binary format
python scripts/dump_bin.py dump_all \
--data_path ~/.qlib/stock_data/source/cn_1d_nor \
--qlib_dir ~/.qlib/qlib_data/cn_data \
--freq day --exclude_fields date,symbol --file_suffix .csv
Warning
Yahoo Finance blocks access from within China. Switch your network if you need the Yahoo crawler. The collected data may also contain anomalies even after price adjustment — validate it with the health check from Section 3.4.
8.2 Build an index/instrument universe
To track which stocks belong to an index over time (additions and removals), use the index collectors:
# China indices: CSI300, CSI100, CSI500
python scripts/data_collector/cn_index/collector.py \
--index_name CSI300 --qlib_dir ~/.qlib/qlib_data/cn_data --method parse_instruments
# US indices: SP500, NASDAQ100, DJIA, SP400
python scripts/data_collector/us_index/collector.py \
--index_name SP500 --qlib_dir ~/.qlib/qlib_data/us_data --method parse_instruments
8.3 Other data sources
Qlib includes collectors beyond daily equities:
| Collector | Data | Notes |
|---|---|---|
yahoo |
Global equities (CN/US/IN/BR), 1d & 1min | Most common source. |
baostock_5min |
China 5-minute bars | High-frequency CN data. |
crypto |
Coingecko crypto prices | Data-retrieval only — no back-test (no OHLC). |
fund |
China mutual-fund NAVs | From 天天基金网 (East Money). |
pit |
Point-in-Time quarterly fundamentals | Use dump_pit.py to dump. |
crowd_source |
Cross-validated community data | Mitigates survivorship bias. |
9. Advanced Workflows
9.1 Adapting to market dynamics (rolling & DDG-DA)
Financial markets are non-stationary, so a model trained on old data decays over time. Qlib provides two adaptation strategies:
- Rolling Retraining (RR): periodically retrain on the most recent data.
- DDG-DA: a meta-learning method that forecasts the future data distribution and adapts to it.
Run the rolling baseline:
cd examples/benchmarks_dynamic/baseline
python rolling_benchmark.py run
# Use a different forecasting model
python rolling_benchmark.py --conf_path=workflow_config_lightgbm_Alpha158.yaml run
The rolling entry point is also exposed as a module:
python -m qlib.contrib.rolling base --conf_path <path/to/workflow.yaml> run
9.2 Reinforcement learning for order execution
Qlib includes an RL framework for modeling continuous trading decisions — most notably order execution, where the goal is to fill an order while minimizing market impact. Example configurations under examples/rl_order_execution/ cover TWAP, PPO, and OPDS methods.
Note
The RL framework integrates with the back-test executor and supports nested execution — for example, optimizing an intraday order-execution agent inside a daily portfolio strategy. See Section 9.3.
9.3 Nested decision execution
Real trading involves decisions at multiple time scales: a daily portfolio strategy decides what to hold; an intraday executor decides how to trade it. Qlib's NestedExecutor lets you stack strategies and executors at different granularities and optimize them together. The example lives at examples/nested_decision_execution/workflow.py.
9.4 Hyperparameter tuning
The bundled Optuna example tunes LightGBM hyperparameters with a live dashboard:
# Terminal 1: create the study and launch the dashboard
optuna create-study --study LGBM_158 --storage sqlite:///db.sqlite3
optuna-dashboard --port 5000 --host 0.0.0.0 sqlite:///db.sqlite3
# Terminal 2: run the search
python hyperparameter_158.py
10. Analyzing Results
After a workflow finishes, run the graphical report notebook to visualize signal quality and portfolio performance:
python -m pip install .[analysis]
jupyter notebook examples/workflow_by_code.ipynb
The analysis covers two areas:
Forecasting-signal analysis (how good are the predictions?):
- Cumulative return by prediction-ranked groups
- Return distribution (long/short)
- Information Coefficient (IC) and Monthly IC
- Auto-correlation of the signal
Portfolio analysis (how does the strategy perform?):
- Back-test cumulative return vs. benchmark
- Risk metrics: annualized return, information ratio, max drawdown
The same numbers are printed in the qrun summary you saw in Section 1.3: mean, std, annualized_return, information_ratio, and max_drawdown, reported both with and without trading cost.
Tip
Always read the with-cost table. The example LightGBM strategy's annualized return drops from
0.178to0.129once commissions are applied — costs matter.
11. How Qlib Works (Concepts)
You can use Qlib productively from the configs above, but understanding the component layers helps you customize. Qlib is built as a stack of loosely-coupled modules; each can be used stand-alone.
Data Layer Raw fields + expression engine (D, ExpressionCache)
│
Dataset / Handler Feature sets (Alpha158/Alpha360) split into train/valid/test
│
Model Layer fit() / predict() — trees, neural nets, RL agents
│
Workflow Layer R recorder + record templates (Signal/SigAna/PortAna)
│
Strategy Layer Turn signals into trade decisions (TopkDropoutStrategy)
│
Backtest / Executor Simulate trading, optionally nested across time scales
│
Analysis IC, returns, risk, drawdown
Key concepts:
- Signal: a model's per-stock score for a future period. Higher score = more attractive.
- Strategy: a rule that converts the signal into trades.
TopkDropoutStrategyholds the top-topkstocks and swaps outn_dropof them each rebalance. - Recorder: the unit that stores one run's parameters, metrics, and artifacts.
- Handler: the component that builds features and labels for a time range.
- Offline vs. online mode: by default Qlib runs offline (data lives on your machine). In online mode, a shared data server (Qlib-Server) serves data and caches to multiple clients for higher cache-hit rates and lower disk use.
12. Troubleshooting
Error: TypeError when early_stopping_rounds=None (LightGBM 4.0+)
Cause: LightGBM 4.0 changed the early-stopping API; Qlib model code that passes early_stopping_rounds=None triggers a TypeError.
Solution: Pin a LightGBM 3.x version (for example lightgbm==3.1.0 as used by several benchmark configs), or upgrade to a Qlib build that handles LightGBM 4.0+.
Prevention: Match the requirements.txt shipped with the specific benchmark model you are running.
Error: The benchmark SH000300 does not exist. Please provide the right benchmark
Cause: The benchmark index symbol referenced in your config isn't present in your downloaded data set.
Solution: Confirm your data region matches the benchmark (SH000300 is the CSI300 index in CN data), and that your data download completed. Re-download with the correct --region.
Prevention: Keep market, benchmark, and qlib_init.region consistent in your config.
Error: unhashable type: 'list' in InternalData.setup() (DDG-DA)
Cause: A known chain of compatibility bugs in the DDG-DA dynamic workflow involving newer pandas indexing and LightGBM 4.0+.
Solution: Use the pinned dependency versions for the DDG-DA example, and a pandas version compatible with the example's requirements.txt.
Prevention: Run dynamic-benchmark examples in their own virtual environment with the example's exact requirements.
Issue: Data loading is very slow
Cause: Feature computation without caches, or redundant filter execution across field groups (a known inefficiency in SeriesDFilter).
Solution: Enable ExpressionCache/DatasetCache (server mode), and reduce the number of distinct fields_group filters where possible.
Prevention: Use the cache configuration and load only the fields you need.
Error: Invalid provider uri: <path> ... This path does not exist.
Cause: qlib.init() was given a provider_uri that doesn't exist on disk.
Solution: Download data to that path first (Section 3), or point provider_uri at your actual data directory.
Prevention: Verify the directory exists before calling qlib.init().
Issue: qrun imports the wrong Qlib
Cause: Running qrun from a directory that contains a folder named qlib (such as the cloned repo root) makes Python import the source tree instead of the installed package.
Solution: Run from examples/ or any other directory.
Prevention: Keep your working directory separate from the source checkout.
Issue: pandas group_key break change
Cause: From pandas 1.5 to 2.0 the default of groupby(group_keys=...) changed, which can break some scripts.
Solution: Qlib sets group_key=False internally, but a few scripts (e.g. gen_training_orders.py, the TRA dataset, tft.py) may still need attention with newer pandas.
Prevention: Use a pandas version compatible with your target model's requirements.
Issue: LightGBM build fails on Apple Silicon
Cause: Missing OpenMP runtime when compiling the LightGBM wheel.
Solution: brew install libomp, then re-run pip install ..
Prevention: Install libomp before building on macOS M1/M2.
13. FAQ
Q: What's the difference between qrun and workflow_by_code?
They do the same thing. qrun config.yaml runs a workflow declared entirely in YAML; workflow_by_code assembles the identical pipeline in Python so you can customize each step. Start with qrun, switch to code when you need control.
Q: The official data download fails — what do I do?
The official hosted dataset is temporarily disabled. Use the community data set (chenditc/investment_data) described in Section 3.3.
Q: How do I change the stock universe?
Set market (e.g. csi300, csi500, all) in your config, and make sure benchmark and your data region match.
Q: Where are my trained models and predictions stored?
Under the experiment-tracking URI, which defaults to ./mlruns in your working directory. Reload artifacts with R.get_recorder(...).load_object(name).
Q: Can I use my own model?
Yes. Subclass qlib.model.base.Model (implement fit and predict) and reference it in the task.model block with its class and module_path.
Q: Which data set version reproduces the published benchmark numbers?
The v1 Yahoo data set. Pass --version v1 to the downloader.
Q: Does Qlib support intraday / high-frequency trading?
Yes. Download 1min data, and use the high-frequency examples (examples/highfreq/) and nested execution. Note that some operations require both 1d and 1min data.
Q: Can I back-test crypto? You can retrieve crypto data, but the crypto collector provides retrieval only — back-testing isn't supported there because it lacks full OHLC data.
Q: How do I run many models to compare them?
Use python run_all_model.py run <iterations> (Linux only). It isolates each model's dependencies in its own virtual environment.
Q: What does TopkDropoutStrategy actually do?
Each rebalance it holds the topk highest-ranked stocks by the model's signal and replaces the n_drop lowest-ranked currently-held positions — a simple, effective long-only ranking strategy.
Q: How do I adapt a model to changing markets?
Use rolling retraining (examples/benchmarks_dynamic/baseline) or the DDG-DA meta-learning approach (examples/benchmarks_dynamic/DDG-DA).
Q: Can I share data across machines? Yes — deploy Qlib in online mode with Qlib-Server, which serves data and caches to multiple clients.
Q: My run prints warnings about Redis / cache not used. Is that a problem? No. If Redis isn't reachable, Qlib disables the disk caches that depend on it and continues. Performance is lower but results are unaffected.
14. Command Reference
| Command | Purpose |
|---|---|
pip install pyqlib |
Install Qlib. |
python -m qlib.cli.data qlib_data --target_dir <dir> --region cn |
Download data (as a module). |
python scripts/get_data.py qlib_data --target_dir <dir> --region cn |
Download data (from source). |
python scripts/check_data_health.py check_data --qlib_dir <dir> |
Validate data integrity. |
qrun <config.yaml> |
Run a full workflow from a config. |
qrun <config.yaml> <exp_name> |
Run a workflow under a named experiment. |
python -m pdb qlib/cli/run.py <config.yaml> |
Debug a workflow. |
python run_all_model.py run --models=<name> |
Run a single benchmark model. |
python run_all_model.py run <n> |
Run all benchmark models for n iterations. |
python -m qlib.contrib.rolling base --conf_path <yaml> run |
Run a rolling-retrain workflow. |
python scripts/dump_bin.py dump_all --data_path <dir> --qlib_dir <dir> --freq day |
Convert CSVs to Qlib binary format. |
python scripts/data_collector/<source>/collector.py download_data ... |
Collect raw data from a source. |
Key Python entry points
| Object | Import | Purpose |
|---|---|---|
qlib.init |
import qlib |
Initialize Qlib with a data path and region. |
D |
from qlib.data import D |
Query calendars, instruments, and features. |
R |
from qlib.workflow import R |
Manage experiments and recorders. |
init_instance_by_config |
from qlib.utils import init_instance_by_config |
Build a model/dataset/strategy from a config dict. |
SignalRecord, SigAnaRecord, PortAnaRecord |
from qlib.workflow.record_temp import ... |
Generate predictions and analysis. |