本章将详细介绍 QLib 量化投资平台的数据结构、数据获取与更新方法、初始化配置以及数据存储机制。掌握这些基础知识对于后续的量化策略开发和模型训练至关重要,我们将从实际应用角度出发,带你深入了解 QLib 的数据管理体系。
在量化投资研究中,数据是基础中的基础。QLib 作为一个专业的量化平台,设计了高效的数据结构来存储和管理金融市场数据。理解这些数据结构不仅有助于正确使用 QLib,还能帮助我们更好地处理和分析量化数据。
QLib 采用了自定义的二进制格式(.bin 文件)来存储金融数据,这种格式经过优化,特别适合量化研究中的科学计算需求。与传统的 CSV 格式相比,.bin 格式具有以下优势:
QLib 的二进制文件设计参考了金融数据的特性,每个文件通常对应特定股票的特定字段(如收盘价、成交量等),并按时间顺序存储数据点。
QLib 数据集中包含以下核心字段,这些字段是进行量化分析的基础:
open
:开盘价(经过复权处理)close
:收盘价(经过复权处理)high
:最高价(经过复权处理)low
:最低价(经过复权处理)volume
:成交量(经过复权处理)factor
:复权因子,用于将复权价格还原为原始价格需要特别说明的是,QLib 中的价格数据默认是经过复权处理的。复权处理是量化分析中非常重要的一步,它通过调整历史价格来消除股票分割、分红等因素对价格的影响,使不同时期的价格具有可比性。
如果需要获取原始价格,可以使用复权因子进行计算:
# 计算原始收盘价
original_close = $close / $factor
QLib 中的数据按照以下层次结构进行组织:
flowchart TD
A[根目录]
A --> B[calendars/]
A --> C[instruments/]
A --> D[features/]
B --> B1[day.txt]
B --> B2[1min.txt]
C --> C1[all.txt]
C --> C2[csi300.txt]
C --> C3[...]
D --> D1[SH600000/]
D --> D2[SZ000001/]
D --> D3[...]
D1 --> D1a[open.day.bin]
D1 --> D1b[close.day.bin]
D1 --> D1c[...]
calendars/
:存储不同频率的交易日历instruments/
:存储不同股票池的成分股列表features/
:按股票代码组织的具体行情数据这种层次结构既保证了数据的有序存储,又便于快速定位和访问所需数据。
QLib 提供了灵活的数据获取和更新机制,用户可以根据需要获取不同市场、不同频率的数据,并保持数据的时效性。
QLib 官方提供了预先生成的数据集,用户可以通过 get_data.py
脚本快速下载。目前支持中国市场和美国市场的日线和分钟线数据。
python scripts/get_data.py qlib_data --target_dir ~/.qlib/qlib_data/cn_data --region cn
python scripts/get_data.py qlib_data --target_dir ~/.qlib/qlib_data/qlib_cn_1min --region cn --interval 1min
python scripts/get_data.py qlib_data --target_dir ~/.qlib/qlib_data/us_data --region us
这些命令会将数据下载到指定目录(默认为 ~/.qlib/qlib_data/
),并自动组织成 QLib 所需的目录结构。下载完成后,就可以通过 QLib 的 API 访问这些数据了。
金融数据是不断更新的,QLib 提供了数据自动更新机制,确保用户能够获取最新的市场数据。
在 Linux 系统中,可以通过 crontab
设置定时任务来实现数据的自动更新:
crontab -e
0 18 * * 1-5 python /path/to/qlib/scripts/data_collector/yahoo/collector.py update_data_to_bin --qlib_data_1d_dir ~/.qlib/qlib_data/cn_data
这条命令会在每个工作日的 18:00 自动更新日线数据。
如果需要手动更新特定时间段的数据,可以使用以下命令:
python scripts/data_collector/yahoo/collector.py update_data_to_bin --qlib_data_1d_dir ~/.qlib/qlib_data/cn_data --trading_date 2023-01-01 --end_date 2023-12-31
其中 --trading_date
指定开始日期,--end_date
指定结束日期(不包含)。
除了使用 QLib 提供的数据集,用户还可以导入自己的 CSV 格式数据。QLib 提供了 dump_bin.py
脚本,可以将 CSV 数据转换为 QLib 的二进制格式。
CSV 数据需要满足以下要求:
SH600000.csv
)假设 CSV 数据存放在 ~/.qlib/csv_data/my_data
目录下,可以使用以下命令进行转换:
python scripts/dump_bin.py dump_all --csv_path ~/.qlib/csv_data/my_data --qlib_dir ~/.qlib/qlib_data/my_data --include_fields open,close,high,low,volume,factor
--csv_path
:CSV 数据所在目录--qlib_dir
:转换后的 QLib 格式数据存放目录--include_fields
:需要包含的字段转换完成后,就可以像使用官方数据一样使用自定义数据了。
为确保数据质量,QLib 提供了数据健康检查工具,可以检查数据是否存在缺失、异常波动等问题:
# 检查日线数据
python scripts/check_data_health.py check_data --qlib_dir ~/.qlib/qlib_data/cn_data
# 检查1分钟线数据
python scripts/check_data_health.py check_data --qlib_dir ~/.qlib/qlib_data/cn_data_1min --freq 1min
可以通过参数调整检查阈值:
python scripts/check_data_health.py check_data --qlib_dir ~/.qlib/qlib_data/cn_data --missing_data_num 300 --large_step_threshold_price 20
--missing_data_num
:允许的最大缺失数据量--large_step_threshold_price
:价格最大允许波动阈值--large_step_threshold_volume
:成交量最大允许波动阈值在使用 QLib 进行任何操作之前,都需要先调用 qlib.init()
函数进行初始化。这个函数的参数配置直接影响 QLib 的行为,理解这些参数对于正确使用 QLib 至关重要。
最基本的初始化只需要指定数据存储路径:
import qlib
qlib.init(provider_uri='~/.qlib/qlib_data/cn_data')
这条命令会初始化 QLib,使用指定路径下的中国市场数据。
指定市场区域,目前支持中国(REG_CN)和美国(REG_US)市场:
from qlib.constant import REG_CN, REG_US
# 中国市场
qlib.init(provider_uri='~/.qlib/qlib_data/cn_data', region=REG_CN)
# 美国市场
qlib.init(provider_uri='~/.qlib/qlib_data/us_data', region=REG_US)
不同市场区域会影响以下设置:
QLib 使用 Redis 进行缓存和锁机制,这两个参数用于配置 Redis 连接:
qlib.init(
provider_uri='~/.qlib/qlib_data/cn_data',
redis_host='127.0.0.1',
redis_port=6379
)
如果 Redis 连接失败,QLib 会自动降级为不使用缓存,这可能会影响性能但不会导致程序错误。
配置实验管理器,用于跟踪和管理实验结果:
qlib.init(
provider_uri='~/.qlib/qlib_data/cn_data',
exp_manager={
"class": "MLflowExpManager",
"module_path": "qlib.workflow.expm",
"kwargs": {
"uri": "mlruns",
"default_exp_name": "MyExperiment",
}
}
)
这需要安装 MLflow 库,它可以帮助记录实验参数、指标和结果,方便比较不同实验。
配置 MongoDB 连接,用于任务管理等高级功能:
qlib.init(
provider_uri='~/.qlib/qlib_data/cn_data',
mongo={
"task_url": "mongodb://localhost:27017/",
"task_db_name": "qlib_tasks",
}
)
MongoDB 主要用于支持分布式任务和高级工作流管理,普通用户可以忽略此参数。
设置日志级别,控制输出信息的详细程度:
import logging
qlib.init(
provider_uri='~/.qlib/qlib_data/cn_data',
logging_level=logging.INFO
)
常用的日志级别有 DEBUG、INFO、WARNING、ERROR,级别从低到高,级别越低输出信息越详细。
初始化完成后,可以通过以下方式验证是否成功:
import qlib
from qlib.data import D
qlib.init(provider_uri='~/.qlib/qlib_data/cn_data')
# 获取交易日历
calendar = D.calendar()
print(f"交易日历长度: {len(calendar)}")
print(f"最近5个交易日: {calendar[-5:]}")
# 获取股票列表
instruments = D.instruments(market='csi300')
stock_list = D.list_instruments(instruments=instruments, as_list=True)
print(f"CSI300成分股数量: {len(stock_list)}")
print(f"部分成分股: {stock_list[:5]}")
如果能够成功输出交易日历和股票列表,说明初始化成功。
QLib 的数据存储路径和环境变量设置直接影响数据的访问效率和系统的灵活性。合理配置这些参数可以提高工作效率,并避免潜在的问题。
QLib 默认将数据存储在用户主目录下的 .qlib
文件夹中:
~/.qlib/
├── qlib_data/
│ ├── cn_data/ # 中国市场数据
│ ├── us_data/ # 美国市场数据
│ └── my_data/ # 自定义数据
└── csv_data/ # CSV格式原始数据
这种默认设置对于大多数用户来说已经足够,但在某些情况下,可能需要修改数据存储路径。
有两种方式可以自定义数据存储路径:
在调用 qlib.init()
时,通过 provider_uri
参数指定:
qlib.init(provider_uri='/data/qlib/qlib_data/cn_data')
设置 QLIB_DATA
环境变量:
# Linux/MacOS
export QLIB_DATA=/data/qlib/qlib_data
# Windows (PowerShell)
$env:QLIB_DATA = "D:\data\qlib\qlib_data"
设置环境变量后,调用 qlib.init()
时可以不指定 provider_uri
:
qlib.init() # 自动使用环境变量QLIB_DATA指定的路径
QLib 的数据目录结构经过精心设计,理解这些结构有助于更好地管理和使用数据:
qlib_data/
├── calendars/ # 交易日历
│ ├── day.txt # 日线交易日历
│ └── 1min.txt # 1分钟线交易日历
├── instruments/ # 股票池定义
│ ├── all.txt # 所有股票
│ ├── csi300.txt # CSI300成分股
│ ├── csi500.txt # CSI500成分股
│ └── ...
├── features/ # 行情数据
│ ├── SH600000/ # 股票代码
│ │ ├── open.day.bin # 日线开盘价
│ │ ├── close.day.bin # 日线收盘价
│ │ ├── high.day.bin # 日线最高价
│ │ ├── low.day.bin # 日线最低价
│ │ ├── volume.day.bin # 日线成交量
│ │ └── ...
│ ├── SZ000001/
│ └── ...
└── cache/ # 缓存数据
└── ...
存储不同频率的交易日历,文件中每行是一个交易日,格式为 YYYY-MM-DD。
存储不同股票池的成分股,每个文件对应一个股票池,文件中每行是一个股票代码。
按股票代码组织的具体行情数据,每个股票一个目录,每个字段一个文件,文件名格式为 字段名.频率.bin
。
QLib 使用缓存机制来提高数据访问效率,缓存文件存储在 qlib_data/cache/
目录下。缓存机制包括:
QLib 会将频繁访问的日历、股票列表和特征数据缓存在内存中,以加快访问速度。
对于计算成本较高的特征表达式(如移动平均),QLib 会将计算结果缓存到磁盘,避免重复计算。
可以通过以下方式控制缓存行为:
# 加载特征时禁用磁盘缓存
D.features(instruments, fields, disk_cache=0)
# 加载特征时使用磁盘缓存,如果不存在则生成
D.features(instruments, fields, disk_cache=1)
# 强制更新磁盘缓存
D.features(instruments, fields, disk_cache=2)
合理使用缓存可以显著提高数据访问速度,特别是在重复运行相同实验时。
除了 QLIB_DATA
,QLib 还支持其他环境变量来定制系统行为:
指定缓存目录:
export QLIB_CACHE=/data/qlib/cache
指定日志目录:
export QLIB_LOG=/var/log/qlib
指定实验数据目录:
export QLIB_EXP=/data/qlib/experiments
这些环境变量可以在系统的配置文件(如 .bashrc
、.zshrc
)中设置,以便永久生效。
为了帮助你更好地理解 QLib 的数据管理功能,下面提供几个常见的数据操作示例。
from qlib.data import D
# 获取默认时间段的日线日历
calendar = D.calendar()
print(f"总交易日数: {len(calendar)}")
print(f"日期范围: {calendar[0]} 至 {calendar[-1]}")
# 获取指定时间段的日历
custom_calendar = D.calendar(start_time='2020-01-01', end_time='2020-12-31')
print(f"2020年交易日数: {len(custom_calendar)}")
from qlib.data import D
from qlib.data.filter import NameDFilter
# 获取所有股票
all_instruments = D.instruments(market='all')
all_stocks = D.list_instruments(instruments=all_instruments, as_list=True)
print(f"所有股票数量: {len(all_stocks)}")
# 获取CSI300成分股
csi300_instruments = D.instruments(market='csi300')
csi300_stocks = D.list_instruments(instruments=csi300_instruments, as_list=True)
print(f"CSI300成分股数量: {len(csi300_stocks)}")
# 按股票代码筛选
name_filter = NameDFilter(name_rule_re='SH[0-9]{4}55') # 筛选代码以SH开头且后四位为数字,第五位为5的股票
filtered_instruments = D.instruments(market='csi300', filter_pipe=[name_filter])
filtered_stocks = D.list_instruments(instruments=filtered_instruments, as_list=True)
print(f"筛选后的股票: {filtered_stocks}")
from qlib.data import D
# 定义股票列表和特征
instruments = ['SH600000', 'SH600036', 'SH601318']
fields = [
'$close', # 收盘价
'$volume', # 成交量
'Ref($close, 1)', # 前一日收盘价
'Mean($close, 5)', # 5日平均收盘价
'$high - $low' # 当日振幅
]
# 加载特征数据
features = D.features(
instruments=instruments,
fields=fields,
start_time='2020-01-01',
end_time='2020-12-31',
freq='day'
)
print(f"特征数据形状: {features.shape}")
print(features.head())
QLib 支持使用表达式构造复杂特征,而不仅限于直接引用已有字段:
from qlib.data import D
from qlib.data.ops import Feature, ExpressionOps
# 使用表达式构造特征
f1 = Feature('high') / Feature('close') # 最高价/收盘价
f2 = Feature('open') / Feature('close') # 开盘价/收盘价
f3 = f1 + f2 # (最高价+开盘价)/收盘价
f4 = f3 * f3 / f3 # 简化为f3
# 加载自定义特征
data = D.features(["SH600519"], [f4], start_time="2020-01-01", end_time="2020-01-10")
print(data.head())
这种方式可以灵活地构造各种技术指标和特征,为量化策略开发提供了强大的支持。
在数据初始化和管理过程中,可能会遇到一些常见问题,这里提供解决方案:
解决方案:
解决方案:
provider_uri
参数是否正确指向数据目录解决方案:
rm -rf ~/.qlib/qlib_data/cache/*
disk_cache=2
强制更新缓存解决方案:
本章详细介绍了 QLib 的数据结构、数据获取与更新方法、初始化配置以及数据存储机制。我们从数据格式入手,讲解了 QLib 特有的二进制数据结构及其优势,然后详细介绍了数据下载、更新和自定义导入的方法。接着,我们深入解析了 qlib.init()
函数的核心参数,帮助你根据实际需求进行配置。最后,我们探讨了数据存储路径和环境变量设置,并通过实战示例展示了常见的数据操作。
掌握这些知识将为你的量化研究打下坚实的基础。在后续章节中,我们将基于这些基础知识,进一步学习 QLib 的核心功能,如特征工程、模型训练和策略回测等。记住,数据是量化研究的基石,对数据的深入理解和熟练操作是成为一名优秀量化研究员的必备技能。