无噪 logo
  1. qlib 速读指南
  2. 数据初始化与管理

2. 数据初始化与管理

本章将详细介绍 QLib 量化投资平台的数据结构、数据获取与更新方法、初始化配置以及数据存储机制。掌握这些基础知识对于后续的量化策略开发和模型训练至关重要,我们将从实际应用角度出发,带你深入了解 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

中国市场 1 分钟线数据

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 系统自动更新

在 Linux 系统中,可以通过 crontab 设置定时任务来实现数据的自动更新:

  1. 编辑 crontab 配置:
crontab -e
  1. 添加以下内容(每个工作日执行更新):
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 数据

CSV 数据需要满足以下要求:

  • 可以按股票代码命名文件(如 SH600000.csv
  • 或在 CSV 文件中包含股票代码列(需指定列名)
  • 必须包含日期列
  • 至少包含 OHLCV(开盘价、最高价、最低价、收盘价、成交量)等基础字段

转换 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.init()函数参数配置

在使用 QLib 进行任何操作之前,都需要先调用 qlib.init() 函数进行初始化。这个函数的参数配置直接影响 QLib 的行为,理解这些参数对于正确使用 QLib 至关重要。

基本初始化

最基本的初始化只需要指定数据存储路径:

import qlib
qlib.init(provider_uri='~/.qlib/qlib_data/cn_data')

这条命令会初始化 QLib,使用指定路径下的中国市场数据。

核心参数详解

region

指定市场区域,目前支持中国(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)

不同市场区域会影响以下设置:

  • 交易单位(中国市场为 100 股/手,美国市场为 1 股)
  • 涨跌幅限制(中国市场为 10%,美国市场无限制)
  • 交易日历

redis_host 和 redis_port

QLib 使用 Redis 进行缓存和锁机制,这两个参数用于配置 Redis 连接:

qlib.init(
    provider_uri='~/.qlib/qlib_data/cn_data',
    redis_host='127.0.0.1',
    redis_port=6379
)

如果 Redis 连接失败,QLib 会自动降级为不使用缓存,这可能会影响性能但不会导致程序错误。

exp_manager

配置实验管理器,用于跟踪和管理实验结果:

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 库,它可以帮助记录实验参数、指标和结果,方便比较不同实验。

mongo

配置 MongoDB 连接,用于任务管理等高级功能:

qlib.init(
    provider_uri='~/.qlib/qlib_data/cn_data',
    mongo={
        "task_url": "mongodb://localhost:27017/",
        "task_db_name": "qlib_tasks",
    }
)

MongoDB 主要用于支持分布式任务和高级工作流管理,普通用户可以忽略此参数。

logging_level

设置日志级别,控制输出信息的详细程度:

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格式原始数据

这种默认设置对于大多数用户来说已经足够,但在某些情况下,可能需要修改数据存储路径。

自定义数据存储路径

有两种方式可以自定义数据存储路径:

1. 通过 init 函数参数

在调用 qlib.init() 时,通过 provider_uri 参数指定:

qlib.init(provider_uri='/data/qlib/qlib_data/cn_data')

2. 通过环境变量

设置 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/                # 缓存数据
    └── ...

calendars/

存储不同频率的交易日历,文件中每行是一个交易日,格式为 YYYY-MM-DD。

instruments/

存储不同股票池的成分股,每个文件对应一个股票池,文件中每行是一个股票代码。

features/

按股票代码组织的具体行情数据,每个股票一个目录,每个字段一个文件,文件名格式为 字段名.频率.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 还支持其他环境变量来定制系统行为:

QLIB_CACHE

指定缓存目录:

export QLIB_CACHE=/data/qlib/cache

QLIB_LOG

指定日志目录:

export QLIB_LOG=/var/log/qlib

QLIB_EXP

指定实验数据目录:

export QLIB_EXP=/data/qlib/experiments

这些环境变量可以在系统的配置文件(如 .bashrc.zshrc)中设置,以便永久生效。

数据操作实战示例

为了帮助你更好地理解 QLib 的数据管理功能,下面提供几个常见的数据操作示例。

1. 获取交易日历

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)}")

2. 获取股票列表

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}")

3. 加载特征数据

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())

4. 使用表达式构造特征

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())

这种方式可以灵活地构造各种技术指标和特征,为量化策略开发提供了强大的支持。

常见问题与解决方案

在数据初始化和管理过程中,可能会遇到一些常见问题,这里提供解决方案:

1. 数据下载速度慢

解决方案

  • 使用国内镜像源加速下载
  • 手动下载数据并解压到指定目录
  • 检查网络连接,确保网络稳定

2. 初始化时提示数据不存在

解决方案

  • 检查 provider_uri 参数是否正确指向数据目录
  • 确认数据已成功下载并解压
  • 检查数据目录结构是否符合 QLib 要求

3. 缓存导致的数据分析不一致

解决方案

  • 清除缓存目录:rm -rf ~/.qlib/qlib_data/cache/*
  • 加载数据时使用 disk_cache=2 强制更新缓存
  • 在开发新特征时暂时禁用缓存

4. 内存占用过高

解决方案

  • 减少同时加载的股票数量
  • 缩小时间范围
  • 关闭不必要的缓存
  • 增加系统内存或使用更高配置的服务器

总结

本章详细介绍了 QLib 的数据结构、数据获取与更新方法、初始化配置以及数据存储机制。我们从数据格式入手,讲解了 QLib 特有的二进制数据结构及其优势,然后详细介绍了数据下载、更新和自定义导入的方法。接着,我们深入解析了 qlib.init() 函数的核心参数,帮助你根据实际需求进行配置。最后,我们探讨了数据存储路径和环境变量设置,并通过实战示例展示了常见的数据操作。

掌握这些知识将为你的量化研究打下坚实的基础。在后续章节中,我们将基于这些基础知识,进一步学习 QLib 的核心功能,如特征工程、模型训练和策略回测等。记住,数据是量化研究的基石,对数据的深入理解和熟练操作是成为一名优秀量化研究员的必备技能。