简介:这份PDF资料是华泰证券金工研究团队2020年12月发布的深度研究报告,聚焦微软AI量化投资平台Qlib的体验与评测,面向量化投资研究者、金融工程从业者及希望降低AI算法使用门槛的开发者。报告以港股日频量价因子LightGBM选股策略为例,分安装、数据准备、因子生成、策略构建、结果展示等步骤讲解基础功能,并进一步介绍自定义因子、标签、数据预处理方式与AI模型等进阶用法,同时对比传统量化开发流程,提炼Qlib在数据存储方案、表达式引擎和缓存系统上的工程创新。资源包共1个PDF文件,大小约4.71MB,内容完整、结构清晰,便于按章节检索学习。目前已有1173人学习下载,适合希望快速上手Qlib、理解其优势与局限并借鉴案例设计新策略的读者参考。
1. 从一份“跑不通”的官方示例说起:这套方案要解决什么
量化选股这件事,最劝退新人的往往不是模型本身,而是从原始行情到回测净值之间那条又长又碎的链路:装环境、转数据、算因子、训模型、跑回测,每一步都可能卡在版本、字段、路径上。某高校实验室做课程设计时,A 同学照着官方示例跑港股日频量价选股,结果卡在 C++ 编译报错和因子收益异常上,折腾一周没出图。这套方案要解决的正是这个:用一套覆盖量化投资全过程的 AI 选股工作流,把“数据准备—因子生成—模型训练—策略回测—绩效分析”串成可复现的流水线,适合做量化方向毕设、课设,或需要交付一份完整选股方案的人直接参考。
2. 总体架构设计:三层框架与工作流串联的职责划分
Qlib 的定位是“AI 量化投资平台”,落到工程上可以拆成三层:基础架构层负责数据存储、表达式计算和缓存;量化投资流程层负责把因子、标签、模型、回测这些组件按工作流串起来;交互层负责用户调用和结果读取。理解这三层,后面每一步操作才知道自己在动哪一块。
2.1 三层框架与模块边界
基础架构层是这套方案的地基。它把行情数据从 csv 转成 bin 存储,用表达式引擎按需计算因子,再用缓存系统避免重复计算。流程层是“业务编排”,一个 workflow 里包含数据处理器、模型、回测配置,参数一改,整条链路跟着变。交互层则是我们写脚本调用的入口,初始化运行环境、取数据、读结果都在这一层完成。
我一般会把三层对应到交付物上:基础架构层对应“数据能不能读、因子算得快不快”,流程层对应“策略配置对不对”,交互层对应“结果能不能拿出来写进报告”。做毕设时,评审最常问的也是这三件事,先把边界划清,后面排查问题不会乱。
2.2 工作流的组件串联方式
一个完整的 AI 选股工作流,组件顺序是固定的:先由数据处理器生成特征和标签,再交给模型训练,训练完的预测结果进入回测,最后做绩效分析。每个组件都有对应参数,最简单的自定义就是改参数,更灵活的方式是改源码或继承出新类。
下面这段是工作流的核心配置骨架,字段名按项目实际结构写,参数含义在代码后说明:
from qlib.contrib.model.gbdt import LGBModel 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", # 股票池,港股场景换成自定义池 } # 模型参数:LightGBM 的学习率、树数量、叶子数 model = LGBModel( loss="mse", learning_rate=0.05, num_leaves=64, num_threads=8, ) # 把处理器和模型塞进同一个任务 task = { "model": {"class": "LGBModel", "module_path": "qlib.contrib.model.gbdt", "kwargs": model.get_params()}, "dataset": {"class": "DatasetH", "module_path": "qlib.data.dataset", "kwargs": {"handler": Alpha158(**data_handler_config), "segments": {"train": ("2008-01-01", "2017-12-31"), "test": ("2018-01-01", "2020-11-30")}}}, }这段配置里,fit_start_time和fit_end_time决定预处理阶段的统计窗口,segments决定训练集和测试集的切分,两者不能混。num_leaves和learning_rate是 LightGBM 最影响过拟合的两个参数,课程设计阶段先固定一组能跑通的,别一上来就调参。工作流跑通之后再谈优化,顺序反了会一直在“没结果”和“结果不可信”之间打转。
2.3 数据存储与表达式引擎为什么值得单独设计
传统做法是把因子算好存进关系型数据库或 HDF5,读的时候整表拉出来。Qlib 换了个思路:原始行情按列存成 bin,因子不预先落库,而是用表达式引擎在读取时按表达式现算,配合缓存复用结果。论文里的对比测试显示,读取原始数据和生成因子这两类任务上,这套方案比 MySQL、MongoDB、InfluxDB 和 HDF5 表现更好。
对做方案的人来说,这个设计的实际意义是:因子库可以很大,但不必为每个因子建一张表;改因子表达式不用重跑全量落库;重复回测时缓存能省掉大量计算。代价是第一次跑会慢一些,且表达式写错时报错信息不如 SQL 直观,这也是后面避坑章节要重点讲的地方。
3. 基础功能落地:港股日频量价选股的五步实现
这一章按“安装—数据—因子—策略—结果”五步走,场景选港股日频量价因子配 LightGBM。选港股而不是官方示例的 A 股,是因为换一个市场能逼着你把数据格式、字段、股票池这些“官方代码帮你绕过的坑”真正走一遍,代入感更强,交付时也更能说明你理解了整条链路。
3.1 环境安装:为什么推荐 setup.py 而不是 pip
官方给两种安装方式,pip 一行命令最省事,但实测在 Windows 和 Mac 上都更容易遇到依赖编译问题。更稳的是源码方式:先装好 numpy 并升级 cython,再进源码目录执行安装。
pip install numpy pip install --upgrade cython # 方式一:已配置 git git clone <qlib源码地址> && cd qlib python setup.py install # 方式二:下载 zip 解压后,进入含 setup.py 的目录 python setup.py install关键前置是 Microsoft Visual C++ 14.0 生成工具。注意只装运行库(Redistributable)解决不了编译报错,要装完整的生成工具并在安装时勾选 C++ 生成相关组件。这一步是新人第一个翻车点,报错信息里其实写清楚了,照着装就行。源码方式装的是含开发版的最新版,功能比稳定版全,做课设够用。
3.2 数据准备:csv 转 bin 的字段要求
官方数据可以直接用脚本下载,但做方案更常见的是用自己的行情数据。Qlib 要求每只股票一个 csv,文件名即股票代码,字段至少包含开高低收、成交量、成交额、复权因子、均价和涨跌幅。转换用dump_all:
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参数里symbol_field_name和date_field_name必须和 csv 表头完全一致;include_fields逗号后不能有空格,否则转换直接出错。两个容易忽略的点:价格要用复权价,因为后续标签用收盘价或均价算未来收益、回测也用它成交;数据里必须带factor或change字段,缺了它策略净值和收益会出现异常。指数数据按同样格式单独存一份作基准,放在同一目录下。
3.3 因子生成:Alpha158 与自定义股票池
数据就位后,初始化运行环境,先确认能取到交易日历和股票列表,再取单只股票指定日期区间的字段,验证数据链路通不通。股票池可以自定义,把港股里符合条件的标的筛出来,避免把权证、低流动性标的混进去。
因子库用 Alpha158,它把当期量价特征和下期收益标签一起生成。标签默认用未来收益,特征则是各类量价变换。生成后建议先抽查几只股票的因子值和标签,确认没有大面积空值或极端值,再进模型。这一步花十分钟,能省掉后面几小时的“模型不收敛”排查。
3.4 策略构建与回测配置
模型训练就是把上一章的工作流配置跑起来,训练完拿到预测分数。回测配置决定怎么用这些分数选股、调仓、算成本:
port_analysis_config = { "strategy": { "class": "TopkDropoutStrategy", "module_path": "qlib.contrib.strategy", "kwargs": {"signal": "<预测分数>", "topk": 50, "n_drop": 5}, }, "backtest": { "start_time": "2018-01-01", "end_time": "2020-11-30", "account": 10000000, "benchmark": "hkhsi", "exchange_kwargs": {"freq": "day", "limit_threshold": 0.095, "deal_price": "close"}, }, }topk是持仓数量,n_drop是每期换出的只数,两者共同决定换手率。limit_threshold模拟涨跌停限制,港股场景按实际规则调整。deal_price用收盘价成交是简化处理,写报告时要说明这是假设,别当成真实成交价。
3.5 结果读取与绩效指标
回测跑完,读预测结果的 IC 和 Rank IC 判断模型有没有选股能力,再读净值、超额收益净值、最大回撤和换手率。IC 长期在 0 附近说明因子和模型没提供有效信号,先回头查标签和预处理,而不是急着换模型。净值曲线要同时看绝对收益和相对基准的超额,只看一条容易误判。
4. 进阶定制:四个可替换组件的改法与边界
基础流程跑通只说明“能用”,交付一份像样的方案还得说明“能改”。Qlib 的组件都通过参数控制,改参数是最轻的定制,改源码或继承新类是更深的定制。这一章按特征、标签、预处理、模型四个组件讲,每个都给可抄的改法。
4.1 自定义特征与标签
特征定制最直接的方式是在因子表达式里加自己的量价组合,比如把某几个字段做比值或滚动统计,注册进处理器。标签定制有两种:改参数指定标签表达式,或改因子库源码里的标签定义。前者适合换收益计算窗口,后者适合换收益口径。
# 通过参数改标签:把下期收益窗口从默认改成 5 日 from qlib.contrib.data.handler import Alpha158 handler = Alpha158( start_time="2008-01-01", end_time="2020-11-30", fit_start_time="2008-01-01", fit_end_time="2017-12-31", label=["Ref($close, -5) / Ref($close, -1) - 1"], # 5 日未来收益 )Ref($close, -5)表示向后取 5 个交易日的收盘价,负号方向别写反,写反会变成用未来数据算历史标签,回测好看但完全不可用。这是量化里最典型的“看起来很美”陷阱,交付前一定用样本外时间段验证。
4.2 更换数据预处理方法
内置预处理包括缺失值填充、标准化、去极值等,Alpha158 和 Alpha360 各有默认组合。换预处理就是换处理器参数或继承处理器类重写处理链。常见需求是把标准化窗口和训练窗口对齐,避免用测试期统计量污染训练。
from qlib.data.dataset.processor import RobustZScoreNorm, Fillna # 自定义处理链:先填缺失,再按训练窗口做稳健标准化 processors = [ Fillna(fields_group="feature"), RobustZScoreNorm(fields_group="feature", fit_start_time="2008-01-01", fit_end_time="2017-12-31"), ]fit_start_time和fit_end_time必须落在训练区间内,这是防止数据泄漏的关键参数。很多人图省事不填,默认用全区间统计,样本外指标会虚高。
4.3 更换 AI 模型
内置模型覆盖梯度提升、神经网络等常见类型。换模型有两种路径:参数里指定模型类和超参,或仿照现有模型写一个继承类接入新算法。前者改配置即可,后者要保证输入输出接口一致——输入是特征矩阵和标签,输出是预测分数。
from qlib.model.base import Model class MyModel(Model): def fit(self, dataset): # 从 dataset 取训练段特征和标签,训练自己的模型 ... def predict(self, dataset): # 对测试段输出预测分数,形状要和样本对齐 ...继承类最容易错的是predict返回的索引和数据集对不上,回测阶段会报对齐错误。写完先用小样本跑一遍fit和predict,确认形状和索引再进全流程。
4.4 定制能力的边界
参数级定制适合课程设计快速出结果,源码级定制适合毕设体现工作量。但要清楚:换模型、换因子不等于策略有效,样本外表现才是验收依据。定制越多,越要保留一组基线配置做对照,否则改到最后说不清提升来自哪里。
5. 避坑与排查:五个最容易翻车的点
这一章按“现象—原因—解决”写,都是这条链路上真实会卡住人的地方。做方案时把这几条提前写进文档,答辩被问到也能答得上来。
5.1 安装阶段报 C++ 编译错误
现象:执行安装命令时报 Microsoft Visual C++ 14.0 is required。原因:只装了运行库,没装生成工具,或生成工具里没勾选 C++ 组件。解决:装完整生成工具并勾选对应组件,重开命令行再装。别在这个报错上反复重装 Python,方向错了。
5.2 数据转换后策略收益异常
现象:流程能跑完,但净值曲线明显不合理。原因:csv 缺factor或change字段,或价格用了未复权数据。解决:补齐字段,价格统一用复权价,转换后抽查几只股票的 bin 数据是否和原始 csv 对得上。
5.3 因子或标签出现大面积空值
现象:模型训练报样本不足,或 IC 计算异常。原因:日期区间和交易日历不匹配,或标签表达式窗口超出数据末尾。解决:确认数据起止日期覆盖标签所需的前后窗口,标签窗口越长,末尾要预留的交易日越多。
5.4 回测结果好得不真实
现象:样本外净值一路向上,回撤极小。原因:预处理用了全区间统计、标签方向写反、或股票池混入不可交易标的。解决:预处理窗口严格限定训练段,标签方向用单只股票手工验算,股票池剔除低流动性和权证类标的。
5.5 换模型后结果对不齐
现象:自定义模型接入后回测报索引或形状错误。原因:predict返回的索引和数据集样本索引不一致。解决:输出前按数据集索引重建结果,先用小样本验证接口,再跑全量。
6. 验收与答辩:怎么证明这套方案真的跑通了
验收不看代码行数,看三样东西:链路可复现、指标可解释、边界说清楚。我一般会准备一张验收表,把每一步的输入、输出和检查点列出来,答辩时按表讲,比临场回忆稳得多。
| 环节 | 检查点 | 合格标准 |
|---|---|---|
| 环境 | 安装无报错,能导入核心模块 | 导入成功且版本可查 |
| 数据 | csv 转 bin 后字段完整 | 抽查个股数据与原始一致 |
| 因子 | 特征和标签无大面积空值 | 空值比例在可接受范围 |
| 模型 | 训练收敛,样本外有预测 | IC 和 Rank IC 方向稳定 |
| 回测 | 净值、超额、回撤、换手可读 | 指标齐全且能解释来源 |
答辩时最容易被追问的是“你的结果可信吗”。回答思路不是强调收益多高,而是说明:训练和测试时间段怎么切的、预处理有没有用未来数据、股票池怎么筛的、交易假设是什么。把这四点讲清楚,即使收益一般,方案也是成立的。反过来,收益漂亮但说不清这四点,评审一问就露馅。
还有一个具体技巧:提前准备一组基线结果和一组改动后的结果做对照,比如默认参数对比调过学习率或换过预处理。对照能直接说明你的改动带来了什么,也证明你理解每个参数的作用,而不是碰巧跑出一个好看的数字。
血泪经验是,我第一次做这类方案时把预处理窗口设成了全区间,样本外指标虚高,答辩被问到统计窗口当场卡住。从那以后我每次跑回测前都强制走一遍检查清单:标签方向、预处理窗口、股票池、交易假设,四项逐条打勾才允许出图。希望帮到你。
本文还有配套的精品资源,点击获取