Qlib Data Collector 实战指南:数据采集器家族、数据集规范与自定义 Collector 开发
【免费下载链接】qlibQlib is an AI-oriented Quant investment platform that aims to use AI tech to empower Quant Research, from exploring ideas to implementing productions. Qlib supports diverse ML modeling paradigms, including supervised learning, market dynamics modeling, and RL, and is now equipped with https://github.com/microsoft/RD-Agent to automate R&D process.项目地址: https://gitcode.com/GitHub_Trending/qli/qlib
导读:Qlib 作为 AI 量化平台,其研究与回测都依赖规整、可复现的历史行情数据。本指南以 scripts/data_collector/README.md 为核心,系统讲解 Qlib 数据采集模块(Data Collector)内置的多市场数据源、统一的数据落盘规范、下游组件对数据字段的依赖关系,以及如何按照BaseCollector / BaseNormalize / BaseRun三个基类,在 4 个文件内为任意新数据源扩展一个全新的 Collector。读完本文,你可以掌握 Qlib 行情数据 "采集 → 规范化 → 入库" 的完整闭环,并具备从零编写自定义采集器的工程能力。
一、Data Collector 是什么:Qlib 数据链路的入口
在 Qlib 中,数据是一切机器学习建模(特征工程、训练、回测)的地基。scripts/data_collector/目录下存放着所有数据采集脚本,其职责是:从公开网络数据源抓取原始行情,经过标准化(Normalize)后,再交给dump_bin.py转成 Qlib 二进制格式(bin)供数据层直接读取。换句话说,Collector 解决的是"数据从哪里来、以什么形态进入 Qlib"这一最上游问题。
内置采集器一览
按照 scripts/data_collector/README.md 的 Introduction,当前仓库主要提供以下数据源脚本:
| 目录 | 数据源 | 覆盖标的 |
|---|---|---|
| scripts/data_collector/yahoo | Yahoo Finance | US/CN股票行情(US/CN,另扩展支持印度IN、巴西BR) |
| scripts/data_collector/fund | http://fund.eastmoney.com | 公募基金数据 |
| scripts/data_collector/cn_index | http://www.csindex.com.cn | CN 指数成分,如CSI300/CSI100 |
| scripts/data_collector/us_index | https://en.wikipedia.org/wiki | US 指数成分,如SP500/NASDAQ100/DJIA/SP400 |
| scripts/data_collector/contrib | — | 辅助功能脚本 |
除上述在文档 Introduction 中列出的目录外,仓库中还包含 baostock 5 分钟数据(scripts/data_collector/baostock_5min)、中证指数补充(scripts/data_collector/br_index)、加密货币(scripts/data_collector/crypto)、PIT 点数据(scripts/data_collector/pit)以及期货交易日历(scripts/data_collector/future_calendar_collector.py)等,均遵循同一套基类设计。从实现结构看,这些目录由两个角色组成:行情/标的采集器(collector)与指数成分股/日历生成器(index),前者继承BaseCollector,后者继承IndexBase(见 scripts/data_collector/index.py)。
二、数据集规范:Feature / Calendar / Instruments 三件套
无论数据来自哪个市场,Collector 输出的原始数据最终都要被组织成 Qlib 认可的形态。文档用一张表定义了各数据集共用的 Basic Data 结构:
| 类别 | 内容 |
|---|---|
| Features | Price/Volume行情字段:close/open/low/high/volume/change/factor |
| Calendar | 按频率命名的交易日历文件<freq>.txt:如day.txt(日线)、1min.txt(分钟线) |
| Instruments | 按市场命名的标的池文件<market>.txt:all.txt为必需;csi300.txt/csi500.txt/sp500.txt等按需提供 |
补充约定:
Features必须是**数字(digital)**类型;- 若行情未做复权(adjusted)处理,则
factor = 1; - 输出目录通常以
features / calendars / instruments三个子目录组织(可在dump_bin.py、qlib_data目录结构中印证)。
Data-dependent component:谁依赖哪些数据
为了让 Qlib 各组件正常运行,文档进一步给出了数据依赖清单:
| 组件 | 必需数据 |
|---|---|
数据检索(Data retrieval,即qlib.data.D查询引擎) | Features、Calendar、Instrument |
| 回测(Backtest,含撮合、仓位、账户管理) | Features[Price/Volume]、Calendar、Instruments |
这解释了为什么回测对行情完整性要求严苛:撮合需要open/high/low/close/volume才能计算成交与冲击成本,而日历决定哪些时刻可交易,标的池决定可下单位置。因此,采集阶段的任何缺口(停牌缺行、字段缺失、区间不连续)都会沿数据链路传导到回测结果。
三、自定义数据采集:四个文件接入一个新数据源
scripts/data_collector/README.md 的 Custom Data Collection 一节,给出了把任意新数据源接入 Qlib 的标准骨架(具体实现参考 yahoo 目录)。完整步骤为:
- 在
scripts/data_collector/下创建一个数据集代码目录(如my_source); - 添加
collector.py,其中定义三类类(见下); - 添加
README.md(说明数据源、用法、参数); - 添加
requirements.txt(声明该数据源所需的第三方依赖)。
3.1collector.py的最小骨架
CUR_DIR = Path(__file__).resolve().parent sys.path.append(str(CUR_DIR.parent.parent)) from data_collector.base import BaseCollector, BaseNormalize, BaseRun class UserCollector(BaseCollector): ... # 实现数据抓取 class UserNormalzie(BaseNormalize): ... # 实现数据规范化(原文档中如此拼写,实际命名约定见 3.4) class Run(BaseRun): ... # 注册 CLI 命令入口其中路径拼接sys.path.append(str(CUR_DIR.parent.parent))是为了让子目录能 import 位于 scripts/data_collector/base.py 中的三个抽象基类。
3.2 Collector 侧:继承BaseCollector
BaseCollector(定义于 scripts/data_collector/base.py)负责从数据源逐标的抓取原始行情。子类必须实现三个抽象方法:
| 抽象方法 | 职责 |
|---|---|
get_instrument_list() | 返回待抓取的标的列表(如全市场股票代码),基类会对其sorted(set(...))去重排序 |
normalize_symbol(symbol) | 把数据源代码规范化为 Qlib 惯例格式(例如 Yahoo 的600519.ss→sh600519,见 scripts/data_collector/yahoo/collector.py) |
get_data(symbol, interval, start_datetime, end_datetime) | 真正请求数据源并返回pd.DataFrame,要求包含symbol、date列 |
此外可复写_timezone属性以适配不同市场的时区转换(如 CN 用Asia/Shanghai、US 用America/New_York)。__init__暴露了以下关键参数(默认值可直接参考 scripts/data_collector/base.py):
| 参数 | 含义 | 默认值 |
|---|---|---|
save_dir | 原始数据落盘目录(按symbol.csv一个标的一文件保存) | 必填 |
interval | 频率,取值1d/1min | 1d |
start/end | 起止日期 | 分别默认2000-01-01与"明天" |
max_workers | 并发抓取的标的数;采集时建议设为 1(基类文档明确提示保持 1 以保证数据完整性) | 1 |
max_collector_count | 失败/数据不足标的的重试轮数上限 | 2 |
delay | 每次请求前time.sleep(delay),用于限速 | 0 |
check_data_length | 若大于 0,则每个标的数据行数 ≥ 该值才算完整,否则按max_collector_count次数重新抓取 | None |
limit_nums | 只抓前 N 个标的,用于调试 | None |
底层抓取链路:collector_data()(scripts/data_collector/base.py)按max_collector_count轮次调用_collector(),后者通过joblib.Parallel并行执行_simple_collector()(每轮之间自动sleep);_simple_collector若发现数据行数不足check_data_length,会把该标的缓存进mini_symbol_map等待下一轮补齐;补不齐的最终写入 CSV 并打印警告。save_instrument()(scripts/data_collector/base.py)还做了增量合并:若symbol.csv已存在则先读旧文件再pd.concat,且文件名经由qlib.utils.code_to_fname归一化,便于后续按符号寻址。
3.3 Normalize 侧:继承BaseNormalize
BaseNormalize(scripts/data_collector/base.py)是数据规范化的抽象:它要求子类实现normalize(df) -> df(将原始字段处理成目标字段)与_get_calendar_list()(提供基准交易日历,通常复用交易所有效交易日)。其构造函数接收date_field_name(默认date)与symbol_field_name(默认symbol)两个字段名参数,作为后续所有处理的"列名契约"。
真正执行多文件并行规范化的是Normalize调度器(scripts/data_collector/base.py),其关键行为包括:
- 读取
source_dir/*.csv,通过ProcessPoolExecutor(max_workers=16)并行处理; - 解析 CSV 时对
symbol字段手工固定 dtype 与na_values,避免TRUE、NA这类合法股票代码被 pandas 误判成 bool / NaN; - 过滤尾部的脏行(
format_data在1d频率下剔除无法解析为%Y-%m-%d的最后一行); - 支持
end_date截断(含当日),结果逐文件写入target_dir。
3.4 Run 侧:用BaseRun一键注册 CLI
BaseRun(scripts/data_collector/base.py)是整个 collector 目录的命令层。以 yahoo 为例,执行python collector.py download_data ...时,fire),download_data()内部再按命名约定YahooCollector{REGION}{INTERVAL}通过importlib动态加载对应类并调用其collector_data()。
BaseRun的默认目录约定:source_dir缺省为<collector 目录>/source,normalize_dir缺省为<collector 目录>/normalize。子类只需实现三个只读属性:
collector_class_name:如"YahooCollectorCN1d",与数据源内定义的类名保持一致;normalize_class_name:如"YahooNormalizeCN1d";default_base_dir:默认路径基准(通常为CUR_DIR)。
由此形成统一开发范式:每个数据源 = 1 个 collector 类 + 1 个 normalize 类 + 1 个 Run 命令类 + 3 个配套文件。你可以对照仓库中同类实现(fund、crypto、pit、baostock_5min)来确认这一约定,各目录的collector.py底部都定义了class Run(BaseRun)。
四、端到端实战参考:以 Yahoo 为例的三步数据流水线
尽管 scripts/data_collector/README.md 明确"具体实现参考 yahoo 目录",但它所述的source → normalize → dump_bin三段式在全部数据源中通用。以 scripts/data_collector/yahoo/README.md 为模板,可将流程归纳为:
第 1 步:抓取原始数据(download_data)
# CN 日线:指定区间 python 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每个标的生成一个 CSV,保存 open/high/low/close/adjclose/volume 等原始字段。注意:start为闭区间(含),end为开区间(不含);interval=1min时受 Yahoo Finance API 限制通常只可获取最近一个月数据。
第 2 步:规范化(normalize_data)
python 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规范化主要做两件事:一是用 adjclose 对 high/low/close/open 做复权归一;二是把价格归一化到首个有效交易日 close=1 的基准(YahooNormalize1d 中的处理,可查看 scripts/data_collector/yahoo/collector.py)。当interval == 1min时必须额外提供--qlib_data_1d_dir(1min 复权依赖 1d 数据的 factor/paused 信息)。
第 3 步:转成 Qlib bin(dump_bin)
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 .csvdump_bin.py 会把规范化 CSV 转为 numpy 数组,按"一列一文件、一标的一目录"落盘,同时生成calendars/与instruments/(频率参数映射为1d → day、1min → 1min)。自动化更新则可通过update_data_to_bin命令或 crontab 定时(交易日* * * * 1-5)调用实现增量更新。
若不想从零抓取,也可直接使用
python scripts/get_data.py qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn(见 scripts/get_data.py)下载已打包好的现成 qlib-data。其中version可选v1/v2,仓库 benchmarks 默认基于v1复现;注意官方打包数据为压缩体积做了字段裁剪,无法在其上做增量更新,需要最新数据时仍应使用 Yahoo collector 从零抓取后再增量维护。
五、配套基础设施:日历、复权因子与指数成分(IndexBase)
除基类外,scripts/data_collector/utils.py 提供了大量共享函数,理解它们能帮你更精确地实现自定义 normalize 类:
get_calendar_list(bench_code):获取某基准(CSI300/CSI500/ALL/US_ALL等)的历史交易日列表,模块级缓存避免重复请求;generate_minutes_calendar_from_daily(...):由日线日历按上下午时段(默认 A 股09:30–11:29、13:00–14:59)扩展出分钟级日历;calc_adjusted_price(...):1min 复权核心函数——补paused字段、对齐 1d 时间轴、按volume / factor与open/high/low/close × factor重加权、并计算连续停牌天数paused_num;calc_paused_num(...):逐日统计连续停牌字段(该字段是calc_adjusted_price内部调用的一个方法,用于剔除全天为 NaN 的尾部交易日);deco_retry(retry=5, retry_sleep=3):网络请求重试装饰器,默认为巴西等弱数据源覆盖场景可在子类中覆盖重试次数。
对指数成分股,scripts/data_collector/index.py 定义了IndexBase:通过get_new_companies()(当前成分 + 起始日期)与get_changes()(历史 add/remove 事件)两个抽象方法,parse_instruments()即可生成含symbol/start_date/end_date的csi300.txt类文件(保存于<qlib_dir>/instruments/);save_new_companies()则输出*_only_new.txt。各指数目录(cn_index/collector.py、us_index/collector.py、br_index/collector.py)中的XXXIndex子类分别对接中证官网、Wikipedia 成分页与巴西 B3 数据,共同产出二、三节所描述的instruments/<market>.txt。
六、数据接入后的使用方式
Data Collector 产出的 qlib-data(含features、calendars、instruments的目录)可直接作为qlib.init的provider_uri使用。以采集结果为例:
import qlib from qlib.data import D qlib.init(provider_uri="~/.qlib/qlib_data/cn_data", region="cn") df = D.features(D.instruments("all"), ["$close"], freq="day") # freq 默认 day若你手握的是 CSV 格式而非本模块产出的 bin,也可参考 docs/component/data.rst 中"Converting csv format into qlib format"一节。回测与数据检索两大下游组件对本数据集核心字段的依赖关系,已在第二节的依赖表中说明,这也是 Data Collector 在 qlib/backtest 与 qlib/data 之间扮演的枢纽角色。
七、实践要点与注意事项
- 并发要克制:抓取阶段建议
max_workers=1,且用delay限速,既避免触发数据源反爬,也防止单标的请求错位导致数据不完整; - 用
check_data_length做自校验:例如日线一年约 252 个交易日可设252 // 4,1min 一周约6.5 * 60 * 5(US)或4 * 60 * 5(CN),数据不足会自动重抓,最终仍不足的标的会打印警告清单,便于人工复核; - 字段契约要守:
get_data返回的 DataFrame 必须含symbol与date列,规范化阶段的date_field_name/symbol_field_name要与 CSV 实际列名一致; - 停牌与复权是隐性陷阱:原始源(如 Yahoo)复权序列偶尔异常,规范化阶段依赖 adjclose 与前复权 factor 重算;
factor字段在未复权场景下恒为1; - 数据结构以
all.txt为锚:instruments中all.txt必需,csi300.txt等仅当需要特定股票池回测时生成; - 自定义数据源从复制 yahoo 目录起步:这是文档推荐的参考实现,它完整覆盖了 collector、normalize、index 数据补充、增量更新与 dump 全链路。
综上,Data Collector 以"三个抽象基类 + 一套数据规范"将多市场、多频率、多数据源统一进同一条流水线:原始抓取(BaseCollector)→ 规范化(BaseNormalize/Normalize)→ 指数日历与成分(IndexBase)→ bin 落盘(dump_bin.py)→ 供qlib.data检索与回测使用。理解并扩展这套模块,是你在 Qlib 上构建自定义高质量数据集、复现基准实验或服务生产策略的第一步。
【免费下载链接】qlibQlib is an AI-oriented Quant investment platform that aims to use AI tech to empower Quant Research, from exploring ideas to implementing productions. Qlib supports diverse ML modeling paradigms, including supervised learning, market dynamics modeling, and RL, and is now equipped with https://github.com/microsoft/RD-Agent to automate R&D process.项目地址: https://gitcode.com/GitHub_Trending/qli/qlib
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考