功能

记录与映射数组

将稀疏事件和区间存为记录,再筛选、归约和重新分组

订单、交易、回撤和形态匹配属于事件,而非时间序列:大多数 K 线没有事件,有些则同时有多个。VBT 将这类稀疏事件和区间存储为带列映射的记录,让您无需为每个字段创建稠密数组,就能跨数千列筛选、归约、重新分组和绘图。

Find the order with the worst fill among 20,000 orders in 1,000 columns
close = vbt.GBMOHLCData.pull("S", start="2024-01-01", end="2025-01-01", seed=42).close
np.random.seed(42)
slippage = pd.DataFrame(
    np.random.uniform(0, 0.005, size=(len(close), 1000)),
    index=close.index,
)
pf = vbt.PF.from_random_signals(close, n=10, seed=42, slippage=slippage)  
orders = pf.orders
print(orders.count().sum())
20000
fill_vs_close = orders.price.values / close.values[orders.idx.values] - 1
cost = orders.map_array(  
    np.where(orders.side.values == 0, fill_vs_close, -fill_vs_close)
)
cost.max().describe().round(4)  
count    1000.0000
mean        0.0048
std         0.0002
min         0.0035
25%         0.0047
50%         0.0048
75%         0.0049
max         0.0050
Name: max, dtype: float64
readable = cost.to_readable()
readable.loc[readable["Value"].idxmax()]
Id                                1
Column                          165
Index     2024-03-12 00:00:00+00:00
Value                      0.004999
Name: 3301, dtype: object

两万个订单占用两万行,而不是 366 根 K 线乘以 1,000 列再乘以每个字段。最差成交是第 165 列的第二个订单,发生于 2024 年 3 月 12 日。

记录

记录数组是结构化 NumPy 数组,每个事件一行,具有列、K 线、价格和规模等字段。记录类将其与数据的时间索引和列标签一起封装,让同一对象同时了解原始位置及其对应日期。订单、日志、交易、持仓、回撤和形态匹配都是记录。

区间是带有起点和终点的记录。任意布尔掩码都能转换为区间,将时段变成可衡量的对象:

Turn overbought periods into ranges
btc = vbt.YFData.pull("BTC-USD", start="2020-01-01", end="2025-01-01")
rsi = btc.run("rsi", window=14).rsi.rename("RSI")
overbought = vbt.Ranges.from_array(rsi > 70)
print(overbought.count(), overbought.coverage.round(3))  
42 0.128
longest = overbought.apply_mask(overbought.duration.top_n_mask(3))
longest.readable[["Start Index", "End Index", "Status"]]
                Start Index                 End Index  Status
0 2023-01-11 00:00:00+00:00 2023-01-30 00:00:00+00:00  Closed
1 2023-10-20 00:00:00+00:00 2023-11-14 00:00:00+00:00  Closed
2 2024-11-06 00:00:00+00:00 2024-11-25 00:00:00+00:00  Closed
longest.duration.values
array([19, 25, 19])

记录也可根据您自己的数据构建。带有日期和交易标的的 DataFrame 或字典列表,可以转换为具有类型的记录;索引记录正是通过这种方式将稀疏订单传入模拟。

映射数组

映射数组为每条记录保存一个值,同时保留记录的列和 K 线位置。记录对象的每个字段都可作为映射数组访问,例如 pf.trades.pnl 或 pf.drawdowns.duration;map_array 则可附加您计算的任意数值。映射数组支持通过 mean、max、idxmax、count 或任意编译函数按列或组归约,通过 top_n_mask 等掩码筛选,并在需要表格时用 to_pd 或 to_readable 转换为 pandas。to_pd 将每个值放到其记录对应的 K 线上。同一列的多条记录共享一根 K 线时,会保留最后一条并发出警告。传入 reduce_func_nb(例如 "sum")可合并它们,传入 repeat_index=True 可全部保留,或用 ignore_index=True 将值无日期堆叠。

这让您能够针对回测提出更具体的问题:几乎没有浮盈的亏损交易持续了多久?哪些订单成本最高?先筛选记录或映射值,再对选定事件运行相同归约。结果保留资产和参数标签。交易分析展示了如何将此流程用于多空交易及其价格偏移。

索引与重新分组

记录保持按列排序,列映射记住每列记录的起始位置,因此选择某列或分组(例如 pf.trades["BTC-USD"])无需扫描全部记录。分组可在事后更改:同一组交易记录通过 group_by=False 按资产报告,也可通过其他分组方式按策略报告。如需跨列按时间查看,请按索引列对可读表格排序。

例如,先分别报告三个资产,再将 A 和 B 合并为一个研究分组:

Regroup trade profits without rerunning the backtest
group_close = pd.DataFrame({"A": [10.0, 11.0, 12.0], "B": [20.0, 18.0, 19.0], "C": [30.0, 33.0, 36.0]}, index=pd.date_range("2026-01-01", periods=3))
group_pf = vbt.PF.from_orders(group_close, size=np.array([1, 0, -1])[:, None])
trade_pnl = group_pf.trades.status_closed.pnl
trade_pnl.sum()
A    2.0
B   -1.0
C    6.0
Name: sum, dtype: float64
trade_pnl.sum(group_by=["Group 1", "Group 1", "Group 2"])
group
Group 1    1.0
Group 2    6.0
Name: sum, dtype: float64

同一组记录现在回答了不同的报告问题。您可以按行业、策略系列或每列的其他标签分组。如需让资产在模拟运行时共享资金,请使用共享现金。

自定义记录类

您自己的事件可以有自己的类。定义包含所需字段的 NumPy dtype,附加标题和值映射,让可读表格显示名称而非代码,再继承 vbt.Records 或 vbt.Ranges,即可获得筛选、映射字段、统计和绘图功能。记录像其他 VBT 对象一样可以保存到磁盘并加载。在 Numba 代码中,用 record["price"] 这样的方括号读取记录字段,无论是否开启编译都能工作。

✅ 此前 OHLC 数据用于模拟,但分析只使用收盘价。现在,大多数类都能跟踪全部 OHLC 数据,让定量和定性分析更加准确。

Plot trades of a random portfolio
data = vbt.YFData.pull("BTC-USD", start="2020-01", end="2020-03")
pf = vbt.PF.from_random_signals(
    open=data.open,
    high=data.high,
    low=data.low,
    close=data.close,
    n=10,
    seed=42
)
pf.trades.plot().show()
BTC-USD OHLC 与随机投资组合交易的入场和退出 图表数据(JSON)

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

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