2. Qlib基础回顾
在进入滚动训练与模型更新的实战之前,有必要把 Qlib 的整体骨架重新梳理一遍。滚动训练并不是一个孤立功能,它建立在 Qlib 的数据组织方式、工作流抽象和配置驱动机制之上。只有理解了这些基础,后续才能准确判断“哪些环节需要滚动、哪些状态需要继承、哪些参数需要随窗口变化”。本节从架构、数据层、工作流、配置文件和常用模块五个角度回顾,并给出一个可直接运行的快速上手示例。
一、核心原理:Qlib 的分层架构
Qlib 的设计哲学是“数据与流程解耦、配置驱动执行”。从下到上大致可分为四层:
- 数据层(Data Layer):负责原始行情数据的采集、清洗、存储与表达式计算,核心是
DataHandler与表达式引擎。 - 工作流层(Workflow Layer):以
qrun和Workflow为核心,把数据、模型、训练、回测串成可复现的流水线。 - 模型层(Model Layer):提供
Model基类及 LightGBM、LSTM、Transformer 等实现,统一fit/predict接口。 - 策略与回测层(Strategy & Backtest):包含
Strategy、Executor、Backtest,负责信号到持仓的转换与绩效评估。
这种分层带来的直接好处是:滚动训练时,我们只需替换数据切分逻辑和模型更新策略,而无需重写回测与评估代码。
二、数据层:Qlib 的“数据即表达式”
Qlib 数据层最鲜明的特点是表达式驱动。用户不需要预先计算所有因子,而是用类似 Ref($close, 1)/$close - 1 的表达式描述特征,由引擎在读取时计算。核心组件包括:
Calendar:交易日历,决定时间轴。Instrument:股票池,如csi300、csi500。Feature:原始字段与表达式特征。DataHandler:把上述内容组装成模型可用的DataFrame,并处理缺失值、标准化。
表达式引擎是 Qlib 高效的关键:它支持缓存与增量计算,滚动训练时若窗口重叠,可显著减少重复计算开销。
三、工作流与配置文件:qrun 的驱动方式
Qlib 推荐用 YAML 配置文件描述整个实验,再用 qrun 执行。一个典型配置包含 qlib_init、market、benchmark、data_handler_config、task 等段落。下面是一个最小可运行示例:
qlib_init:
provider_uri: "~/.qlib/qlib_data/cn_data"
region: cn
market: &market csi300
benchmark: &benchmark SH000300
data_handler_config: &data_handler_config
start_time: 2018-01-01
end_time: 2020-08-01
fit_start_time: 2018-01-01
fit_end_time: 2019-12-31
instruments: *market
task:
model:
class: LGBModel
module_path: qlib.contrib.model.gbdt
kwargs:
loss: mse
learning_rate: 0.05
dataset:
class: DatasetH
module_path: qlib.data.dataset
kwargs:
handler:
class: Alpha158
module_path: qlib.contrib.data.handler
kwargs: *data_handler_config
segments:
train: [2018-01-01, 2019-12-31]
valid: [2020-01-01, 2020-06-30]
test: [2020-07-01, 2020-08-01]
record:
- class: SignalRecord
module_path: qlib.workflow.record_temp
执行命令非常简洁:
qrun workflow_config_lightgbm.yaml
运行后 Qlib 会在 mlruns 目录下生成实验记录,包含模型、预测信号和回测结果。理解这份配置的结构,是后续改造为滚动训练配置的前提。
四、常用模块速查
| 模块 | 典型类/函数 | 作用 |
|---|---|---|
| 数据 | Alpha158 / Alpha360 | 内置因子集,快速构建特征 |
| 数据集 | DatasetH | 按时间段切分 train/valid/test |
| 模型 | LGBModel / LSTM | 统一 fit/predict 接口 |
| 工作流 | qrun / Workflow | 配置驱动执行与记录 |
| 回测 | TopkDropoutStrategy | 按预测分数选股并调仓 |
| 记录 | SignalRecord / PortAnaRecord | 保存信号与绩效分析 |
五、快速上手示例与常见误区
若不想用 YAML,也可以用 Python API 快速跑通:
import qlib
from qlib.contrib.data.handler import Alpha158
from qlib.contrib.model.gbdt import LGBModel
from qlib.data.dataset import DatasetH
qlib.init(provider_uri="~/.qlib/qlib_data/cn_data", region="cn")
handler = Alpha158(instruments="csi300",
start_time="2018-01-01", end_time="2020-08-01",
fit_start_time="2018-01-01", fit_end_time="2019-12-31")
dataset = DatasetH(handler, segments={
"train": ("2018-01-01", "2019-12-31"),
"valid": ("2020-01-01", "2020-06-30"),
"test": ("2020-07-01", "2020-08-01"),
})
model = LGBModel(loss="mse", learning_rate=0.05)
model.fit(dataset)
pred = model.predict(dataset)
print(pred.head())
常见误区一:把
fit_start_time 与 train 段混为一谈。前者用于特征标准化统计,后者用于模型训练,二者时间范围可以不同,滚动训练时必须分别管理。误区二:忽略 qlib.init 的 provider_uri,导致数据路径错误却报出难以定位的异常。误区三:直接修改 test 段做“滚动”,实际上破坏了样本外评估的严谨性。复盘来看,Qlib 的基础可以浓缩为一句话:用表达式描述数据,用配置描述流程,用记录保证可复现。滚动训练要做的,正是在这套稳定骨架上,把“一次性切分”替换为“按时间窗口反复切分与更新”。理解了本节内容,后续改造配置、继承模型状态、管理多窗口实验时,就能做到心中有数、改动有据。