功能
数据存储与数据库
在文件、DuckDB、SQL 数据库和 ArcticDB 中保存和查询市场数据
下载后的市场数据应放在哪里,又如何只读取需要的部分?VBT 可将任意数据对象保存到 CSV、HDF5、Feather、Parquet、DuckDB、SQL 数据库或 ArcticDB,再读回可用于研究的数据对象。在 Python 中存储市场数据,并为下一次回测选择所需日期和标的。
data = vbt.GBMOHLCData.pull(
["AAA", "BBB", "CCC"],
start="2024-01-01",
end="2024-01-29",
timeframe="1min",
std=0.0005,
seed=42,
)
data.loc[:"2024-01-21 23:59"].to_duckdb(connection="market.duckdb")
data.loc["2024-01-22":].to_duckdb(
connection="market.duckdb",
if_exists="append",
)
vbt.DuckDBData.list_tables(connection="market.duckdb")['AAA', 'BBB', 'CCC']week = vbt.DuckDBData.pull(
["AAA", "BBB", "CCC"],
start="2024-01-15",
end="2024-01-22",
tz="UTC",
connection="market.duckdb",
)
week.close.shape(10080, 3)week.close.head(3).round(2)symbol AAA BBB CCC
2024-01-15 00:00:00+00:00 67.01 176.99 60.39
2024-01-15 00:01:00+00:00 66.99 176.51 60.20
2024-01-15 00:02:00+00:00 67.18 175.62 60.15每个标的成为一张表,追加操作延长历史,查询则仅返回请求的一周数据,作为普通数据对象,可直接用于指标和回测。
选择存储格式
根据采集和复用数据的方式选择:
| 您的需求 | 从哪里开始 |
|---|---|
| 可检查并与其他工具交换的文件 | CSV |
| 在一个文件中存储多个标的数据集,并在之后追加 | HDF5 |
| 保存 DataFrame,用 Python 和 Arrow 工具重新加载 | Feather |
| 一次写入、反复查询的压缩归档 | Parquet,适合时按日期分区 |
| 对本地表或已有 Parquet 文件执行 SQL 分析 | DuckDB |
| 数据已存于 PostgreSQL、MySQL 或 SQLite | 通过 vbt.SQLData 使用 SQLAlchemy |
| 在本地或对象存储中保存有版本的 DataFrame | ArcticDB |
可以同时使用多种格式。保留 Parquet 归档,用 DuckDB 查询子集,再将结果传入回测。下面示例展示存储和读取。
文件
每个数据对象都有 to_csv、to_hdf、to_feather 和 to_parquet,对应的
vbt.CSVData、vbt.HDFData、vbt.FeatherData 和 vbt.ParquetData 类负责读回文件。同样四周的分钟 K
线,根据格式不同,占用空间差别很大:
import os
data.to_csv("csv")
data.to_hdf("data.h5")
data.to_parquet("parquet")
data.to_feather("feather")
def size_mb(path):
if os.path.isfile(path):
return os.path.getsize(path) / 1e6
return sum(
os.path.getsize(os.path.join(d, f))
for d, _, files in os.walk(path)
for f in files
) / 1e6
paths = ["csv", "data.h5", "parquet", "feather", "market.duckdb"]
pd.Series({path: round(size_mb(path), 1) for path in paths})csv 12.0
data.h5 5.2
parquet 5.9
feather 4.8
market.duckdb 5.8
dtype: float64CSV 几乎处处可读,但体积最大、解析最慢。HDF5 将多个标的保存在同一文件。Parquet 采用压缩列式存储,多数数据工具可读取,并能按标的或日期分区。读取文件夹会发现其中的文件,按文件名匹配标的。CSV 和 HDF 读取器可分块处理,仅保留需要的行。Parquet 筛选器可选择日期或其他值,如下方分区数据集示例所示。
使用独立文件时,每个文件被视为一个标的。分区 Parquet 目录则可为同一标的保留多个日期分区。对于已有的每日文件集合,可用 Pandas 合并并使用
vbt.Data.from_data,也可通过 DuckDB 查询。
数据库
vbt.DuckDBData 在 DuckDB 中存储和查询数据。DuckDB 是运行于进程内的嵌入式分析数据库,也能直接查询 Parquet 和 CSV 文件。vbt.SQLData 支持
SQLAlchemy 能连接的任意数据库,例如 PostgreSQL、MySQL、SQLite;vbt.ArcticDBData 则利用 ArcticDB 存储大型版本化时间序列。DuckDB 和
SQLData 接受自定义 SQL 查询,并能列出模式、表和视图。ArcticDBData 列出库与标的,并通过 ArcticDB 自身 API 读取。vbt.DuckDBData.pull
默认以只读方式打开数据库,因此多个研究进程可同时读取同一文件。连接可作为对象传入,也可根据 URL 创建。反复执行 SQL 读取和更新时,可复用 SQLAlchemy 引擎及其连接池。
ArcticDBData 可选择已存的 version、日期区间和列。因此即使写入新数据后,在比较研究运行时,仍能重新访问保存的数据集版本。
使用现有数据存储
无需为每个标的单独建表。自定义查询可从共享表选择行、连接其他输入,并为 VBT 重命名列。结果会成为与提供商下载相同类型的数据对象。
这个小示例创建一个包含两个标的虚构价格的 Parquet 文件,再仅读取最后两天。在您自己的归档中,文件已经存在:
archive_rows = pd.DataFrame(
{
"timestamp": pd.to_datetime(["2024-01-01", "2024-01-02", "2024-01-03"] * 2, utc=True),
"ticker": ["AAA"] * 3 + ["BBB"] * 3,
"price": [100.0, 102.0, 104.0, 50.0, 49.0, 51.0],
}
)
archive_rows.to_parquet("archive.parquet", index=False)
archive_data = vbt.DuckDBData.pull(
["AAA", "BBB"],
query=vbt.key_dict(
{
symbol: f"""
SELECT timestamp, price AS Close
FROM read_parquet('archive.parquet')
WHERE ticker = '{symbol}' AND timestamp >= '2024-01-02'
ORDER BY timestamp
"""
for symbol in ["AAA", "BBB"]
}
),
index_col="timestamp",
)
archive_data.closesymbol AAA BBB
timestamp
2024-01-02 00:00:00+00:00 102.0 49.0
2024-01-03 00:00:00+00:00 104.0 51.0SQL 查询在数据成为 Pandas 对象之前选择行和列。DuckDB 可以在读取时筛选 Parquet 数据,让研究运行仅使用大型归档中的相关切片。SQLData 对 SQL 数据库提供同样的自定义查询入口。如果已有返回 DataFrame 的加载器,市场数据页面也展示了如何将其引入 VBT。
持续更新存储
让研究数据自动保持最新。数据保存器结合 update
和保存:按计划拉取新增数据并追加到存储,可停止并恢复而不丢失进度,如下方数据保存器功能介绍所示。研究过程中,数据缓存将每次下载保存在本地,使重新运行 notebook
时读取缓存而非提供商,如数据缓存功能介绍所示。
CSV、HDF5、SQL、DuckDB 和 ArcticDB 都有保存器,并支持多个标的。使用与存储匹配的保存器,例如 vbt.DuckDBDataSaver 或
vbt.SQLDataSaver,并传入知道如何获取更新的提供商数据对象。数据流水线页面介绍增量更新与调度。
保存研究会话
如需将数据与 VBT 设置和获取参数一同保留,可用 data.save 保存整个对象,再通过数据类的 load 方法恢复。这适合在另一会话中继续使用同一提供商对象。Parquet
等表格导出则适合与其他工具共享底层数据。配置与持久化介绍 VBT 对象的保存和恢复。
✅ 所有数据类现在都支持数据缓存,让您从(远程)数据源拉取时将数据缓存在磁盘上。缓存使用高效键值存储 LMDB。缓存键根据类、标的和其他获取参数的哈希生成,确保不同拉取分别缓存。
data = vbt.TVData.pull(
"AAPL",
exchange="NASDAQ",
timeframe="1 minute",
tz="America/New_York",
cache=True
)✅ ArcticDB 是为 Python 数据科学生态设计的无服务器 DataFrame 数据库引擎。它依托通用对象存储(兼容 S3 的存储及 Azure Blob Storage),大规模存储、读取和处理 Series 与 DataFrame。除运行中的 Python 环境和对象存储访问权限外,ArcticDB 无需额外基础设施,数秒即可安装。
data = vbt.TVData.pull(
"AAPL",
exchange="NASDAQ",
timeframe="1 minute",
tz="America/New_York"
)
data.to_arcticdb()
day_data = vbt.ArcticDBData.pull(
"AAPL",
start="2026-02-27 09:30:00",
end="2026-02-27 16:00:00",
tz="America/New_York",
)
day_data.get() Open High Low Close Volume
datetime
2026-02-27 09:30:00-05:00 272.90 272.90 269.80 269.960 49256.0
2026-02-27 09:31:00-05:00 269.97 270.12 269.19 269.230 43715.0
2026-02-27 09:32:00-05:00 269.18 270.05 269.18 269.890 33913.0
2026-02-27 09:33:00-05:00 269.85 270.01 269.60 269.770 27569.0
2026-02-27 09:34:00-05:00 269.74 269.98 269.40 269.500 22963.0
... ... ... ... ... ...
2026-02-27 15:55:00-05:00 264.41 264.51 263.15 263.490 162153.0
2026-02-27 15:56:00-05:00 263.51 263.78 263.23 263.670 114741.0
2026-02-27 15:57:00-05:00 263.67 263.78 262.89 263.655 113641.0
2026-02-27 15:58:00-05:00 263.61 263.92 263.25 263.620 158462.0
2026-02-27 15:59:00-05:00 263.68 264.28 263.65 264.200 107619.0
[390 rows x 5 columns]✅ 借助 DuckDB,现在可以直接对数据实例运行 SQL 查询。
data = vbt.TVData.pull(
"AAPL",
exchange="NASDAQ",
timeframe="1 minute",
tz="America/New_York"
)
data.sql("""
SELECT datetime, AVG(Close) OVER(
ORDER BY "datetime" ASC
RANGE BETWEEN INTERVAL 14 DAYS PRECEDING AND CURRENT ROW
) AS "Moving Average"
FROM "AAPL";
""")datetime
2023-09-11 09:30:00-04:00 180.080000
2023-09-11 09:31:00-04:00 179.965000
2023-09-11 09:32:00-04:00 180.000000
2023-09-11 09:33:00-04:00 180.022500
2023-09-11 09:34:00-04:00 179.984000
...
2023-10-20 15:55:00-04:00 177.786669
2023-10-20 15:56:00-04:00 177.785492
2023-10-20 15:57:00-04:00 177.784322
2023-10-20 15:58:00-04:00 177.783166
2023-10-20 15:59:00-04:00 177.781986
Name: Moving Average, Length: 11700, dtype: float64✅ DuckDB 是高性能分析数据库系统,提供功能完善的 SQL 方言来操作各种数据存储。即使数据无法装入内存,也能对本地数据运行分析查询,无需分布式框架;还可以直接查询 CSV、Parquet 和 JSON 文件。
data = vbt.TVData.pull(
"AAPL",
exchange="NASDAQ",
timeframe="1 minute",
tz="America/New_York"
)
URL = "database.duckdb"
data.to_duckdb(connection=URL)
day_data = vbt.DuckDBData.pull(
"AAPL",
start="2023-10-02 09:30:00",
end="2023-10-02 16:00:00",
tz="America/New_York",
connection=URL
)
day_data.get() Open High Low Close Volume
datetime
2023-10-02 09:30:00-04:00 171.260 171.34 170.93 171.10 61654.0
2023-10-02 09:31:00-04:00 171.130 172.37 171.13 172.30 53481.0
2023-10-02 09:32:00-04:00 172.310 172.64 172.16 172.64 44750.0
2023-10-02 09:33:00-04:00 172.640 172.97 172.54 172.78 53195.0
2023-10-02 09:34:00-04:00 172.780 173.07 172.75 173.00 47416.0
... ... ... ... ... ...
2023-10-02 15:55:00-04:00 173.300 173.51 173.26 173.51 61619.0
2023-10-02 15:56:00-04:00 173.525 173.59 173.42 173.43 45066.0
2023-10-02 15:57:00-04:00 173.430 173.55 173.42 173.50 45220.0
2023-10-02 15:58:00-04:00 173.510 173.60 173.46 173.56 47371.0
2023-10-02 15:59:00-04:00 173.560 173.78 173.56 173.75 161253.0
[390 rows x 5 columns]✅ SQLAlchemy 提供标准接口,让开发者编写不依赖具体数据库的代码,与众多 SQL 数据库引擎通信。借助它,您现在可以轻松将数据存入 SQL 数据库,也能从中读取。
data = vbt.TVData.pull(
"AAPL",
exchange="NASDAQ",
timeframe="1 minute",
tz="America/New_York"
)
URL = "postgresql://postgres:postgres@localhost:5432"
data.to_sql(engine=URL)
day_data = vbt.SQLData.pull(
"AAPL",
start="2023-10-02 09:30:00",
end="2023-10-02 16:00:00",
tz="America/New_York",
engine=URL
)
day_data.get() Open High Low Close Volume
datetime
2023-10-02 09:30:00-04:00 171.260 171.34 170.93 171.10 61654.0
2023-10-02 09:31:00-04:00 171.130 172.37 171.13 172.30 53481.0
2023-10-02 09:32:00-04:00 172.310 172.64 172.16 172.64 44750.0
2023-10-02 09:33:00-04:00 172.640 172.97 172.54 172.78 53195.0
2023-10-02 09:34:00-04:00 172.780 173.07 172.75 173.00 47416.0
... ... ... ... ... ...
2023-10-02 15:55:00-04:00 173.300 173.51 173.26 173.51 61619.0
2023-10-02 15:56:00-04:00 173.525 173.59 173.42 173.43 45066.0
2023-10-02 15:57:00-04:00 173.430 173.55 173.42 173.50 45220.0
2023-10-02 15:58:00-04:00 173.510 173.60 173.46 173.56 47371.0
2023-10-02 15:59:00-04:00 173.560 173.78 173.56 173.75 161253.0
[390 rows x 5 columns]✅ 数据可以通过 PyArrow 写入 Feather,也可通过 PyArrow 或 FastParquet 写入 Parquet。Parquet 在一次写入、多次读取的情景下表现尤其出色,具有高效压缩和解压能力,非常适合时间序列存储。
data = vbt.TVData.pull(
"AAPL",
exchange="NASDAQ",
timeframe="1 minute",
tz="America/New_York"
)
data.to_parquet(partition_by="day")
day_data = vbt.ParquetData.pull("AAPL", filters=[("group", "==", "2023-10-02")])
day_data.get() Open High Low Close Volume
datetime
2023-10-02 09:30:00-04:00 171.260 171.34 170.93 171.10 61654.0
2023-10-02 09:31:00-04:00 171.130 172.37 171.13 172.30 53481.0
2023-10-02 09:32:00-04:00 172.310 172.64 172.16 172.64 44750.0
2023-10-02 09:33:00-04:00 172.640 172.97 172.54 172.78 53195.0
2023-10-02 09:34:00-04:00 172.780 173.07 172.75 173.00 47416.0
... ... ... ... ... ...
2023-10-02 15:55:00-04:00 173.300 173.51 173.26 173.51 61619.0
2023-10-02 15:56:00-04:00 173.525 173.59 173.42 173.43 45066.0
2023-10-02 15:57:00-04:00 173.430 173.55 173.42 173.50 45220.0
2023-10-02 15:58:00-04:00 173.510 173.60 173.46 173.56 47371.0
2023-10-02 15:59:00-04:00 173.560 173.78 173.56 173.75 161253.0
[390 rows x 5 columns]✅ 想象一个脚本,可以定期从交易所拉取最新数据并保存到磁盘,全程无需干预。VBT 实现了两个这样的类:一个保存为 CSV,另一个保存为 HDF。
from vectorbtpro import *
import logging
logging.basicConfig(level=logging.INFO)
if __name__ == "__main__":
if vbt.CSVDataSaver.file_exists():
csv_saver = vbt.CSVDataSaver.load()
csv_saver.update()
init_save = False
else:
data = vbt.BinanceData.pull(
"BTCUSDT",
start="10 minutes ago UTC",
timeframe="1 minute"
)
csv_saver = vbt.CSVDataSaver(data)
init_save = True
csv_saver.update_every(1, "minute", init_save=init_save)
csv_saver.save() $ python BTCUSDT_1m_saver.py
2023-02-01 12:26:36.744000+00:00 - 2023-02-01 12:36:00+00:00: : 1it [00:01, 1.22s/it]
INFO:vectorbtpro.data.saver:Saved initial 10 rows from 2023-02-01 12:27:00+00:00 to 2023-02-01 12:36:00+00:00
INFO:vectorbtpro.utils.schedule_:Starting schedule manager with jobs [Every 1 minute do update(save_kwargs=None) (last run: [never], next run: 2023-02-01 13:37:38)]
INFO:vectorbtpro.data.saver:Saved 2 rows from 2023-02-01 12:36:00+00:00 to 2023-02-01 12:37:00+00:00
INFO:vectorbtpro.data.saver:Saved 2 rows from 2023-02-01 12:37:00+00:00 to 2023-02-01 12:38:00+00:00
INFO:vectorbtpro.utils.schedule_:Stopping schedule manager$ python BTCUSDT_1m_saver.py
INFO:vectorbtpro.utils.schedule_:Starting schedule manager with jobs [Every 1 minute do update(save_kwargs=None) (last run: [never], next run: 2023-02-01 13:42:08)]
INFO:vectorbtpro.data.saver:Saved 5 rows from 2023-02-01 12:38:00+00:00 to 2023-02-01 12:42:00+00:00
INFO:vectorbtpro.utils.schedule_:Stopping schedule manager✅ 获取远程数据后,您很可能希望将其保存到磁盘。现在有两种新选择:序列化整个数据类,或将实际数据保存为 CSV 或 HDF5。每个数据集可保存在一个扁平文件中,比数据库更易处理。保存后,可以通过反序列化,或使用专门加载 CSV、HDF5 文件的数据类,轻松重新读取。这些类支持按行和日期时间区间筛选、更新、分块,甚至智能数据集搜索:递归遍历子目录,返回匹配指定 glob 模式或正则表达式的数据集 🧲
btc_data = vbt.BinanceData.pull("BTCUSDT")
eth_data = vbt.BinanceData.pull("ETHUSDT")
btc_data.to_hdf()
eth_data.to_hdf()
data = vbt.BinanceData.from_hdf(start="2020", end="2021")data.closesymbol BTCUSDT ETHUSDT
Open time
2020-01-01 00:00:00+00:00 7200.85 130.77
2020-01-02 00:00:00+00:00 6965.71 127.19
2020-01-03 00:00:00+00:00 7344.96 134.35
2020-01-04 00:00:00+00:00 7354.11 134.20
2020-01-05 00:00:00+00:00 7358.75 135.37
... ... ...
2020-12-27 00:00:00+00:00 26281.66 685.11
2020-12-28 00:00:00+00:00 27079.41 730.41
2020-12-29 00:00:00+00:00 27385.00 732.00
2020-12-30 00:00:00+00:00 28875.54 752.17
2020-12-31 00:00:00+00:00 28923.63 736.42
[366 rows x 2 columns]版权所有 © 2021–2026 Oleg Polakow。保留所有权利。
本站内容与文档供使用和评估 VectorBT PRO 以及教育用途。任何其他用途,包括开发或支持竞争产品或服务,均须事先取得书面同意。