功能

配置与持久化

压缩保存任意研究对象、快速重新加载,并将设置保存在文件中

如何保存研究状态,并使其可复现?VBT 可将任意自身对象,从数据到 10,000 列投资组合,保存为一个可选压缩的文件,再重新加载分析;设置则集中放在配置文件中,而非散落于代码各处。

Save a 10,000-column portfolio with four compression settings and reload it
import time
from itertools import product

data = vbt.YFData.pull("BTC-USD", start="2020-01-01", end="2025-01-01")
pairs = list(product(range(2, 102), range(105, 305, 2)))
fast = vbt.MA.run(data.close, window=[f for f, _ in pairs], short_name="fast")
slow = vbt.MA.run(data.close, window=[s for _, s in pairs], short_name="slow")
entries = fast.ma_crossed_above(slow)
exits = fast.ma_crossed_below(slow)
pf = vbt.PF.from_signals(data, entries, exits, fees=0.001)

rows = {}
for compression in [None, "blosc2", "gzip", "lzma"]:
    start = time.perf_counter()
    path = pf.save("sweep", compression=compression)  
    save_s = time.perf_counter() - start
    start = time.perf_counter()
    loaded = vbt.PF.load(path)
    load_s = time.perf_counter() - start
    rows[str(compression)] = dict(
        file=str(path),
        size=vbt.file_size(path),
        save_s=round(save_s, 2),
        load_s=round(load_s, 2),
    )
pd.DataFrame(rows).T
                       file     size save_s load_s
None           sweep.pickle  11.7 MB   0.01    0.0
blosc2  sweep.pickle.blosc2   2.2 MB   0.06   0.09
gzip      sweep.pickle.gzip   1.9 MB   1.15   0.01
lzma      sweep.pickle.lzma   1.0 MB   1.93   0.06
loaded.wrapper.shape, np.allclose(loaded.total_return, pf.total_return)
((1827, 10000), True)

每个文件重新加载后都是完整投资组合,包含全部 10,000 个策略,可直接计算度量和绘图。在 Apple M3 上,blosc2 将文件缩小至五分之一,保存和加载仍均不到 0.1 秒。lzma 文件最小,但写入约需两秒。

保存与加载

每个 VBT 对象,包括数据、指标、投资组合和切分器,都有 save 和 load;vbt.save 和 vbt.load 可处理任意 Python 对象,例如投资组合字典。只保存对象状态,不保存类,因此文件用当前 VBT 版本加载;加载旧文件时,重命名或移动过的类可映射到新名称。VBT 还提供重建钩子,在类参数变化后加载旧对象。跨机器迁移实验时使用匹配的软件包版本,旧对象有需要时则注册状态转换。

  • 压缩: 支持 zip、gzip、bz2 和 lzma,安装后还支持 lz4、blosc 和 blosc2。
  • 格式: 默认为 pickle,也可用 file_format 选择可读的 .cfg、.yaml 和 .toml 文件,并无损还原为同一对象。
  • 容器: vbt.pdict 是可以像其他 VBT 对象一样保存和加载的字典。
  • 数据更新: vbt.CSVDataSaver、vbt.HDFDataSaver 和 vbt.DuckDBDataSaver 持续更新磁盘数据集,详见数据存储。

将实验内容放在一起

将输入、参数和结果保存到同一字典中,重新打开回测时就能知道它如何产生。对象保留各自形状和标签,因此价格与参数化指标输出可以共存,无须强行塞进同一张表:

Save prices, settings, and a portfolio in one research bundle
import os
import tempfile

close = pd.Series([100.0, 105.0, 103.0], index=pd.date_range("2025-01-01", periods=3))
parameters = dict(fees=0.001, init_cash=1000)
pf = vbt.PF.from_holding(close, **parameters)
research = vbt.pdict(close=close, parameters=parameters, portfolio=pf, version=vbt.__version__)
with tempfile.TemporaryDirectory() as directory:
    path = research.save(os.path.join(directory, "research"), compression="gzip")
    restored = vbt.pdict.load(path)
print(list(restored))
['close', 'parameters', 'portfolio', 'version']
print(restored["parameters"])
{'fees': 0.001, 'init_cash': 1000}
print(restored["close"].equals(close), np.isclose(restored["portfolio"].total_return, pf.total_return))
True True

临时目录使示例可独立运行。若要在会话间保留文件,应使用项目路径。可将指标输出、信号或自己的笔记添加到同一字典,之后加载投资组合绘制新图或计算新度量,无须重跑回测。

重新启动数据更新

保存的研究对象与持续增长的市场数据存储用途不同。重新启动数据保存任务时,加载已有数据,围绕它创建新的 saver,并以 init_save=False 恢复定时更新。这样可以继续保存周期,无须重复写入初始数据集。数据存储介绍存储选项,工作流自动化介绍调度。

设置

vbt.settings 按领域保存整个软件包的默认值,例如 vbt.settings.portfolio["fees"] 或 vbt.settings.plotting["default_theme"]。修改一次后,后续使用该默认值的调用就会采用新值。显式调用参数则可为单次实验覆盖默认值。若要永久保存,可将设置放入工作目录中的 vbt.cfg、vbt.yml 或 vbt.toml,或用 VBT_SETTINGS_PATH 环境变量指定文件。VBT 导入时应用配置,见下方配置文件。工作目录中的 .env 文件也会在导入时加载,使 API 密钥无需写入代码。

可以只保存某个设置部分,例如投资组合默认值,再用 load_update 加载。对该部分调用 reset() 可恢复初始设置。这便于在多个 notebook 中复用项目手续费、初始资金和绘图偏好。

配置化对象与模板

多数 VBT 对象不可变:投资组合、指标或数据实例创建后不再改变。replace 返回修改了部分参数的副本,例如 pf.replace(init_cash=500),原对象保持不变,因此始终可以检查早期结果。replace 根据配置重建对象,不会重新运行策略的订单决策,因此新交易规则应使用新模拟测试。不可变性是约定,并非复制:输入按传入方式保存,因此由 DataFrame 创建对象后再原地修改它,可能使对象与已缓存结果不一致。应复制输入或重新创建对象。

设置和参数通过 vbt.merge_dicts 合并,逐键组合嵌套字典,因此传入参数只覆盖默认值中的对应键。以 vbt.unsetkey 为值可移除默认键;用 vbt.atomic_dict 包装字典则可整体替换。

模板将值的求解推迟到所需信息齐备时。vbt.Rep("name") 替换为当前上下文中的值,vbt.RepEval("expression") 在上下文中计算表达式,vbt.RepFunc(func) 则以该上下文调用函数。投资组合优化页用模板为每个再平衡窗口提供相应收益切片,详见下方模板。

实用示例

会员专享的持久化(英文)和配置(英文)页面收录保存对象与修改设置的简短示例。

配置文件

✅ VBT 扩展常见配置格式(INI、YAML、TOML),形成自己的配置格式,使用户可保存、内省、修改及加载复杂内部对象。其主要优点是可读性和无损往返:任何对象都可编码后再解码,不丢失信息。主要特性包括嵌套结构、引用、字面量解析,以及任意 Python 表达式求值。此外,可为 VBT 创建配置文件并放在工作目录中,每次导入软件包时都用它更新默认设置。

Define global settings in vbt.cfg
[plotting]
default_theme = "dark"

[portfolio]
init_cash = 5000

[data.custom.binance.client_config]
api_key = "<YOUR_API_KEY>"
api_secret = "<YOUR_API_SECRET>"

[data.custom.ccxt.exchanges.binance.exchange_config]
apiKey = &data.custom.binance.client_config.api_key
secret = &data.custom.binance.client_config.api_secret
Verify that the settings have been loaded correctly
from vectorbtpro import *

vbt.settings.portfolio["init_cash"]
5000

压缩

✅ 序列化的 VBT 对象有时会占用大量磁盘空间。此次更新支持多种压缩算法,让文件尽可能轻巧!🪶

Save data without and with compression
data = vbt.RandomOHLCData.pull(
    "RAND",
    start="2022",
    end="2023",
    timeframe="1 minute",
    seed=42
)

file_path = data.save()
print(vbt.file_size(file_path))
21.0 MB
file_path = data.save(compression="blosc")
print(vbt.file_size(file_path))
13.3 MB

更快加载

✅ 若工作流不需要访问器、Plotly 图表或多数其他可选功能,可完全关闭自动导入,将 VBT 加载时间缩短到一秒以内 ⏳

Define importing settings in vbt.cfg
[importing]
auto_import = False
Measure the loading time
start = utc_time()
from vectorbtpro import *
end = utc_time()
end - start
0.580937910079956

序列化

✅ 与机器学习模型一样,每个原生 VBT 对象都可序列化并保存为二进制文件,分享数据与研究见解更加方便!另一个好处是只序列化对象实际内容,不保存类定义,因此加载后的对象始终使用最新类定义。VBT 还实现了专门逻辑,在 API 出现破坏性变更时帮助“重建”对象 🏗️

Backtest each month of data and save the results for later
data = vbt.YFData.pull("BTC-USD", start="2022-01-01", end="2022-06-01")

def backtest_month(close):
    return vbt.PF.from_random_signals(close, n=10, seed=42)

month_pfs = data.close.resample(vbt.offset("M")).apply(backtest_month)
month_pfs
Date
2022-01-01 00:00:00+00:00    Portfolio(\n    wrapper=ArrayWrapper(\n       ...
2022-02-01 00:00:00+00:00    Portfolio(\n    wrapper=ArrayWrapper(\n       ...
2022-03-01 00:00:00+00:00    Portfolio(\n    wrapper=ArrayWrapper(\n       ...
2022-04-01 00:00:00+00:00    Portfolio(\n    wrapper=ArrayWrapper(\n       ...
2022-05-01 00:00:00+00:00    Portfolio(\n    wrapper=ArrayWrapper(\n       ...
Freq: MS, Name: Close, dtype: object
vbt.save(month_pfs, "month_pfs")  

month_pfs = vbt.load("month_pfs")  
month_pfs.apply(lambda pf: pf.total_return)
Date
2022-01-01 00:00:00+00:00   -0.083672
2022-02-01 00:00:00+00:00    0.173909
2022-03-01 00:00:00+00:00   -0.006249
2022-04-01 00:00:00+00:00   -0.057868
2022-05-01 00:00:00+00:00    0.019209
Freq: MS, Name: Close, dtype: float64

模板

✅ 扩展类很容易,但 VBT 以函数为中心,如何增强函数或改变流程?最简单的方式是引入用户提供的小函数(即回调),由主函数在某个时刻调用。然而,主函数需要知道向回调传什么参数,以及如何处理输出。更好的方式是:允许主函数的大多数参数变成回调,再执行这些回调以取得实际值。这些参数称为“模板”,过程称为“替换”。某些参数(如数组)只有在信息齐备后才适合构建,例如其他数组已完成广播,此时模板尤其有用。每个替换时机都有自己的标识符,便于控制何时替换模板。模板在 VBT 中是一等公民,集成到大多数函数中,提供出色的灵活性!🧞

Design a template-enhanced resampling functionality
def resample_apply(index, by, apply_func, *args, template_context={}, **kwargs):
    grouper = index.vbt.get_grouper(by)  
    results = {}
    with vbt.ProgressBar() as pbar:
        for group, group_idxs in grouper:  
            group_index = index[group_idxs]
            context = {"group": group, "group_index": group_index, **template_context}  
            final_apply_func = vbt.substitute_templates(apply_func, context, eval_id="apply_func")  
            final_args = vbt.substitute_templates(args, context, eval_id="args")
            final_kwargs = vbt.substitute_templates(kwargs, context, eval_id="kwargs")
            results[group] = final_apply_func(*final_args, **final_kwargs)
            pbar.update()
    return pd.Series(results)

data = vbt.YFData.pull(["BTC-USD", "ETH-USD"], missing_index="drop")
resample_apply(
    data.index, "Y",
    lambda x, y: x.corr(y),  
    vbt.RepEval("btc_close[group_index]"),  
    vbt.RepEval("eth_close[group_index]"),
    template_context=dict(
        btc_close=data.get("Close", "BTC-USD"),  
        eth_close=data.get("Close", "ETH-USD")
    )
)
分组 7/7
2017    0.808930
2018    0.897112
2019    0.753659
2020    0.940741
2021    0.553255
2022    0.975911
2023    0.974914
Freq: A-DEC, dtype: float64

版权所有 © 2021–2026 Oleg Polakow。保留所有权利。

本站内容与文档供使用和评估 VectorBT PRO 以及教育用途。任何其他用途,包括开发或支持竞争产品或服务,均须事先取得书面同意。