This guide is for the engineers, architects, and researchers who deploy Qlib, configure it for production research, extend its components, and reason about its internals. It assumes familiarity with the day-to-day usage covered in the User Guide and focuses on architecture, the full configuration surface, security posture, operations, and the code-level structure needed to extend or replicate the platform.
Note
Package identity: PyPI distribution
pyqlib; import nameqlib. Source is asrc-less flat layout rooted atqlib/. The platform is pure Python with two compiled Cython extensions (qlib.data._libs.rolling,qlib.data._libs.expanding) built fromsetup.py.
1. Executive Summary
Qlib is an AI-oriented quantitative investment platform that covers the full research chain: data processing, feature engineering, model training, signal generation, portfolio construction, back-testing, and analysis. It is architected as a stack of loosely-coupled components, each usable stand-alone, wired together either declaratively (a single workflow YAML executed by qrun) or imperatively (Python "workflow by code").
| Attribute | Value |
|---|---|
| Language | Python 3.8–3.12 (+ Cython extensions) |
| Distribution | pyqlib on PyPI; Docker image pyqlib/qlib_image_stable:stable |
| Experiment backend | MLflow (wrapped), default URI file:./mlruns |
| Optional services | Redis (caches), MongoDB (task management) |
| Data format | Custom compact binary, optimized for array assembly |
| Deployment modes | Offline (local data) / Online (shared data server, Qlib-Server) |
| License | MIT (Microsoft Open Source) |
Operational stance: Qlib is a library and research framework, not a long-running service. There is no API server, no authentication layer, and no network listener in the core. Its "production" footprint is the data directory, the MLflow tracking store, and optionally Redis/MongoDB. Security and operations therefore center on data integrity, dependency management, and reproducibility rather than on hardening a service surface.
2. Architecture
2.1 Component layers
┌─────────────────────────────────────────────────────────────┐
│ qlib.init() → QlibConfig (global C) → register providers/ops │
└─────────────────────────────────────────────────────────────┘
│
▼
┌───────────────┐ Data Layer (qlib/data)
│ Providers │ LocalProvider → Calendar/Instrument/Feature/PIT/Expression/Dataset providers
│ Expression │ $field raw access + operator graph (Ref, Mean, ...) compiled via _libs
│ Caches │ ExpressionCache, DatasetCache (Disk* variants depend on Redis)
└───────────────┘
│
▼
┌───────────────┐ Dataset Layer (qlib/data/dataset)
│ DataHandler │ Alpha158 / Alpha360 (qlib/contrib/data/handler)
│ DatasetH │ train/valid/test segmentation, DataHandlerLP processing
└───────────────┘
│
▼
┌───────────────┐ Model Layer (qlib/model, qlib/contrib/model)
│ Model.fit │ LGBModel + ~20 pytorch/tensorflow SOTA models
│ Model.predict │ Trainer / TrainerR / TrainerRM (MongoDB TaskManager)
└───────────────┘
│
▼
┌───────────────┐ Workflow Layer (qlib/workflow)
│ R (recorder) │ QlibRecorder → MLflowExpManager → MLflowExperiment → MLflowRecorder
│ RecordTemp │ SignalRecord → SigAnaRecord → PortAnaRecord
└───────────────┘
│
▼
┌───────────────┐ Strategy + Execution (qlib/strategy, qlib/backtest)
│ BaseStrategy │ TopkDropoutStrategy, RL strategies
│ Executor │ SimulatorExecutor, NestedExecutor, Exchange, Position, Account
└───────────────┘
│
▼
┌───────────────┐ Analysis (qlib/contrib/eva, contrib/evaluate, contrib/report)
│ IC / risk │ calc_ic, risk_analysis, indicator_analysis
└───────────────┘
Every box is independently importable. The glue is config-driven instantiation: throughout Qlib, components are described by {class, module_path, kwargs} dicts and built at runtime by init_instance_by_config (qlib/utils). This is why a workflow YAML can swap any model, dataset, or strategy without code changes.
2.2 Initialization and the global config object
qlib.init() (qlib/__init__.py) is the single entry point that activates the framework:
- Resets the global config
C(aQlibConfig) from a mode template (clientorserver). - Applies region defaults (
cn/us/tw) and any keyword overrides. - Resolves and (optionally) mounts the data path — including NFS auto-mount logic for shared deployments (
_mount_nfs_uri). - Calls
C.register(), which registers all expression operators (register_all_ops), data wrappers (register_all_wrappers), and constructs theQlibRecorder(R) backed by the configured experiment manager.
import qlib
from qlib.constant import REG_CN
qlib.init(provider_uri="~/.qlib/qlib_data/cn_data", region=REG_CN)
Alternative initializers:
| Function | Use case |
|---|---|
qlib.init(default_conf="client", **kwargs) |
Standard explicit init. |
qlib.init_from_yaml_conf(conf_path, **kwargs) |
Init from a YAML config file. |
qlib.auto_init(**kwargs) |
Walk up the directory tree to find a project config.yaml and init from it; supports conf_type: origin (standalone) and conf_type: ref (reference a shared config + project overrides). Used by python -m qlib.contrib.rolling. |
Note
The config object
Cis a singleton (qlib/config.py,C = QlibConfig(_default_config)).qlib.init()is not safe to call twice while a recorder is active — theRecorderWrapperraisesRecorderInitializationErrorto prevent silently relocating experiment storage.
2.3 Data path management
QlibConfig.DataPathManager resolves provider_uri (and mount_path) into concrete data URIs, distinguishing local paths from NFS paths by regex (get_uri_type). provider_uri may be a string or a per-frequency dict:
qlib_init:
provider_uri:
day: "~/.qlib/qlib_data/cn_data"
1min: "~/.qlib/qlib_data/cn_data_1min"
For NFS deployments, Qlib can auto-mount (auto_mount: True) on Windows (mount -o anon) or Linux/Unix (mount.nfs, requires nfs-common and sudo). This is the mechanism behind shared, multi-client data servers.
3. System Requirements
| Requirement | Detail |
|---|---|
| Python | 3.8–3.12 (model-specific exceptions, e.g. TFT needs 3.6–3.7) |
| Build toolchain | C/C++ compiler + Cython for the _libs extensions; cmake listed in docs requirements |
| Core libraries | numpy, scipy, pandas, scikit-learn |
| Experiment store | mlflow (always), filelock for concurrency |
| Config | ruamel.yaml, pydantic-settings, jinja2 |
| Optional: Redis | For DiskExpressionCache / DiskDatasetCache (server mode) |
| Optional: MongoDB | For TrainerRM / TaskManager parallel task orchestration |
| GPU | Required by some neural models (TFT requires CUDA 10.0) |
Important
Each benchmark model under
examples/benchmarks/pins its own dependency versions in a localrequirements.txt(often specifictorch/tensorflow/lightgbmversions). Treat these as authoritative per-model environments —run_all_model.pyenforces this by building an isolated virtualenv per model.
4. Configuration Mastery
There are three distinct configuration surfaces in Qlib. Conflating them is the most common operational mistake.
- Runtime config — the
qlib.init()keyword arguments, layered over the_default_configdict inqlib/config.py. - Environment settings — the
QSettings(pydantic-settings) object, prefixQLIB_. - Workflow config — the per-experiment YAML consumed by
qrun(model/dataset/strategy/backtest).
4.1 Runtime config (_default_config)
These are the keys you can pass to qlib.init() or set in qlib_init:. Reproduced from qlib/config.py:
| Key | Default | Purpose |
|---|---|---|
calendar_provider |
LocalCalendarProvider |
Trading-calendar backend. |
instrument_provider |
LocalInstrumentProvider |
Instrument-universe backend. |
feature_provider |
LocalFeatureProvider |
Raw-feature backend. |
pit_provider |
LocalPITProvider |
Point-in-time fundamentals backend. |
expression_provider |
LocalExpressionProvider |
Expression-evaluation backend. |
dataset_provider |
LocalDatasetProvider |
Dataset assembly backend. |
provider |
LocalProvider |
Top-level data provider. |
provider_uri |
"" |
Data directory (string or per-freq dict). |
expression_cache |
None |
Expression cache class (e.g. DiskExpressionCache). |
dataset_cache |
None (client) / DiskDatasetCache (server) |
Dataset cache class. |
local_cache_path |
~/.cache/qlib_simple_cache |
Simple on-disk cache dir. |
kernels |
NUM_USABLE_CPU (cpu_count - 2) |
Parallelism; may be an int or a freq → int callable. |
maxtasksperchild |
None |
Tasks per worker process (use 1 for high-freq). |
joblib_backend |
multiprocessing |
Parallel backend. |
default_disk_cache |
1 |
0 skip / 1 use. |
mem_cache_size_limit |
500 |
In-memory cache size. |
mem_cache_limit_type |
length |
Cache eviction metric. |
mem_cache_expire |
3600 |
Memory cache TTL (seconds). |
dataset_cache_dir_name |
dataset_cache |
Cache subdir. |
features_cache_dir_name |
features_cache |
Cache subdir. |
redis_host |
127.0.0.1 |
Redis host (cache locking). |
redis_port |
6379 |
Redis port. |
redis_task_db |
1 |
Redis DB index. |
redis_password |
None |
Redis auth. |
logging_level |
logging.INFO |
Global log level. |
logging_config |
(dict) | Full logging.dictConfig (formatters, filters, handlers). |
exp_manager |
MLflowExpManager |
Experiment-manager class + uri/default_exp_name. |
mongo |
{task_url: mongodb://localhost:27017/, task_db_name: default_task_db} |
MongoDB for TaskManager. |
pit_record_type / pit_record_nan |
(dicts) | Binary record layout for PIT data. |
min_data_shift |
0 |
Minute-data market-time shift for high-freq backtest. |
Mode templates (MODE_CONF) differ in cache defaults:
client(default): caches disabled by default,region: cn,auto_mount: False,timeout: 100,custom_ops: [].server:DiskExpressionCache+DiskDatasetCacheenabled (these depend on Redis).
Warning
DiskExpressionCacheandDiskDatasetCacherequire a reachable Redis (DEPENDENCY_REDIS_CACHE). At init, if Redis is unreachable, Qlib silently disables these caches and logs a warning — it will not fail. Monitor for this warning in production; a disabled cache can silently 10–25× your data-loading time.
4.2 Region defaults
set_region() applies market-specific trading parameters:
| Region | trade_unit |
limit_threshold |
deal_price |
|---|---|---|---|
REG_CN (cn) |
100 | 0.095 | close |
REG_US (us) |
1 | None |
close |
REG_TW (tw) |
1000 | 0.1 | close |
4.3 Environment settings (QLIB_ prefix)
QSettings (qlib/config.py) reads from the environment with prefix QLIB_ and nested delimiter _:
| Env var | Maps to | Default |
|---|---|---|
QLIB_PROVIDER_URI |
provider_uri |
~/.qlib/qlib_data/cn_data |
QLIB_MLFLOW_URI |
exp_manager.kwargs.uri |
file:<cwd>/mlruns |
QLIB_MLFLOW_DEFAULT_EXP_NAME |
default experiment name | Experiment |
Note
Settings precedence is: explicit
qlib.init()kwargs >QLIB_*environment > built-in defaults. Use environment variables for deployment-level config (data location, MLflow store) andqlib.init()kwargs for per-run overrides.
4.4 Workflow config schema
The qrun YAML is the primary research configuration. Its sections (qlib_init, market, benchmark, data_handler_config, port_analysis_config, task.model, task.dataset, task.record) are documented in the User Guide. Two operational features worth highlighting:
BASE_CONFIG_PATH— inherit from a base config and override only changed fields (update_configmerge inqlib/cli/run.py). Enables a base-template + experiment-delta pattern across a model sweep.- Jinja2 templating — configs are rendered as Jinja2 before parsing; undeclared
{{ VAR }}variables are filled from matching environment variables (render_template). Enables parameter sweeps from a single file driven by env vars.
The qrun workflow handler (workflow() in qlib/cli/run.py) signature: workflow(config_path, experiment_name="workflow", uri_folder="mlruns"). If exp_manager is present under qlib_init, it is used directly; otherwise the MLflow URI is set to file:<cwd>/<uri_folder>.
5. Security
Qlib's core ships no network service, no auth, and no secret management — its threat surface is the data pipeline and the dependency graph, not an exposed endpoint. Security review should focus on the following.
5.1 Data provenance and integrity
- Bundled/collected market data is sourced from third parties (Yahoo Finance, Coingecko, baostock, East Money). The project explicitly warns this data "might not be perfect" and may contain anomalies even after price adjustment. Do not trust downloaded data blindly — run
scripts/check_data_health.pyand consider the cross-validatedcrowd_sourcedata to reduce survivorship bias. - The community data source (
chenditc/investment_data) is a third-party GitHub release fetched overwget. Verify checksums/releases before ingestion in a controlled environment.
5.2 Code-execution surfaces
Caution
Qlib's config system is powerful by design and trusting by default. Several mechanisms execute or import arbitrary code from configuration:
init_instance_by_configimports anymodule_pathand instantiates anyclassnamed in a config — including loading a pickle object from afile://path (InstConfinqlib/typehint.py).R.save_objects/load_objectand model serialization use Python pickle. Never load a recorder artifact or a config from an untrusted source — pickle deserialization is arbitrary code execution.- The
syssection of a workflow config appends arbitrary paths tosys.path(sys_configinqlib/cli/run.py).- Jinja2 config rendering pulls values from the process environment.
Treat workflow YAML files and saved artifacts as trusted code, not data. Source them only from your own pipeline.
5.3 Network and credentials
- NFS auto-mount (
_mount_nfs_uri) shells out tosudo mount.nfs(Linux) ormount -o anon(Windows). In shared deployments this requires elevated privileges; scope it carefully and prefer pre-mounting volumes overauto_mount: True. - Redis (
redis_host/redis_port/redis_password) and MongoDB (mongo.task_url) connection details live in plain config. In production, supply credentials via environment/secret injection and bind these services to private networks — they are unauthenticated by default in the example configs (mongodb://localhost:27017/,redis 127.0.0.1). - Data collectors make outbound HTTP requests to financial data providers; some (Yahoo) are geo-blocked from China.
5.4 Recommended hardening
- [ ] Run model sweeps (
run_all_model.py) in isolated virtualenvs (the default) and ideally isolated containers. - [ ] Pin and audit per-model
requirements.txt— many pin oldtorch/tensorflow/numpywith known CVEs. - [ ] Never deserialize third-party recorder artifacts or configs.
- [ ] Bind Redis/MongoDB to localhost or a private subnet; set
redis_passwordand Mongo auth. - [ ] Validate downloaded data with the health checker before training.
6. Operations
6.1 Deployment modes
| Mode | Data location | Caching | Use case |
|---|---|---|---|
| Offline (default) | Local disk per machine | Optional simple/disk caches | Single-researcher, reproducible |
| Online | Shared Qlib-Server, NFS-mounted | Disk caches shared across clients | Team, higher cache-hit rate, less disk |
Online mode is documented under the separate Qlib-Server project and supports one-click Azure deployment. In online mode, multiple clients share data and cache, improving cache-hit rate and reducing per-client disk usage.
6.2 The experiment store (MLflow)
All run state — params, metrics, tags, and artifacts (models, predictions, reports) — is persisted to the MLflow tracking URI (default file:./mlruns). Operationally:
- The URI can be a local
file:path or a remote MLflow tracking server. For file URIs, use absolute paths (the backend rejects~-style strings viaset_uri). - Concurrency: experiment creation is guarded by a
filelockon file URIs (_get_or_create_exp) because MLflow does not lock multi-process experiment creation. For non-file schemes, Qlib double-checks viaExpAlreadyExistError. - MLflow version compatibility is handled (
search_experimentsfor v2+,list_experimentsfor v1).
from qlib.workflow import R
# Audit all runs of an experiment as a DataFrame
df = R.search_records([exp_id], order_by=["metrics.ic DESC"])
# Inspect a specific run's artifacts
rec = R.get_recorder(recorder_id=rid, experiment_name="my_exp")
Note
MLflow's
search_runscaps results at 50,000 (UNLIMITED = 50000inqlib/workflow/exp.py). For very large experiment stores, page or filter withfilter_string.
6.3 Parallel & distributed training
Two trainer families (qlib/model/trainer.py):
| Trainer | Backend | Behavior |
|---|---|---|
TrainerR |
Recorder only | Linear, in-process training of a task list. |
TrainerRM |
Recorder + MongoDB TaskManager |
Tasks pushed to MongoDB; multiple worker() processes/machines pull and train in parallel. |
DelayTrainerR / DelayTrainerRM |
— | Split into a cheap train (prepare) step and a heavy end_train (fit) step — useful for "prepare on CPU VM, fit on GPU VMs". |
For TrainerRM, run the orchestrator (train) on one node and worker() on others, all sharing one task_pool (MongoDB collection). This is Qlib's mechanism for scaling a model sweep across machines.
6.4 Data lifecycle operations
| Task | Command |
|---|---|
| Download data | python scripts/get_data.py qlib_data --target_dir <dir> --region <cn|us|in> |
| Health check | python scripts/check_data_health.py check_data --qlib_dir <dir> |
| Incremental daily update | python scripts/data_collector/yahoo/collector.py update_data_to_bin --qlib_data_1d_dir <dir> |
| Rebuild from raw | collect → normalize_data → python scripts/dump_bin.py dump_all |
| Point-in-time dump | python scripts/dump_pit.py dump --data_path <dir> --qlib_dir <dir> --interval quarterly |
| Automated cron update | * * * * 1-5 python scripts/data_collector/yahoo/collector.py update_data_to_bin --qlib_data_1d_dir <dir> |
Tip
dump_bin.py dump_allparallelizes with--max_workers(default 16) and selects fields via--include_fields/--exclude_fields. For high-frequency data, setmaxtasksperchild: 1in the runtime config to bound per-process memory.
6.5 Logging
Logging is fully configurable through the logging_config runtime key (a logging.dictConfig). Notable built-ins (qlib/log.py):
- A custom
LogFiltersuppresses noisy "data not found" warnings by regex. set_global_logger_level(level)and theset_global_logger_level_cmcontext manager adjust handler levels at runtime.TimeInspector(logtcontext manager) instruments code blocks for timing — useful for profiling data-loading bottlenecks.
7. Repository Structure
qlib/
├── __init__.py init(), auto_init(), NFS mount logic
├── config.py QlibConfig, _default_config, MODE_CONF, region config, QSettings
├── constant.py REG_CN/US/TW, EPS, INF
├── log.py logging, LogFilter, TimeInspector
├── typehint.py InstConf / InstDictConf (config-as-instance contract)
├── cli/
│ ├── run.py `qrun` workflow runner (fire-based)
│ └── data.py `python -m qlib.cli.data` data downloader
├── data/ Data layer: providers, expression engine, caches, _libs (Cython)
│ └── dataset/ DatasetH, DataHandler(LP), processors, samplers
├── model/ base.py (Model/ModelFT), trainer.py (TrainerR/RM)
├── workflow/ R recorder, ExpManager, RecordTemp, task/ (TaskManager)
├── strategy/ BaseStrategy, RLStrategy, RLIntStrategy
├── backtest/ Exchange, Executor, Position, Account, decision
├── rl/ Reinforcement-learning framework (interpreters, trainer, order_execution)
├── contrib/ Batteries-included: models, data handlers (Alpha158/360),
│ strategies (TopkDropout), evaluation, reporting, rolling, tuner
├── utils/ init_instance_by_config, serialization, parallel, time
└── tests/ GetData, canned configs (CSI300_GBDT_TASK, CSI300_BENCH)
scripts/ get_data.py, dump_bin.py, dump_pit.py, check_data_health.py,
└── data_collector/ per-source collectors (yahoo, cn_index, us_index, crypto, fund, pit, ...)
examples/ workflow_by_code.py, run_all_model.py, benchmarks/<MODEL>/,
benchmarks_dynamic/, rl_order_execution/, nested_decision_execution/,
highfreq/, tutorial/
docs/ Sphinx documentation (readthedocs)
7.1 Module reference (HIGH-priority)
| Module | Lines (≈) | Responsibility |
|---|---|---|
qlib/data |
173K chars | Providers, expression engine, calendar/instrument/feature access, caches. |
qlib/utils |
116K chars | init_instance_by_config, serialization, parallelism, time utilities. |
qlib/workflow |
106K chars | Recorder/experiment management (MLflow wrapper), record templates. |
qlib/data/dataset |
98K chars | DatasetH, DataHandlerLP, processors, weight/reweighter, samplers. |
qlib/contrib/data |
76K chars | Alpha158/Alpha360 handlers and feature definitions. |
qlib/workflow/task |
51K chars | TaskManager (MongoDB), task generation, collection. |
qlib/rl (+ utils) |
62K chars | RL interpreters, trainer, order-execution environment. |
qlib/backtest |
227K chars | Exchange, executors (incl. NestedExecutor), position, account, decisions. |
qlib/model |
27K chars | Model/ModelFT base, Trainer family. |
qlib/strategy |
11K chars | BaseStrategy, RL strategy bases. |
qlib/contrib/rolling |
28K chars | Rolling-retrain driver (python -m qlib.contrib.rolling). |
qlib/contrib/tuner |
16K chars | Hyperparameter tuning launcher. |
8. Internals & Extension Points
8.1 Config-driven instantiation (the core idiom)
init_instance_by_config(config, accept_types=..., default_module=...) is the universal factory. A config can be:
- A dict
{class, module_path, kwargs}(the common case). - A class object directly, with
kwargs. - A string: a class name, a dotted
a.b.c.ClassName, or afile://.../obj.pklpickle path. - An already-constructed instance (passed through).
The task executor (_exe_task in qlib/model/trainer.py) shows the full lifecycle: instantiate model + dataset, auto_filter_kwargs(model.fit)(dataset, reweighter=...), save the model and (config-only) dataset, fill the <MODEL>/<DATASET> placeholders via fill_placeholder, then run each record template's generate().
8.2 Writing a custom model
Subclass qlib.model.base.Model and implement fit and predict:
from qlib.model.base import Model
from qlib.data.dataset import Dataset
from qlib.data.dataset.handler import DataHandlerLP
class MyModel(Model):
def fit(self, dataset: Dataset, reweighter=None):
df_train, df_valid = dataset.prepare(
["train", "valid"], col_set=["feature", "label"], data_key=DataHandlerLP.DK_L
)
x_train, y_train = df_train["feature"], df_train["label"]
# ... train self ...
def predict(self, dataset: Dataset, segment="test"):
x = dataset.prepare(segment, col_set="feature", data_key=DataHandlerLP.DK_I)
return ... # pandas.Series indexed by (datetime, instrument)
Note
Learned attributes must not start with
_so the model serializes cleanly (Serializablecontract). For fine-tunable models, subclassModelFTand addfinetune(dataset).
8.3 Writing a custom strategy
Subclass qlib.strategy.base.BaseStrategy and implement generate_trade_decision(execute_result). The base provides executor, trade_calendar, trade_position, and trade_exchange via the shared level_infra / common_infra infrastructure objects. For RL strategies, subclass RLStrategy (carries a policy) or RLIntStrategy (adds state_interpreter / action_interpreter that translate between Qlib execution results and the RL env).
8.4 Custom expression operators
Pass custom_ops to qlib.init() — each element is either an ExpressionOps subclass or a {class, module_path} dict. They are registered by register_all_ops at init, extending the $field/operator expression language.
8.5 Record templates
Custom analysis = subclass RecordTemp (qlib/workflow/record_temp.py) and implement generate(). Templates declare artifact_path and an optional depend_cls so dependent records (e.g. SigAnaRecord depending on SignalRecord) can locate upstream artifacts. The built-in chain is SignalRecord → SigAnaRecord → PortAnaRecord.
9. Code Quality & Conventions
- Consistent factory pattern. Nearly every component is built through
init_instance_by_config, giving a uniform, declarative, swap-anything design. This is the platform's defining architectural strength. - MLflow wrapper rationale.
qlib/workflow/__init__.pydocuments why Qlib wraps MLflow rather than using it directly: object-oriented recorder handles instead of barerun_ids, code-diff logging at run start, andlog_object/load_objectfor Python objects. The cost is the up-front need to create an experiment before getting a recorder. - Abstract base + concrete impl is used consistently (
Experiment/MLflowExperiment,ExpManager/MLflowExpManager,Trainer/TrainerR/TrainerRM), keeping the backend swappable. - Pydantic settings (
QSettings) provide typed, env-overridable configuration. - Cython hot paths. Rolling/expanding window operators are compiled C++ (
qlib/data/_libs/*.pyx) for the expression engine — the source of Qlib's data-throughput advantage.
9.1 Performance characteristics
Qlib's own storage benchmark (14 features over ~800 stocks/day, 2007–2020) demonstrates the compact-binary + cache design:
| Storage | HDF5 | MySQL | MongoDB | InfluxDB | Qlib −E −D | Qlib +E −D | Qlib +E +D |
|---|---|---|---|---|---|---|---|
| 1 CPU (s) | 184.4 | 365.3 | 253.6 | 368.2 | 147.0 | 47.6 | 7.4 |
| 64 CPU (s) | — | — | — | — | 8.8 | 4.2 | — |
(+E = ExpressionCache, +D = DatasetCache.) The takeaway for operators: enable both caches in any throughput-sensitive deployment.
10. Known Issues & Compatibility
These are confirmed from the project's issue tracker and release notes — track them when pinning dependencies.
| Issue | Impact | Mitigation |
|---|---|---|
| LightGBM 4.0+ incompatibility | TypeError when early_stopping_rounds=None; affects model training and DDG-DA. |
Pin LightGBM 3.x (e.g. 3.1.0) or use a patched Qlib build. |
| DDG-DA chained failures | Dynamic workflow fails on LightGBM 4.0+, unhashable-list in InternalData.setup(), and pandas indexing. |
Use the example's pinned deps in an isolated env. |
SeriesDFilter redundant execution |
Filter pipe re-runs per fields_group, slowing data loading. |
Reduce distinct field-group filters; enable caches. |
FileCalendarStorage.index() defect |
Reported calendar-storage bug. | Track upstream fix; validate calendar data. |
pandas 1.5 → 2.0 group_keys change |
A few scripts (gen_training_orders.py, TRA dataset, tft.py) may misbehave. |
Qlib sets group_key=False; pin a compatible pandas. |
Missing benchmark index (SH000300) |
Backtest aborts if the benchmark isn't in the data set. | Ensure region/data alignment. |
| Official dataset disabled | Built-in downloader may return empty data. | Use community chenditc/investment_data. |
11. Potential Improvements
For maintainers and contributors, the following are visible technical-debt and enhancement areas (several flagged in-repo):
- LightGBM 4.0+ support across all GBDT models and the DDG-DA pipeline — the most impactful compatibility gap.
run_all_model.pyportability — currently Linux-only and cannot run the same model in parallel across iterations; both are noted as planned.SeriesDFilteroptimization — deduplicate filter-pipe execution across field groups to fix the slow-loading path.- GeneralPtNN consolidation — migrate existing per-architecture NN models onto the unified
GeneralPtNNdesign so swapping a PyTorch module is the only change needed. - Data robustness — the project itself recommends users supply their own high-quality data; the crowd-sourced/cross-validated pipeline reduces survivorship bias and could become the default.
- Find rough edges — the README explicitly suggests
rg 'TODO|FIXME' qlibto surface incomplete implementations.
12. Contributing
- Repo:
https://github.com/microsoft/qlib(MIT, Microsoft Open Source CoC). A CLA is required on first PR. - Dev install:
pip install -e .[dev]; seedocs/developer/code_standard_and_dev_guide.rst. - Good entry points: the
good first issuelabel, doc fixes, new models (examples/benchmarks/#contributing), new datasets, and bug fixes. - Build docs:
cd docs/ && make html(requiressphinx+sphinx_rtd_theme). - CI reference: if local install/examples fail, compare against
.github/workflows/test_qlib_from_source.yml.
Tip
When adding a model, follow the existing
examples/benchmarks/<MODEL>/convention: aworkflow_config_*.yaml, arequirements.txtwith pinned deps, and aREADME.mdciting the source paper. This keeps the model zoo reproducible andrun_all_model.py-compatible.
13. Quick Reference
Initialization
import qlib
from qlib.constant import REG_CN
qlib.init(provider_uri="~/.qlib/qlib_data/cn_data", region=REG_CN)
Key globals & factories
| Symbol | Module | Role |
|---|---|---|
C |
qlib.config |
Global QlibConfig singleton. |
D |
qlib.data |
Data access (calendar/instruments/features). |
R |
qlib.workflow |
Experiment/recorder manager (MLflow wrapper). |
init_instance_by_config |
qlib.utils |
Build any component from a config dict. |
Model / ModelFT |
qlib.model.base |
Model base classes. |
TrainerR / TrainerRM |
qlib.model.trainer |
Linear / MongoDB-parallel trainers. |
BaseStrategy |
qlib.strategy.base |
Strategy base. |
SignalRecord / SigAnaRecord / PortAnaRecord |
qlib.workflow.record_temp |
Analysis record templates. |
Operational commands
| Command | Purpose |
|---|---|
qrun <config.yaml> [exp_name] |
Run a workflow. |
python scripts/get_data.py qlib_data --target_dir <dir> --region cn |
Download data. |
python scripts/check_data_health.py check_data --qlib_dir <dir> |
Validate data. |
python scripts/dump_bin.py dump_all --data_path <dir> --qlib_dir <dir> --freq day |
Build binary data. |
python run_all_model.py run <n> |
Benchmark sweep (Linux). |
python -m qlib.contrib.rolling base --conf_path <yaml> run |
Rolling retrain. |
Service endpoints (optional, default insecure)
| Service | Default | Used by |
|---|---|---|
| Redis | 127.0.0.1:6379, db 1, no password |
Disk caches (server mode). |
| MongoDB | mongodb://localhost:27017/, db default_task_db |
TrainerRM / TaskManager. |
| MLflow | file:<cwd>/mlruns |
Experiment tracking. |