Portfolio

vectorbt Portfolio:三入口选择与回测可信度审计

Portfolio 是这套框架回测的核心对象,提供三种工厂方法:from_holding(买入并持有)、from_signals(按信号进出场)、from_orders(按订单精细控制)。选对入口后,还要核对信号可知时间、freq 年化口径、费用和成交假设。单看统计摘要无法证明结果可交易。

三入口:holding / signals / orders关键:信号 shift(1)依据官方仓库与文档(2026-09 核验)
from_holding 买入持有
from_signals 信号进出场
from_orders 订单精细控制
stats() 绩效输出
Portfolio 三种工厂方法与绩效输出的关系示意(schematic);语义差异见正文对照表。
Compare

vectorbt 三类入口怎么选?输入、场景与坑

vectorbt 三个工厂方法的差别不在「快慢」,而在你手上已经有的是持仓、信号还是订单。

入口输入适用场景注意点
from_holding持仓数量(如固定股数或固定比例)买入并持有,或作为与策略对比的基准曲线它不主动交易,只反映持有收益;当作基准时必须与策略同区间、同成本口径
from_signals布尔买卖信号(entries / exits)双均线、MACD 金叉死叉、RSI 等信号驱动策略信号与价格同索引时等于当日收盘信号当日成交,必须先 shift(1)
from_signals + accumulate连续出现的买入信号分批建仓、定投式加仓、金字塔加仓不加该参数时,连续信号可能只在首次买入生效,仓位与预期不符
from_signals 多列信号DataFrame 多列(多标的或多组参数)多标的等权、参数组横向对比列数会被广播成多组独立回测,标的数与参数数相乘会显著吃内存
from_orders订单规模(数量或金额)+ 成交价格组合再平衡、指定成交价、含做空、按目标仓位调仓目标仓位与当前仓位的差额要自己算;算错会出现越调越偏
先算信号、再转订单先由信号推出订单,再交给订单入口既要信号驱动的逻辑,又要精细控制成交价与数量两步计算要对齐索引与日期,否则订单会落在错误的 bar 上
三入口组合使用同一份价格数据分别建多个 Portfolio策略与基准对比、不同仓位口径的敏感性测试它们各自独立,不共享资金与持仓;想放在一起比较须统一初始资金与费率
How to choose

按研究目标怎么选 vectorbt 入口?

用 vectorbt 之前先问自己手上有什么:持仓、信号,还是明确的订单清单。

看基准收益

只想算「一直持有」的对照曲线,用 from_holding,输入持仓数量即可,不需要写信号逻辑。它常被用来回答「择时到底有没有跑赢不择时」,注意基准与策略要用同一段价格、同一套成本假设。

信号进出场

策略靠买卖信号驱动,用 from_signals:把指标算出的交叉、突破等布尔序列传进 entries / exits。连续加仓时确认 accumulate 是否符合预期,并且记得把信号 shift(1) 再交给回测。

精细控制成交

需要指定成交价格、数量、或做组合再平衡、分批建仓时用 from_orders,由你自己给出每一笔订单。它比信号入口更贴近实盘下单口径,代价是所有仓位计算都要自己写清楚。

Pitfall

vectorbt 回测的前视偏差:为什么必须 shift(1)?

回测里常见的时间错误,是把「事后才知道的信息」当成「当时就能用的信息」。信号是否后移取决于信号计算时点与成交价假设。

错误写法现象正确写法为什么
信号不 shift,直接传入收益明显高于实盘,回撤还很小entries / exits 先 shift(1) 再传入当日收盘价既用于生成信号又用于成交,等于用了未来信息
用当日收盘价算交叉、当日成交换手越高,虚高越明显信号延后一根 bar 生效盘中无法提前确认收盘价,收盘后下单最快也要下一根 bar 成交
多标的信号不统一索引某几只标的的收益对不上账先对齐到同一交易日索引,再 shift各标的停牌与上市日期不同,索引错位会让信号落到错误日期
缺失值与停牌不处理净值曲线出现异常跳变缺失值补齐或对齐时剔除,再回测缺口位置被当成零收益或异常收益,扭曲了区间收益
不设手续费与滑点策略看起来稳赚成本几乎为零回测时显式传入费率与滑点假设真实交易有佣金、税费与冲击成本,换手越频繁偏差越大
指标用整段样本计算(如全区间标准化、排序)样本内极漂亮,样本外失效只用当根及之前的窗口计算整列一次性运算是向量化的便利,也最容易无意识地引用未来数据
在全部历史上挑较优参数回测里较优的参数上实盘就钝化做样本内外切分或滚动验证择优这一步本身就使用了未来的信息,属于过拟合
import vectorbt as vbt
price = vbt.YFData.download("AAPL").get("Close")

fast = vbt.MA.run(price, 10)
slow = vbt.MA.run(price, 30)
entries = fast.ma_crossed_above(slow)
exits = fast.ma_crossed_below(slow)

# 反例:信号与价格同索引,等于用当日收盘价成交
pf = vbt.Portfolio.from_signals(price, entries, exits)
pf = vbt.Portfolio.from_signals(
    price,
    entries.shift(1).astype(bool),   # 信号延后一根 bar 生效
    exits.shift(1).astype(bool),
    fees=0.001, slippage=0.001,      # 成本假设要写进回测(此处数值仅示意)
)
pf.stats()
写法说明:如果信号依赖当根 K 线收盘数据,却又按同一收盘价成交,便可能使用了当时尚不可得的信息。把信号 shift(1) 是一种常见对齐方式,但最终应由交易时点和成交模型决定;参数名与撮合行为以当前官方 API 和实现为准。
风险提示:回测结果基于历史数据与假设(含手续费、滑点、成交口径),不代表未来收益,也不构成投资建议。
Frequency audit

vectorbt 的 freq 设置错误会怎样影响年化与 Sharpe/Sortino?

年化指标将观测期映射到年度尺度,实际频率与标注不匹配会造成错误缩放。失真幅度由索引、样本区间和实现口径共同决定;本页不编造固定倍数。

检查项记录值不匹配风险建议复核
数据粒度与freq实际间隔与显式频率年观测数、年化收益及比率缩放不一致抽查相邻时间戳并对照交易日历
小时/分钟数据1h/15m 等源数据间隔误标日线可能使年化波动和风险比率失真确认盘中交易时段、时区与缺失 bar
不规则序列停牌、休市和缺失值处理固定频率可能不代表实际观测间距记录重采样或剔除规则
多个市场混合各资产的交易日历与时区一个 freq 可能无法覆盖所有市场先分市场统计,再明确组合换算口径
默认/自动推断所用版本对索引的实际解释版本或索引变化可能影响统计结果读取输出并显式记录验证过的设置
对照实验同一收益序列分别用正确/错误 freqSharpe、Sortino 变化依赖真实序列保留原始收益与 API 版本,不外推固定倍数
频率核验:先用已知时间戳确认实际 bar 间隔,再按当前安装版本官方 API 记录 freq。比较时同时报告不依赖年化的区间总收益,并将 freq、无风险利率和样本长度写入实验记录。
Stats

vectorbt stats() 指标与成本口径怎么读?

同一套 vectorbt 代码换一个区间,这些数字会全变;先看口径,再看大小。

指标含义怎么判断常见误读
Start / End回测起止区间区间是否覆盖了牛熊与震荡不同区间的结果放在一起比大小
Total Return区间总收益与同区间基准、与同类策略比只看收益不看承担的风险与回撤
Annualized Return折算到年的收益区间越长越有参考意义短区间年化被放大,看着很惊人
Max Drawdown区间内回撤幅度先问自己能否承受这个回撤把它当成「未来的回撤幅度」,换区间就会变
Sharpe Ratio风险调整后收益同区间、同口径下横向比较忽略无风险利率与频率假设的差异
Sortino Ratio只惩罚下行波动的风险调整收益与 Sharpe 一起看是否一致样本少或极端值少时数值极不稳定
Win Rate盈利交易占比与盈亏比、期望值一起看以为高胜率就等于赚钱
Profit Factor总盈利与总亏损之比大于 1 才有正期望不看交易次数与资金曲线形态
Total Trades / Total Fees交易次数与累计费用换手是否合理、成本吃掉多少收益只看收益不看被费用消耗掉的部分
手续费与税费费率、最低收费和买卖侧差异净收益是否被交易成本吞噬按账户/市场规则设值并做敏感性测试
滑点与点差比例、固定价差或冲击成本近似触发价是否接近可成交价对高换手、低流动性区间加严假设
交易单位与资金整股/手数、现金共享、杠杆与保证金订单是否符合资金和最小单位约束检查取整后的数量、余额与仓位峰值
涨跌停、停牌与跳空拒单/延迟规则及隔夜价格缺口模型是否把不可成交订单当成已成交OHLCV 不足以模拟排队成交,需额外状态数据
口径提醒:指标名称与计算方式以官方实现为准,年化、比率类指标依赖频率与无风险利率假设。任何回测数字都只是历史区间的统计结果,仅供研究,不构成投资建议。
Decision

vectorbt 社区版与 PRO 的功能、许可怎么分别核对?

先确认代码来自哪个发行形态,再核对安装包、API 文档与许可。社区仓库可证明的功能不能与商业版页面混写;下表列出核验步骤,不宣称已经穷尽 PRO 当前功能清单。

核验项社区版(开源仓库/PyPI)VectorBT PRO使用前动作
发行和获取公开仓库、PyPI 社区包商业产品以官方页面为准核对当前版本与访问条件
组合 API按社区 API reference 核验商业版按其产品文档核验对照安装包接口签名与示例
扩展与并行不从第三方文章推断特定 API以 PRO 文档当前说明为准核对版本、授权与可导入接口
许可仓库 LICENSE 含 Commons Clause 条款以 PRO 商业许可/合同为准分别阅读原文,不互相推断
示例兼容性使用与社区版本相符的官方示例商业示例可能依赖不同包或凭证未核实的 run_parallel 片段不当作标准 API
性能声明按本机版本与输入实测以商业版文档和限定条件为准不引用没有测试环境的倍率
官方来源社区仓库和 API 文档PRO 页面和产品文档逐版本核验功能和许可,不互相推断
核验来源:分别查看 社区仓库 与 PRO 官方页面。产品功能、价格、API 和许可会变化;商业使用前应核对适用条款。
FAQ

常见问题

from_signals 的 accumulate 参数是什么?

它控制连续出现的信号是否累计加仓:开启后连续的买入信号会叠加仓位,不开启时可能只在首次买入生效。是否开启取决于你的策略意图(定投式加仓通常需要它),参数的准确语义与默认值以官方 API 文档为准。

三个入口能混用吗?

三个工厂方法各自独立创建 Portfolio,一次回测通常只用一个;复杂逻辑建议先把信号或订单准备好再统一交给一个入口,避免口径混乱。若同一份数据要分别回测策略与基准,就建两个 Portfolio,但要把区间、初始资金与费率统一;入口语义以官方 API 文档为准

为什么vectorbt 回测收益比实盘高?

最常见的三个原因:信号没有 shift(1) 造成前视、没有计入手续费与滑点、多标的索引未对齐。按这三条依次排查通常能解释大部分差距;剩余差异则来自成交价口径与实盘流动性,这部分只能用实盘口径去校准;排查口径以官方实现为准

from_orders 什么时候用?

需要指定成交价、成交数量,或做组合再平衡、分批建仓等精细控制时用它;简单信号策略用信号入口更简洁。订单入口把所有仓位计算交给你,因此更适合对成交口径要求高的场景,具体字段以官方文档为准。

结果里的年化、Sharpe 能直接信吗?

能作为同一口径下的横向参考,但不能直接当成未来预期:年化与比率类指标依赖数据频率、区间长度与无风险利率假设,换一个区间数值就会变。指标的定义与计算方式以官方实现为准,且任何回测数字都不构成投资建议。

freq 设置错了会怎样?

每期观测数与年化换算不匹配会改变年化收益以及 Sharpe、Sortino 等指标的缩放。先检查索引的真实时间间隔、交易日历和时区,再按当前版本官方 API 指定并记录 freq;本页没有提供未经实测的固定误差倍数。

不写 Python 能验证类似想法吗?

可以走另一条独立路线:本机已核验的量化类技能覆盖了回测与风险指标建模(quant-analyst)、A 股行情数据(akshare-finance / tushare-finance)等方向,一句话即可发起分析任务,但需要先安装对应客户端,且部分数据源要令牌。需要说明的是,vectorbt 与本机技能路线无已证实集成,两者是并列的独立路线,分析结果同样仅供研究;技能能力以官方技能文档为准

vectorbt Portfolio 懂了之后怎么生成指标信号?

下一步用 MA 指标与交叉信号生成买卖点,跑一个双均线策略。