Optimization

vectorbt 参数优化:热力图、walk-forward 与过拟合审计

网格扫描可一次比较多组参数,但峰值只描述被搜索过的历史样本。可信度检查应看相邻参数是否形成稳定区域,并进一步用未参与选参的时间段、成本敏感性和 walk-forward 复核。页面不引用未经同机复现的性能倍率。

核心入口:run_combs 组合扫描结果查看:heatmap 热力图原理:广播 + JIT 编译
定义参数网格
一次算多组指标
批量回测全部组合
热力图找稳定区
参数网格扫描流程示意(schematic):网格 → 指标 → 组合回测 → 热力图;参数名与取值以官方 API 文档为准,加速原理见正文。
Grid search

vectorbt 网格扫描怎么做?从参数列表到热力图

vectorbt 的网格扫描五步按顺序做,每步给出真实代码、一句话说明和可验证的预期结果。示例沿用了双均线场景,参数命名与默认值以官方 API 文档为准。

  1. 1. 准备一段价格序列

    扫描的输入仍然是「索引为时间、值为价格」的一列序列;数据来源可以是内置下载,也可以是自备 CSV(见数据接入页)。

    import vectorbt as vbt
    
    price = vbt.YFData.download('AAPL', start='2020-01-01').get('Close')
    print(price.tail())

    预期:打印出末尾若干行「日期 → 收盘价」。若这一步报网络类错误,先换本地 CSV 或国内数据源再继续——能不能下载到数据取决于数据源可达性,与扫描逻辑无关。

  2. 2. 一次算出多组窗口的指标

    同一个访问器传入窗口列表,就一次性得到多组均线,而不是写循环逐个算。这一步决定了参数网格的横向长度。

    fast = vbt.MA.run_combs(price, window=[5, 10, 20])
    print(fast.window.values)   # 每个组合对应的窗口参数

    预期:返回的结果对象带上了「窗口」这一参数维度,属性名与返回值结构以官方 API 文档为准;若打印报属性不存在的错,说明该版本命名不同,改用文档中的对应属性即可,不影响后续流程。

  3. 3. 把两套参数组合成参数矩阵

    双均线需要快线与慢线两组参数。分别扫描后,两者会按广播规则组合成一张「快线 × 慢线」的参数矩阵——网格的规模就是两个列表长度的乘积。

    slow = vbt.MA.run_combs(price, window=[30, 60])
    
    # 两套参数广播组合后,一次得到「快线 × 慢线」的全部组合
    # 组合数 = 3 × 2 = 6 组,逐条交叉判断即可得到每组参数各自的信号

    预期:结果带上了两个参数维度。注意组合数增长很快:各加 3 个取值就是 9 倍算量,所以网格要「先粗后细」,不要一上来就铺满。

  4. 4. 一次回测整片网格

    把价格与整片信号矩阵交给组合回测入口,所有参数组合在同一批数据上跑完。成本假设在这一步就要定下来,否则不同组合之间不可比。

    pf = vbt.Portfolio.from_signals(price, entries, exits)
    print(pf.stats())

    预期:返回一个组合对象,并打印出按参数维度分组的统计结果;口径与字段名以官方实现输出为准,不同版本可能增删字段。结果只反映这段历史区间的表现,不构成投资建议。

  5. 5. 用热力图看参数稳定区

    把某个绩效指标按两个参数维度铺成热力图,才能一眼看出「哪种参数区域整体表现接近」。

    pf.total_return().vbt.heatmap()

    预期:得到以快线、慢线窗口为坐标的热力图。看的是连成片的稳定区,而不是颜色突出一格——孤立高点通常来自个别行情偶然配合。

环节 / 参数作用取值怎么定适用场景注意点
窗口列表决定要算哪些周期的指标先取一个量级跨度较大的粗列表均线类、趋势类策略的起步扫描列表越长组合数增长越快,网格密度直接决定算量与过拟合程度
参数组合数决定扫描的横向宽度等于各参数列表长度的乘积双参数及以上的策略组合数上千以后必须先想清楚「证据够不够」,而不是直接跑
参数维度命名让结果能被区分与排序按参数角色命名(如快线 / 慢线)结果需要按参数分组查看时名称只用于标识,不影响计算;命名混乱会让后续复盘无法进行
批量回测入口把整片信号一次转成组合输入买入、卖出两组布尔序列买卖条件已明确、只差参数选择成本假设必须一次定好并固定,中途改动会让整片结果失去可比性
费率与滑点让结果贴近真实交易按你自己的实际费率与滑点设定信号频率偏高的参数组合不计成本跑出来的突出组合,绝大多数在真实成本下会失效
网格区间与步长决定扫描的粗细与范围先粗后细,分两轮收窄不确定有效参数区间时把区间外推到极端取值得到的「好结果」没有解释力
结果指标决定用哪个口径排序总收益、夏普、回撤等交叉看不同研究目标下的筛选换一个指标排序往往会换出一组不同的「突出参数」,单一指标不足以定论
提示:网格扫描只在「投资逻辑已经成立、只差参数」时才有意义。如果策略为什么赚钱还说不清,扫描只会把噪声调成一条好看的曲线;把它当成敏感度体检工具,而不是选参数的自动答案。
Why fast

vectorbt 为什么能一次跑完整片网格

同样是「多组参数批量回测」,vectorbt 的做法与逐条循环差别很大,原因就在下面四件事上。

向量化与广播

行情与策略状态都以数组形式保存,多标的、多参数沿新增维度一次性参与运算,避免了 Python 逐事件循环里每个对象、每次函数调用的开销。代价是参数维度越多,占用的内存也越大,扫描前要先估算数据量。

JIT 即时编译

核心计算路径会用即时编译(JIT)把数值循环编成接近机器码的形式执行,因此同一段逻辑不必改写成 C 扩展。首次运行存在编译预热,之后复用编译结果,小任务上反而可能感觉更慢。

可选预编译引擎

官方另提供 Rust 引擎作为可选扩展,用预编译替代部分即时编译开销,适合反复跑大规模网格的场景。它属于可选安装项,需要额外的工具链支持;装不上时退回基础安装仍可正常使用。

与 pandas 同一套接口

指标、信号与结果都以 pandas 对象为主,能直接沿用你熟悉的索引对齐、切片与聚合方式,也能与 pandas / NumPy 生态里的其他工具混用。好处是迁移成本低,代价是仍要遵守 pandas 的对齐规则——索引不一致时会静默出错而不是报错。

加速手段作用代价 / 边界注意点
数组化与广播把多标的、多参数一次算完参数维度上升时内存占用同步上升先估算网格总规模,再决定要不要一次跑完
即时编译(JIT)关键路径让数值循环接近编译语言速度首次调用有编译预热小网格上预热成本占比高,别用一次小测试判断整体速度
可选预编译引擎免去部分预热开销,适合反复扫描需要额外安装与工具链属于可选扩展,装不上可退回基础安装继续研究
按列组织任务贴合连续内存布局,减少跨列随机访问要求数据结构与缺失值口径统一多标的混用不同列结构会让对齐成本悄悄吃掉收益
扫描阶段不生成图表省下渲染与输出时间过程中看不到中间结果最终仍要抽样看图,全程不看容易把错误数据带入结论
控制数值精度与字段降低内存占用与计算量精度取舍会带来细微差异关键结论要用原始精度复核一遍
分批跑大网格避免一次性内存溢出需要自行合并结果并保证口径一致分批时成本假设、数据区间必须完全相同,否则结果不可比
边界说明:上表只讲通用工程手段,不承诺任何具体耗时数字——实际速度取决于数据长度、网格规模、机器配置与是否装了可选引擎,请以你本机实测与官方文档的性能说明为准。
Scenes

vectorbt 参数扫描适合哪些场景?

vectorbt 参数扫描同样如此:有的场景能提高判断质量,有的场景只会得到无法解释的答案。扫描用于敏感性检查,不是自动寻找未来有效策略的工具。

因子参数敏感性

逻辑已经确定,想知道结论对参数是否敏感:看某个参数小幅变化时收益是否平滑过渡。这类扫描的价值在于验证稳健性,而不是找到收益突出的那一格,输出通常是一段区间而不是一个点。

多标的批量验证

同一套逻辑在几十上百个标的上批量回测,看结论是否普遍成立。它能有效排除「只在某个标的上成立」的偶然结果,但前提是所有标的的数据区间、复权口径与缺失值处理方式完全一致。

特征与标签批量生成

为机器学习流程批量生成特征、标签与滚动切分,把向量化能力用在数据准备而不是策略选择上。这一环最容易出错的地方是信息泄漏:切分点之后的信息一旦进入特征,样本外评估就失去了意义。

研究场景该不该做参数扫描建议做法注意点
逻辑明确,只想知道参数敏感度该做用粗网格看邻域是否成片目的是稳健性体检,不追求收益突出的单点
逻辑说不清,指望扫出能赚钱的参数不该做先回头把买卖条件的逻辑写清楚没有逻辑支撑的扫描结果无法解释,也无法在行情变化后判断何时失效
单标的、样本不足三年谨慎拉长样本,或换成多标的验证样本太短时统计量不稳,扫出的差异多数来自噪声
多标的横截面策略该做统一口径,按标的与时间双重切分横截面策略要求同一时点可比,缺失值处理必须一致
机器学习特征与标签准备该做切分训练与验证段,严格按时间推进最怕标签泄漏,切分之后的数据不能出现在特征里
准备实盘、要定最终参数谨慎用样本外段与前向段确认可以接受「不突出但稳定」的参数,而不是样本内表现特别好的那一组
组合数远超本机算力该做但要收窄先粗网格定位,再在局部加密被算力限制逼着收窄网格,本身就是一次合理的筛选
Overfitting

vectorbt 怎么规避过拟合?清单

VectorBT 网格扫描能给出候选参数区域,不能替代独立样本评估。Walk-forward 按时间推进:每轮只用过去窗口选参,再冻结参数跑后续测试窗,最后汇总所有测试窗及失败轮次。

风险点现象规避做法注意点
多重比较(扫的组数太多)网格里总有一格收益明显高于其余记录扫描组数,对该结果打折看待组数越多,出现运气好的组合几乎是必然事件,与策略有效性无关
参数尖峰相邻参数表现断崖式下滑只选连成片的稳定区尖峰通常由个别极端行情贡献,换一段数据就消失
样本内挑参数样本内表现突出,样本外明显回落训练段选参、样本外段复核不能用整段样本挑参数、再拿整段样本汇报结果
区间敏感换一个起止日期结论反转在多段行情上分别复核单一行情阶段(如单边上涨)的结果不能外推
忽略交易成本高频进出组合回报异常高统一施加费率与滑点再排序事后挑选是否计成本,等于变相的参数择优
未做 walk-forward整段历史选参后只报告同一段结果按时间滚动训练、选参和前向测试,汇总所有测试窗测试窗不得参与前一轮选参;窗口与成本口径需预先固定
未做 walk-forward整段历史选参后只报告同一段结果按时间滚动训练、选参和前向测试,汇总所有测试窗测试窗不得参与前一轮选参,窗口和成本口径需预先固定
样本长度不足只靠几十笔交易就下结论拉长样本或换更活跃的标的交易笔数太小时绩效统计量本身就不稳定
参数随行情漂移早期有效、近期失效改为滚动或前向验证参数不是一次选定就长期有效,需要定期复核
标的池选择偏差结论只在现存标的上成立明确标的池的构建规则与纳入时点标的池的构建方式本身就是一种选择,会系统性影响结论
风险提示:扫描只说明在给定历史区间和假设下参数曾如何表现,不代表未来同样成立。还要查看邻近参数、样本外、滚动前向、成本敏感性和不同市场/时间段;回测仅供研究,不构成投资建议。
Performance

vectorbt 性能基准怎么测量、内存怎么控?

vectorbt 的性能基准不引用“快 100 倍”这类脱离环境的宣传值。循环、Numba 与可选 Rust 路径的比较必须固定输入、机器和版本,并把首次 JIT 预热与稳态重复分开记录;未在同机实测前只说明测量方法。

记录项至少保留的值为何影响比较报告建议
数据规模bar 数、资产数、参数组数、数据类型规模决定矩阵与临时数组大小报告总元素规模,不只写“若干标的”
运行环境CPU、内存、操作系统、Python 与依赖版本平台和编译器会改变计算路径保存锁定依赖与完整执行命令
首次调用进程冷启动及 JIT 编译耗时预热可能主导小任务的耗时与稳态重复结果分开列示
稳态重复多次耗时与中位数、离散程度单次计时易被缓存或后台任务干扰说明重复次数、清理规则与统计方式
峰值内存与分块扫描峰值、是否分块、是否中断大矩阵可能先受内存限制而非算力限制记录分块策略、批次参数范围与进程峰值
计算等价性相同输入、信号、成本与输出字段撮合语义不同则耗时不可比对输出摘要做一致性校验并留档
Rust 路径实际安装版本、启用方式与回退情况装了 extras 不代表所有代码路径都走 Rust按官方说明逐项核对,不据 extras 猜结论
分批等价性整批与分批各跑一次的小样本对照边界或广播顺序变化会改变结果逐字段对账通过后再扩展到完整网格
取舍原则:性能比较必须控制输入和口径,并把首次 JIT 编译与稳态计时分开;如果尚未在同机实测,不给固定加速倍率。分批扫描还要保留参数区间、快照与版本,确保结果可复核。
Read results

vectorbt 扫描结果怎么读?

vectorbt 跑完网格只是拿到候选结果,还需复核稳定性、基准、成本和未见时间段。

看什么怎么判断常见误读下一步
热力图整体形态颜色是否连成成片的区域只盯颜色突出的一格取稳定区中心附近的参数,而不是孤点
参数邻域梯度平缓过渡优于陡峭断崖把陡峭当成「参数精准」降低网格密度或换区间再验一次
绩效指标组合收益类与风险类指标交叉看只看总收益排序用回撤、风险调整后收益等口径复核
与基准对比是否明显优于对照基准忽略基准、只看绝对收益计算相对表现,确认超额来自策略还是行情
交易笔数样本量是否足以支撑判断把笔数多当成策略可靠笔数过少时结论只能算线索,不能当作证据
成本敏感性提高成本假设后是否仍然成立用零成本结果下结论在更高成本下重跑,看稳定区是否还存在
结果的时间分布收益是否高度集中在某一段行情只看区间总收益按子区间分别统计,识别对特定行情的依赖
口径说明:热力图上显示的指标口径、字段名与计算方式以官方实现为准,不同版本可能调整;同一个数字在不同数据区间、不同成本假设下没有可比性。所有结论仅供研究,不构成投资建议。
FAQ

vectorbt 常见问题

网格搜索会不会过拟合?

会。参数和尝试次数越多,越容易在历史数据中找到偶然突出的组合。查看相邻参数区域、样本外窗口、walk-forward 和成本敏感性只能降低风险,不能消除数据挖掘偏差;实现与统计口径以官方文档为准。

run_combs 和 run 有什么区别?

run 面向单一参数组,算出一条指标序列;run_combs 面向参数列表,一次算出多组并带上参数维度,结果可直接进入批量回测与热力图。参数名、支持写法和默认行为以官方 API 文档为准,不同版本可能有差异;如果不确定,先用 run 在小样本上验证逻辑,再换 run_combs 做批量扫描。

一次扫多少组参数比较合适?

没有通用数字,判断依据是你打算怎么解释结果:如果只是做敏感度体检,数百组通常就够看出邻域是否成片;如果需要精细定位稳定区,可以在粗扫后再局部加密。要注意组合数随参数个数增长很快,两组参数各取 10 个点就是 100 组,再加上多标的会成倍放大;同时网格越密,对样本外检验的要求也越高;网格上限以官方文档与本机资源为准

网格跑得很慢,先查什么?

按顺序排查四件事:网格总规模是否已经过大、内存是否成为瓶颈(表现为频繁换页或直接中断)、是否在扫描过程中生成了多余的图表与报告、是否装了可选的预编译引擎(可选扩展,需要额外工具链)。常见做法是先粗后细、分批运行、扫描阶段不出图。实际速度取决于数据长度、网格规模与机器配置,以你本机实测为准;若只是想先验证一个想法、不打算维护这套环境,可以用本机技能Claw 本机已核验的量化类技能走一句话研究路线,两者是独立路线,没有已证实集成;性能表现以官方文档与本机实测为准

heatmap(热力图)应该怎么看?

热力图以参数为坐标展示某个绩效指标,看的是「成片」而不是「一格」:相邻参数表现接近的区域才算稳定区,说明策略对该参数不敏感;孤立的高点通常由个别行情贡献。另外要固定热力图的口径——同一张图里混用不同数据区间或不同成本假设,会得出错误结论。指标口径与绘制参数以官方实现为准。

扫出来的参数能直接用于实盘吗?和本机技能路线怎么分工?

不建议直接使用。样本内表现突出只能说明「在这段历史上曾经有效」,落地前至少要做样本外与前向验证、确认成本敏感性、检查交易笔数是否足够。实盘还涉及资金与执行风险,需自行评估。至于分工:需要自己控制数据、成本与参数口径的研究走本页这条自建路线;只想先用自然语言问清研究问题、快速看行情与指标,可以看本机已核验的量化研究类技能。两条路线相互独立,无已证实集成,具体可用能力以各自官方说明为准。

vectorbt 参数优化之后怎么把数据接稳?

下一步处理数据接入:行情来源、A 股数据整理、缺失值对齐与复权口径。