一、概述:
QLib 量化框架 将每个股票的特征(开盘价、收盘价、成交量等)单独存储为一个二进制文件(.bin)。
通过使用 QLib 提供的 Script ,可以将 .CSV 格式的文本文件,转换成 .bin ,Script 用 Python写成。
如果要使用其它语言读取或追加,需要搞明白其格式,然后,采用适当的方式处理。下面记录试验过程及结果。
二、获取数据、写入文件
官方文档《Data Layer: Data Framework & Usage》:Data Layer: Data Framework & Usage — QLib 0.8.5.99 documentation
介绍了数据(Qlib Format Data)准备的方式:
1)用 scripts/get_data.py 从 yahoo 获取,其实 是获取一个已经打包的 Zip 文件,然后 解压到 目标文件夹。
2)用 转换 CSV Format 成 Qlib Format ,使用 scripts/dump_bin.py 示例如下:
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
使用了 dump_bin.py 的 dump_all 参数,查源码,对应 DumpDataAll 类( class), 它继续于:DumpDataBase :
if __name__ == "__main__":
fire.Fire({"dump_all": DumpDataAll, "dump_fix": DumpDataFix, "dump_update": DumpDataUpdate})
dump_bin.py 提供三个类(DumpDataAll、DumpDataFix、DumpDataUpdate),分别用于:初次全部导入、数据修复、数据追加更新。 三个类的基础类是:DumpDataBase 。
DumpDataBase 类的:_dump_bin 函数 使用 _data_to_bin 函数,最后向目标文件夹的 .bin文件写入数据(更新或新增)。
源代码如下:
def _data_to_bin(self, df: pd.DataFrame, calendar_list: List[pd.Timestamp], features_dir: Path):
#... 判断 df 与 calendar_list 不为空(省略)
_df = self.data_merge_calendar(df, calendar_list)
# used when creating a bin file
date_index = self.get_datetime_index(_df, calendar_list)
for field in self.get_dump_fields(_df.columns):
bin_path = features_dir.joinpath(f"{field.lower()}.{self.freq}{self.DUMP_FILE_SUFFIX}")
if field not in _df.columns:
continue
if bin_path.exists() and self._mode == self.UPDATE_MODE:
# update 更新, “ab” 模式: 以字节(二进制)方式往文件末尾追加写入数据,“rb” 读取,“wb” 写入,b 即二进制 binary
with bin_path.open("ab") as fp:
np.array(_df[field]).astype("<f").tofile(fp)
else:
# append 追加; self._mode == self.ALL_MODE or not bin_path.exists()
np.hstack([date_index, _df[field]]).astype("<f").tofile(str(bin_path.resolve()))
Qlib 使用 dump_bin.py 文件进行文件格式转换(CSV ==》.bin ),重点是其 转换后如何保存数据,
文件引用了下列包:import numpy as np , import pandas as pd
完成写文件,实际用了两个 numpy模块 的函数:tofile( file ) , 还有 astype("<f") 。
还有 astype("<f") 的作用,将数据转换成:float32 ("<f" 的意思)。
np.dtype('<f') 即 np.dtype('d')
(可以转换几种类型的字符串。 可以在识别的字符串前面加上 '>' (big-endian)、 '<' (little-endian)
或 '=' (hardware-native、默认值),以指定字节顺序。)
ndarray.tofile(fid, sep='', format='%s')
如果 sep 参数 为 “” (empty),写入为二进制格式,等价于: file.write(arr.tobytes())
当 fid 是一个文件对象(file object), 数组内容 直接写入文件 file, 跳过 文件对象 (file object)的 write 方法。
ndarray.tobytes(order='C') -》 返回 bytes 对象
将nd 数组的内存内容 转换成 Python bytes。默认是 类C顺序,可取 C 、F 、A,控制其行为。
4) .bin 第一行的意义 (参考Qlib论文 :https://arxiv.org/pdf/2009.11189.pdf )。如下图
![]()
本人曾经使用 ndarray.fromfile(file, dtype = dtype.float32) 读取 特征数据文件(.bin), 比转换的CSV数据多了一行。
按官方解释,第一个4 bytes(float32) 是 当前股票第一个交易日期,在 Clendar.txt 交易日历中的索引值。
三、如何读取数据
1、使用 Python 的 numpy
由于数据是通过 Numpy 的 tofile 函数,以二进制写入,因此,也需要相应的 fromfile 函数读取。
arr = np.fromfile( r"open.day.bin", dtype = np.float32 ) 返回一个 数组。
注意: 使用 np.float32 对应 astype("<f") 32位。它用于确定文件中项目的大小和字节顺序。
读到的第一个数是:0 ,不知道原因。
可以对比QLib 获取某股票OHLC数据的方法。相差第一个数。
from qlib.data import D
instruments = ['SH600000']
fields = ['$close', '$volume', '$open']
D.features(instruments, fields, start_time='2010-01-01', end_time='2017-12-31', freq='day').head()
(另外还有:savetxt() 和 loadtxt() ,save() 和savez() ,输出扩展名npy、npz, load() 读取。 )
2、使用 bitstring 模块的 ConstBitStream 函数
用到 bytepos
3、其它语言: