
简介这份PDF资料是华泰证券金工研究团队2020年12月发布的深度研究报告聚焦微软AI量化投资平台Qlib的体验与评测面向量化投资研究者、金融工程从业者及希望降低AI选股门槛的开发者。报告以港股日频量价因子LightGBM选股策略为案例完整梳理Qlib安装、数据准备、因子生成、策略构建与结果展示的基础流程并进一步讲解自定义因子、标签、数据预处理方式与AI模型等进阶组件同时对比传统量化开发流程提炼Qlib在数据存储方案、表达式引擎和缓存系统上的工程创新及性能优势。资源包共1个PDF文件约4.71MB内容结构清晰涵盖研究导读、快速上手、进阶功能与风险提示等模块。目前已有1173人学习适合希望系统了解Qlib框架、借鉴券商研究视角并动手复现案例的读者参考。1. 从一份港股数据开始Qlib 到底能替你省掉哪几步手里有一批港股日频行情 csv想跑一个量价因子选股的 AI 策略传统做法是 pandas 读数据、手写因子、sklearn 训模型、再自己搭回测中间还要处理复权、对齐交易日历、算 IC——每一步都能单独翻车。微软亚洲研究院开源的 Qlib 就是冲着这条链路来的它把数据存储、因子表达式、模型训练、回测评估串成一套工作流官方定位是覆盖量化投资全过程的 AI 量化开源平台。这份资源适合已经会写 Python、想快速验证量价选股想法的人也适合想看清一个工业级量化框架内部怎么组织数据与组件的工程师。下面按安装、数据、因子、策略、回测、自定义组件的顺序拆坑在哪一并说清。2. 装 Qlib 与备数据两个最容易卡住的前置环节Qlib 的安装本身不难难在依赖和网络环境。官方给了 pip 和 setup.py 两条路我实测下来更推荐后者原因不是 pip 不能用而是 pip 装出来的稳定版有时和你手头源码包的目录结构对不上后面跑脚本会莫名其妙找不到模块。这一章把安装、官方数据下载、用户 csv 转换三件事按顺序落地。2.1 先解决 C 生成工具这个硬依赖Qlib 的部分扩展模块在安装时要本地编译Windows 上缺 Microsoft Visual C 14.0 会直接报错error: Microsoft Visual C 14.0 is required. Get it with Build Tools for Visual Studio注意只装运行库Redistributable解决不了这个问题必须装完整的 C 生成工具。装的时候在安装器里勾选「使用 C 的桌面开发」这一组工作负载别只勾一个空壳。Mac 和 Linux 一般自带编译链跳过这步即可。依赖装好后走 setup.py 方式# 先保证 numpy 和 cython 是最新的 pip install numpy pip install --upgrade cython # 有 git 的情况 git clone https://github.com/microsoft/qlib.git cd qlib python setup.py install # 没有 git下载 zip 源码包解压到任意路径确保 setup.py 在该目录下 cd /path/to/qlib python setup.py installsetup.py install装的是包含开发版在内的最新代码版本号会带 dev 后缀这对想跟进新功能的人是好事但也意味着稳定性不如正式版生产环境要自己评估。装完在 Python 里import qlib不报错第一步就算过了。2.2 官方数据下载与 csv 转换的字段要求官方提供 A 股和美股数据用于学习。在 Qlib 安装路径下执行python scripts/get_data.py qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn--target_dir是数据落地目录--region cn指定 A 股。如果用的是 pip 安装这条命令可能报ModuleNotFoundError: No module named qlib.tests原因是 pip 包没带 tests 目录。解决办法是从源码包里把tests文件夹拷到安装路径下这也是我前面推荐 setup.py 的原因之一。用自己的数据时Qlib 要求每只股票一个 csv文件名即股票代码所有文件放同一目录。字段至少包含下表这些字段含义备注stock_code股票代码与文件名一致列名不唯一date日频日期列名不唯一open / high / low / close复权价建议后复权vwap复权均价回测会用到volume / money成交量 / 成交额量价因子基础factor复权因子强烈建议保留change相对前一日涨跌幅强烈建议保留两个血泪坑一是价格务必用复权价因为后续标签计算用 close 或 vwap 算未来收益回测也用这几个字段成交不复权会让收益和净值失真二是factor或change字段至少要有其一缺了跑官方全流程范例时策略收益会出现异常而且不报错属于典型的黑匣子问题。转换命令如下python scripts/dump_bin.py dump_all \ --csv_path ~/.qlib/csv_data/hk_data \ --qlib_dir ~/.qlib/qlib_data/hk_data \ --symbol_field_name stock_code \ --date_field_name date \ --include_fields open,high,low,close,volume,money,factor,vwap,change--csv_path是原始 csv 目录--qlib_dir是转换后 bin 数据落地目录--symbol_field_name和--date_field_name对应你 csv 里的代码列和日期列名--include_fields列出其余字段。这里有个细节逗号后不能有空格写成open, high会直接转换失败。转换完成后目录下会出现 calendar、features、instruments 三块分别存交易日历、因子数据和股票池后面所有读取都基于这个结构。3. 因子生成与 LightGBM 选股把工作流串起来数据就位后核心是把「读数据 → 算因子 → 训模型 → 回测」这条 workflow 跑通。Qlib 的设计是把每个环节做成可配置组件用一份配置字典驱动理解这份配置的结构比背 API 更重要。3.1 初始化环境与 Alpha158 因子库先初始化 Qlib 运行环境并指向自己的数据目录import qlib from qlib.constant import REG_HK # provider_uri 指向 dump 后的数据目录region 决定交易日历和交易规则 qlib.init(provider_uri~/.qlib/qlib_data/hk_data, regionREG_HK)provider_uri必须指向含 calendar/features/instruments 的目录region影响涨跌停、交易成本等默认规则港股用REG_HK。初始化后可以用D.calendar()取交易日、D.instruments()取股票池再用D.features()按字段取数这一步是验证数据转换是否成功的最快方式。因子不用手写Qlib 内置 Alpha158 因子库用表达式引擎描述量价因子比如Ref($close, 1)/$close - 1就是一日反转。生成特征和标签from qlib.contrib.data.handler import Alpha158 # 标签用下期收益特征用当期量价因子 handler Alpha158( instrumentscsi300, # 换成自己的股票池名称 start_time2008-01-01, end_time2020-11-30, fit_start_time2008-01-01, fit_end_time2017-12-31, )fit_start_time和fit_end_time是预处理如标准化的拟合区间必须早于测试区间否则就是未来函数。这是很多人第一次跑通却指标虚高的根源。3.2 模型训练参数 task 的拆解Qlib 用一个大字典task描述训练任务关键在model和dataset两块from qlib.contrib.model.gbdt import LGBModel from qlib.contrib.data.dataset import DatasetH from qlib.contrib.data.handler import Alpha158 data_handler_config { start_time: 2008-01-01, end_time: 2020-11-30, fit_start_time: 2008-01-01, fit_end_time: 2017-12-31, instruments: csi300, } task { model: { class: LGBModel, module_path: qlib.contrib.model.gbdt, kwargs: {loss: mse, learning_rate: 0.05, num_leaves: 64}, }, dataset: { class: DatasetH, module_path: qlib.contrib.data.dataset, kwargs: { handler: {class: Alpha158, module_path: qlib.contrib.data.handler, kwargs: data_handler_config}, segments: {train: (2008-01-01, 2017-12-31), valid: (2018-01-01, 2018-12-31), test: (2019-01-01, 2020-11-30)}, }, }, }segments把时间切成训练、验证、测试三段测试段绝不能参与拟合。learning_rate和num_leaves是 LightGBM 的核心调参项学习率小、叶子多容易过拟合先用默认量级跑通再调。训练只需一行from qlib.model.trainer import task_train model task_train(task, experiment_namehk_lgb_demo)experiment_name是实验名Qlib 会把模型、预测结果、配置都归档方便复现和对比这个机制比手动存 pkl 靠谱得多。3.3 回测配置与绩效读取训练完拿到预测分数回测配置决定怎么把分数变成持仓port_analysis_config { strategy: { class: TopkDropoutStrategy, module_path: qlib.contrib.strategy.signal_strategy, kwargs: {signal: model.predict, topk: 50, n_drop: 5}, }, backtest: { start_time: 2019-01-01, end_time: 2020-11-30, account: 100000000, benchmark: SH000300, # 换成对应港股基准 exchange_kwargs: {freq: day, limit_threshold: 0.095, deal_price: close}, }, }topk是持仓数n_drop是每期换出的股票数limit_threshold控制涨跌停不可成交的阈值deal_price决定按收盘还是均价成交。回测跑完后用risk_analysis读 IC、Rank IC、净值、最大回撤和换手率。这里要清醒官方和研报里的港股案例仅作教学没剔除低价股和低流动性股票训练测试区间也短指标好看不代表策略可用。4. 自定义组件改参数、改源码还是写子类跑通默认流程只是入门真正干活时因子、标签、预处理、模型几乎都要换。Qlib 每个组件都有对应参数和源码自定义有三档改参数最轻改源码最直接继承写子类最干净。4.1 自定义特征与标签特征可以在 handler 里追加表达式标签则通过label配置改from qlib.contrib.data.handler import Alpha158 class MyHandler(Alpha158): def get_label_config(self): # 改成未来 5 日收益字段名自定义 return [Ref($close, -5) / $close - 1], [LABEL5] def get_feature_config(self): fields, names super().get_feature_config() # 追加一个量价背离因子 fields.append($volume / Mean($volume, 20)) names.append(VOL_RATIO20) return fields, namesRef($close, -5)里的负号表示向未来取数只在标签里用特征里用就是未来函数。追加因子时注意表达式引擎的语法Mean、Ref、Std这些算子都是内置的写错不会报语法错而是返回空值排查时先看因子覆盖率。4.2 换预处理与换模型预处理在qlib.data.dataset.processor下常见的有DropnaLabel、CSZScoreNorm、RobustZScoreNorm。Alpha158 默认带一套预处理想换就在 dataset 的 kwargs 里显式指定 processor 列表顺序会影响结果标准化要放在去极值之后。换模型最省事的是改task[model]的class和module_pathQlib 内置了 LightGBM、XGBoost、线性模型、部分深度模型。内置没有的仿照现有模型写子类from qlib.model.base import Model from sklearn.svm import SVR class SVRModel(Model): def __init__(self, **kwargs): self.model SVR(**kwargs) def fit(self, dataset): x_train, y_train dataset.prepare(train, col_set[feature, label], data_keylearn) self.model.fit(x_train.values, y_train.values.ravel()) def predict(self, dataset): x_test, _ dataset.prepare(test, col_set[feature, label], data_keylearn) return x_test关键是fit和predict的入参出参要和框架约定一致prepare的data_key决定取哪段数据。写子类的好处是原组件不动出问题好回退。5. 避坑与排查五个真实会卡住你的地方5.1 安装报 C 14.0 缺失现象pip install或setup.py install中途报 Microsoft Visual C 14.0 required。原因只装了运行库没装编译工具。解决装完整 C 生成工具并勾选桌面开发工作负载重开命令行再装。5.2 get_data 报找不到 qlib.tests现象下载官方数据时ModuleNotFoundError: No module named qlib.tests。原因pip 安装包未包含 tests 目录。解决从源码 zip 里拷 tests 到安装路径或直接用 setup.py 方式安装。5.3 dump_all 转换后因子全空现象数据转换成功但D.features()取出来全是 NaN。原因--include_fields逗号后带了空格或 csv 字段名与参数不一致。解决去掉空格逐字段核对列名转换后先抽查一只股票的 close 序列是否连续。5.4 回测净值曲线异常平滑或收益离谱现象策略收益高得不真实或净值几乎不动。原因价格未复权、缺 factor/change 字段或预处理拟合区间覆盖了测试段。解决统一用后复权价补齐字段严格保证fit_end_time早于测试起点。5.5 自定义因子不生效现象改了 handler 但训练结果和默认一模一样。原因task 里 dataset 的 handler 仍指向原类或实验缓存复用了旧结果。解决确认module_path和class指向新类换一个experiment_name重跑别在旧实验上覆盖。6. 用实验归档做对比一个我每次都会走的验证习惯Qlib 最容易被低估的功能是实验管理。很多人跑完一次回测看一眼净值就完事下次改个参数再跑两次结果混在一起根本说不清是因子起作用还是模型调参起作用。我的做法是每次训练都带独立的experiment_name然后用 recorder 把关键指标拉出来横向对比from qlib.workflow import R # 列出所有实验按需取某次运行的指标 experiments R.list_experiments() for exp_name in experiments: rec R.get_recorder(experiment_nameexp_name) metrics rec.list_metrics() ic rec.load_object(pred_score) # 预测分数对象 print(exp_name, metrics)R.list_experiments()返回实验列表get_recorder定位到具体一次运行list_metrics拿到 IC、Rank IC、年化收益等记录值。这样改因子、换模型、调topk的每一次尝试都有独立档案对比时不会串味。验证层面我一般固定三步先看预测分数的 IC 和 Rank IC 是否稳定为正再看净值相对基准的超额是否单调最后看换手率和最大回撤是否在可接受范围。三步里任何一步异常先回去查数据复权和预处理区间而不是急着调模型参数——十次里有七八次问题出在前处理不在模型本身。还有一个具体技巧把segments的验证段单独留出来做早停测试段只在最后看一次。反复在测试段上调参等于把测试集变成了训练集指标再漂亮也是自欺欺人。这套流程跑顺之后换股票池、换市场只是改region和数据目录的事工作流本身不用重写。从那以后我每次接一个新的量价策略都强制先跑一遍默认 Alpha158 加 LightGBM 拿到基线再动任何自定义组件基线不对就先修数据。希望这套拆法能帮到你少在安装和数据格式上耗时间把精力留给因子和模型。本文还有配套的精品资源点击获取