这不是实现细节。是计算范式的差异。
向量化回测把历史数据视为矩阵。事件驱动回测把历史数据视为按时间排序的事件流。前者优先吞吐量,后者优先执行逻辑保真度。两者都能生成净值曲线,也都能计算夏普比率和最大回撤。但曲线相同,不代表模拟过程相同。
“事件驱动回测 向量化回测 区别”不能被压缩成一句“一个快,一个慢”。真正的分界线在于:策略是否依赖逐时刻状态、订单生命周期、成交反馈和资金约束。
计算范式的博弈:矩阵运算与时间序列模拟
向量化回测先计算信号,再计算结果
向量化回测通常将价格、成交量、因子和持仓状态存储为数组或表格。均线、波动率、动量、横截面排名等指标,均可通过批量运算一次性生成。
以双均线策略为例:
- 短期均线高于长期均线,生成买入信号。
- 短期均线低于长期均线,生成卖出信号。
- 信号整体向后移动一个交易周期。
- 按下一根K线的开盘价或收盘价计算成交结果。
- 汇总收益、成本、回撤和风险指标。
计算过程主要由数组对齐、滚动窗口和布尔运算组成。没有显式的订单对象,也没有逐笔成交回调。多数情况下,策略逻辑可以被表达为一个或多个列运算。
这类结构适合以下任务:
- 大规模因子检验。
- 多标的横截面排序。
- 双均线、动量、突破等规则明确的策略。
- 多组参数组合扫描。
- 日频和低频数据上的组合构建。
- 研究阶段的快速假设验证。
向量化回测的核心优势不是代码短。是数据并行化。
同一组计算可以同时作用于数千个标的、数十组参数和多个时间窗口。底层使用Numba即时编译,或采用基于Apache Arrow的列式数据处理框架,可以进一步降低解释器开销和内存访问成本。真正的向量化回测引擎,例如VectorBT,和直接使用Pandas写几列公式,不是同一件事。
Pandas是数据容器。不是完整回测引擎。
事件驱动回测按时间推进状态
事件驱动回测不一次性计算整段历史结果。它按照时间戳推进市场状态。每个时间点产生事件,事件触发策略、组合、订单和成交模块的后续动作。
典型事件可以拆分为四类:
1. 市场事件:新的Tick、K线或盘口数据到达。
2. 信号事件:策略根据当前可见数据生成买入、卖出或撤单信号。
3. 订单事件:系统提交订单,进入未成交、部分成交、已成交或已撤销状态。
4. 成交事件:撮合模块返回实际成交价格、数量和手续费。
在这一过程中,策略只能读取当前时间点之前已经到达的数据。资金余额、持仓数量、冻结资金、未成交订单和风险限额,均作为运行状态持续存在。
这种结构更接近实盘。
但“更接近”不等于“完全等同”。事件驱动框架仍然需要明确成交规则、数据源、时钟、延迟、滑点和撮合队列。事件循环本身不会自动产生真实性。它只提供了表达真实性的结构。
两种架构的核心差异
| 参数 | 向量化回测 | 事件驱动回测 |
|---|---|---|
| 数据处理方式 | 矩阵和数组批量运算 | 按时间戳逐条处理事件 |
| 主要目标 | 计算效率和参数扫描 | 交易逻辑与执行过程保真 |
| 常见工具 | NumPy、Pandas、Polars、VectorBT | Backtrader、Zipline、vn.py及自研引擎 |
| 未来函数风险 | 较高,容易产生前瞻偏差 | 较低,时间顺序约束更明确 |
| 撮合模型 | 通常较简化 | 可模拟滑点、手续费、部分成交和队列 |
| 复杂状态管理 | 表达困难 | 原生适合订单和资金状态 |
| 参数搜索 | 高效 | 成本较高 |
| 高频与盘口策略 | 通常不适合 | 更适合 |
| 实盘代码复用 | 通常有限 | 订单状态机可直接复用 |
| 研究阶段效率 | 高 | 中低 |
| 上线前验证能力 | 有限 | 较强 |
这里不存在全局最优解。
选择架构,首先取决于策略的状态复杂度,其次取决于数据频率和执行细节,最后才是编程语言与硬件。
向量化回测的性能优势:速度来自批量计算
pandas向量化回测的边界
Pandas能够快速完成基础指标计算。问题出现在回测逻辑开始依赖循环时。
典型的低效实现包括:
- 对每个标的逐个调用回测函数。
- 对每个参数组合重复复制数据。
- 在每根K线上执行Python层循环。
- 每次更新持仓都重新计算完整账户状态。
- 使用大量中间表保存同一份数据。
- 将日期索引、时区转换和数据拼接重复执行。
这种代码看起来仍然是“向量化回测”。实际运行方式已经退化为多层解释器循环。数据规模扩大后,内存占用和执行时间会同时上升。
Pandas的优势在于表达列运算,不在于自动优化所有回测过程。它不会自动处理:
- 订单排队。
- 多账户资金分配。
- 部分成交。
- 逐笔手续费。
- 盘口深度。
- 订单撤销。
- 交易所限制。
- 组合级风险约束。
如果把这些逻辑硬塞进表格,最终会得到大量移位、填充和条件覆盖。结果可能很快,但可读性和可审计性下降。
Polars解决的是数据层效率
Polars采用列式内存布局,并基于Apache Arrow组织数据。相较传统Pandas工作流,在特定数据处理任务中,内存效率可提升约3至10倍。
它更适合以下场景:
- 大规模多标的历史数据清洗。
- 多字段时间序列连接。
- 横截面因子计算。
- 批量读取和过滤。
- 延迟执行的数据处理链。
- 研究阶段的特征工程。
但Polars仍然主要解决数据处理问题,不等于自动获得完整的交易模拟能力。
数据框架负责回答:
当前数据是什么?
回测引擎还需要回答:
当前账户有什么持仓?
订单什么时候提交?
订单是否成交?
成交后现金如何变化?
下一根K线能否使用刚刚生成的信号?
这两个问题属于不同层级。
VectorBT的性能来自计算模型
VectorBT不是简单的表格封装。它通过数组广播、Numba即时编译和批量状态计算,将多个标的、多组参数和多个策略路径压缩到统一的数据结构中。
例如,30组均线参数可以被组织成参数维度。5000个标的可以被组织成标的维度。时间序列作为时间维度。策略结果不再是一条净值曲线,而是一个多维结果集合。
这使得参数扫描从“运行30次”变成“对参数维度进行批量计算”。
但维度增加会直接推高内存需求。时间、标的、参数和指标全部展开时,内存占用近似随维度乘积增长。速度提升不是免费的。数据复制、广播、临时数组和结果缓存都需要内存。
在设计向量化研究系统时,通常需要控制四个变量:
- 保留的数据字段数量。
- 参数组合的总规模。
- 中间计算结果的生命周期。
- 是否分批处理标的和参数。
不要把全部历史数据一次性加载,再把所有指标和交易结果永久保留。那不是高性能设计。只是更快地耗尽内存。
向量化适合搜索,不适合解释所有执行过程
向量化回测最有价值的阶段,是从假设到证据。
例如,需要判断以下问题:
- 20日动量是否优于60日动量。
- 短期均线和长期均线的参数区间是否稳定。
- 因子在不同市场阶段是否具有相同方向。
- 手续费从一个水平提高到另一个水平后,策略是否仍然有效。
- 单标的信号和横截面组合信号之间是否存在差异。
这些问题的共同特征是:信号规则相对固定,执行细节暂时不是主要变量。
此时,向量化回测可以快速生成大量结果,再通过样本外测试、滚动窗口和参数稳定性分析筛选候选区域。
但如果策略收益主要来自以下因素,向量化结果就不能直接作为部署依据:
- 订单优先级。
- 瞬时盘口变化。
- 限价单成交概率。
- 部分成交后的剩余数量。
- 动态止损触发顺序。
- 多策略之间的资金竞争。
- 跨周期信号的到达顺序。
- 成交回报对下一次决策的影响。
速度只解决计算成本。不解决模型正确性。
向量化回测可以快速证明一个假设不值得继续研究,但不能仅凭速度证明交易过程被正确模拟。
事件驱动回测的逻辑防线:时间顺序与订单状态
未来函数通常不是算法问题
前瞻偏差的根源,通常不在均线公式,而在数据访问边界。
例如,使用当天收盘价计算信号,再假设当天收盘价成交。这个结果表面上合理,实际上需要明确成交时刻。如果信号是在收盘后生成,成交至少应落到下一交易时点。如果信号在收盘前生成,就必须说明使用的是哪一个时刻可见的价格。
向量化处理整段数据时,未来数据已经存在于内存。一次错误的索引、移位或填充,就可能将未来信息带入当前决策。
常见问题包括:
1. 使用未移位的收盘价生成信号并直接按同一收盘价成交。
2. 计算滚动指标时错误包含当前尚未完成的K线。
3. 用全样本均值和标准差进行标准化。
4. 使用未来区间的最高价和最低价构造当前止损。
5. 对停牌、缺失和复权数据处理不当。
6. 在横截面排名中混入尚未同时结束交易的标的。
7. 先看完整数据再决定样本区间或交易规则。
事件驱动框架通过时间推进天然提供了一层约束。数据在时间戳上单调递增。策略回调只能获取已经到达的数据。未来K线物理上还没有进入系统。
这会减少前瞻偏差,但不会消除全部偏差。
如果事件源错误地预加载完整数据,或者策略对象直接访问全局数组,未来函数仍然存在。框架提供防线,开发者仍然需要审计。
订单状态机是事件驱动系统的核心
一个可部署的交易系统,不能只保存“持仓数量”和“现金余额”两个字段。至少需要区分以下状态:
- 订单已创建。
- 订单已提交。
- 订单已被交易接口接收。
- 订单部分成交。
- 订单完全成交。
- 订单被拒绝。
- 订单被撤销。
- 订单超时。
- 订单发生重复回报。
- 订单与本地状态不一致。
如果回测和实盘使用两套完全不同的订单逻辑,回测收益和实盘行为之间会出现结构性断裂。
事件驱动架构通常把订单状态机放在回测和实盘之间。回测使用模拟撮合器,实盘使用交易所或券商接口。策略层只提交目标动作,执行层负责将动作转化为订单,回报层负责更新状态。
这是一条清晰的边界。
向量化回测通常直接由信号推导持仓。它可以有效计算“理想情况下应持有多少”,但不天然表达“上一次订单是否还未成交”。
撮合精度决定收益是否可实现
最简单的撮合模型是:
- 当前周期产生信号。
- 下一周期开盘价成交。
- 每笔交易扣除固定手续费。
- 忽略买卖价差和部分成交。
对于低频、流动性较高、信号持有周期较长的策略,这种模型可以用于早期研究。但它不是通用模型。
事件驱动回测可以进一步加入:
- 固定滑点。
- 按成交额比例计算的市场冲击。
- 买一卖一价差。
- 盘口深度。
- 限价单触价规则。
- 排队位置。
- 成交数量上限。
- 部分成交。
- 订单撤销延迟。
- 网络传输延迟。
- 交易所手续费和返佣。
- 最小下单数量与价格精度。
这些因素不一定都需要模拟。需要根据策略的持仓周期和交易频率决定。
日频趋势策略如果每天只交易少量流动性良好的标的,复杂的逐笔盘口重放可能没有必要。高频策略如果只采用收盘价成交,回测净值的统计意义通常有限。
模型复杂度必须与策略暴露的风险来源匹配。
动态止损是向量化的分水岭
固定规则的止损可以通过数组计算。例如,入场后下跌一定比例即生成退出信号。
动态止损更复杂。止损价格可能随最高价、波动率、持仓时间和未成交订单状态变化。一次K线内,先触发止盈还是先触发止损,也可能无法从OHLC数据中唯一确定。
如果同一根K线的最高价和最低价都触及了两个条件,向量化回测必须预先定义优先级。否则,结果取决于代码中的条件覆盖顺序,而不是市场数据本身。
事件驱动回测可以使用更细粒度的Tick或盘口数据重放。它仍然不能从一根普通K线恢复真实的成交路径,但可以明确模拟顺序和触发逻辑。
这就是事件驱动回测的价值:不是自动得到真实答案,而是让假设可见。
策略生命周期:从因子研究到实盘部署
研究阶段不应直接从复杂框架开始
研究阶段的主要成本是迭代。一个因子假设可能在一天内修改几十次。每次都启动完整订单状态机、风险模块和撮合引擎,会增加不必要的工程负担。
更合理的流程通常是:
1. 使用向量化方式清洗数据并构造因子。
2. 通过批量计算完成初步信号检验。
3. 使用多组样本区间检查稳定性。
4. 将候选策略转入事件驱动回测。
5. 增加手续费、滑点、成交限制和资金约束。
6. 进行纸面交易或仿真运行。
7. 最后接入实盘接口。
第一阶段回答“信号是否存在”。第二阶段回答“执行过程是否可实现”。
不要在第一阶段就把全部工程复杂度引入。也不要在第二阶段继续依赖过度简化的成交模型。
因子研究更适合向量化
因子研究的计算对象通常是:
- 横截面排名。
- 分组收益。
- 因子暴露。
- 行业中性化。
- 市值中性化。
- 换手率。
- 信息系数。
- 多空组合收益。
- 样本内与样本外差异。
这些计算天然适合矩阵和列式数据结构。
例如,横截面动量可以将每个交易日的标的收益组织成二维矩阵,再对每个截面进行排序和分组。对数千个标的和多组持有期进行扫描时,逐事件执行没有必要。
但当组合进入执行层,问题开始变化:
- 目标权重何时生成。
- 调仓订单如何拆分。
- 当前持仓是否已经成交。
- 多个策略是否争用同一账户资金。
- 某个标的是否出现涨跌停或暂停交易。
- 调仓过程中风险暴露如何变化。
这些问题属于事件驱动层。
趋势策略可以采用分层架构
双均线、突破和动量策略通常可以用向量化方法完成信号研究。但部署时仍然需要处理订单、资金和交易限制。
可采用三层结构:
- 数据层:读取、清洗、对齐行情数据。
- 研究层:使用向量化方式计算指标、因子和候选信号。
- 执行层:使用事件驱动方式处理订单、成交、资金和风险。
研究层只输出目标仓位或目标订单。执行层不重新解释策略信号,只负责完成交易生命周期。
这样可以保留向量化计算速度,同时避免用理想化持仓替代真实账户状态。
统计套利需要更严格的时间约束
统计套利通常包含价差、协整、滚动回归、标准化和均值回归信号。这里的“均值回归”不是叙事标签,而是一个需要持续估计参数的统计过程。
参数估计窗口必须严格限定在当前时刻之前。滚动均值、滚动标准差、回归系数和残差都不能使用未来样本。样本区间改变后,标准化结果也会改变。
事件驱动回测在跨标的同步方面更有优势。不同标的的行情时间戳可能并不完全一致。某个市场已经收盘,另一个市场仍在交易。若直接对齐到统一K线并前向填充,可能产生虚假的同步价格。
对于跨市场套利,还需要明确:
- 时区转换规则。
- 夏令时处理。
- 交易日历。
- 不同市场的开闭市时间。
- 延迟方向。
- 汇率转换时点。
- 资金占用和保证金变化。
这些因素不会被夏普比率自动修正。
高频策略通常不能停留在向量化结果
高频和加密货币策略依赖更多微观结构变量:
- 买卖价差。
- 盘口深度。
- 委托簿变化。
- 订单到达延迟。
- 排队位置。
- 撤单速度。
- 部分成交。
- 交易所限频。
- 网络抖动。
- 不同接口的时间戳差异。
如果只用分钟K线或收盘价做回测,很多策略收益其实来自成交假设,而不是信号本身。
事件驱动框架能够逐Tick推进,但数据粒度仍然决定上限。没有逐笔数据,就不能宣称完成了盘口级撮合模拟。没有真实延迟分布,就不能宣称复现了低延迟执行。
系统应该明确知道自己没有模拟什么。
事件驱动回测的优势不是“更复杂”,而是把订单、时钟和成交约束显式化。所有没有被显式建模的部分,仍然属于未知误差。
回测与实盘的鸿沟:时间、滑点与数据一致性
时间戳错误比指标错误更隐蔽
量化系统中,时间戳是主键。
以下问题都可能改变信号与成交的顺序:
- 数据使用本地时间,交易接口使用协调世界时。
- 日期索引包含时区,成交回报不包含时区。
- 夏令时切换导致交易时段偏移。
- K线的结束时间被误认为开始时间。
- 不同数据源的分钟边界不一致。
- 夜盘数据被归入错误的交易日。
- 跨市场数据使用不同的交易日历。
- 网络延迟导致行情和账户回报不在同一时钟上。
一个策略即使指标计算完全正确,只要时间对齐错误,也会产生错误的成交顺序。
回测系统需要明确记录:
- 原始时间戳。
- 标准化时间戳。
- 数据到达时间。
- K线生成时间。
- 信号生成时间。
- 订单提交时间。
- 成交回报时间。
不要只保留一个名为“时间”的字段。
K线合成逻辑会改变策略
分钟K线不是天然存在的。它由Tick或成交记录聚合而成。不同的数据源可能在以下方面存在差异:
- 是否包含撤单后的成交修正。
- 是否使用成交价而非中间价。
- 开盘价和收盘价的定义。
- 缺失分钟是否补齐。
- 盘口数据如何聚合。
- 夜盘和日盘是否合并。
- 复权价格如何处理。
对于低频策略,这些差异可能被手续费和滑点覆盖。对于短周期策略,差异会直接改变信号触发位置。
向量化回测往往默认数据已经正确。事件驱动回测则更容易暴露数据流问题,因为每条事件都要经过时间排序和状态更新。
两种架构都需要独立的数据验证层。不要把数据清洗逻辑隐藏在策略代码中。
滑点不是一个固定百分比
固定滑点适合做初步敏感性分析。它不是完整的成交模型。
实际滑点至少受以下因素影响:
- 订单方向。
- 订单数量。
- 市场成交量。
- 买卖价差。
- 波动率。
- 下单时间。
- 订单类型。
- 盘口深度。
- 延迟。
- 市场状态。
对于大额订单,成交价可能随成交数量逐级恶化。对于限价单,价格不变不代表能够成交。对于市价单,成交概率高,但价格不确定性更高。
可以先用多个滑点参数进行敏感性测试。例如,分别测试低、中、高三个摩擦水平,观察策略的年化收益、最大回撤、换手率和收益分布是否发生结构性变化。
如果策略只在零滑点条件下有效,结果已经足够明确。无需继续优化参数。
手续费会改变高换手策略的统计分布
交易成本不仅降低收益,还会改变收益序列的形状。
高换手策略通常具有以下特征:
- 毛收益看起来稳定。
- 净收益对费率变化敏感。
- 单笔交易优势较小。
- 收益分布集中在大量小额交易。
- 极端滑点会放大回撤。
- 交易成本存在明显的非线性影响。
因此,不能只在最终净值中减去一笔总手续费。手续费应当在每次成交时扣除,并与成交数量、成交价格和交易方向绑定。
组合层面还需要处理:
- 多标的同时成交。
- 现金不足。
- 保证金占用。
- 资金冻结。
- 交易单位取整。
- 最小价格变动单位。
- 资金费率或借贷成本。
- 分红和分拆等公司行为。
向量化回测可以对这些因素做近似计算。事件驱动回测更适合逐笔维护。
回测指标不能替代过程审计
常见绩效指标包括:
- 年化收益率。
- 夏普比率。
- 最大回撤。
- 卡玛比率。
- 胜率。
- 盈亏比。
- 换手率。
- 欧米茄比率。
- 尾部损失。
- 收益偏度和峰度。
这些指标可以描述结果,不能解释结果为什么产生。
两个策略可能拥有相同的夏普比率,但一个依靠少数极端收益,另一个依靠大量小额收益。前者对异常数据和交易成本更敏感,后者对延迟和成交率更敏感。
回测系统至少应保存交易级日志:
- 信号产生时刻。
- 使用的数据版本。
- 目标仓位。
- 实际下单数量。
- 委托价格。
- 成交价格。
- 成交数量。
- 手续费。
- 滑点。
- 订单状态变化。
- 账户余额变化。
- 当时的风险暴露。
没有交易级日志,绩效指标无法被有效复核。
如何选择架构:按状态复杂度而不是流行度
可以用以下顺序判断。
第一层:策略是否需要逐时刻反馈
如果策略只依赖历史价格、成交量和固定窗口指标,向量化方法通常足够用于研究。
如果策略需要读取上一笔订单的成交结果、当前剩余现金、未成交订单或动态风险暴露,事件驱动结构更合适。
第二层:成交细节是否决定收益
如果策略持仓周期较长,且交易规模相对市场成交量较小,可以先使用简化成交模型。
如果策略依赖限价单、盘口、拆单、部分成交或极短持仓周期,必须提高撮合层级。否则,回测收益与可执行收益之间的差异可能超过策略本身的统计优势。
第三层:是否需要直接迁移到实盘
如果回测只是一次性研究,向量化结果可以独立存在。
如果目标是自动交易,事件驱动回测的订单状态机、异常处理和接口边界都具有实际价值。回测代码不一定能全部复用,但状态定义和事件接口可以复用。
第四层:数据规模是否允许逐事件运行
逐Tick数据、数千标的和多年历史区间会显著增加事件驱动回测成本。此时可以采用分层架构:
- 用列式数据框架完成清洗。
- 用向量化引擎计算因子和候选信号。
- 只将候选策略、关键标的和必要时间区间送入事件驱动撮合器。
- 对最终版本进行高保真验证。
这比对所有参数、所有标的、所有Tick数据执行完整事件回测更合理。
混合架构:效率与保真的折中方案
实际系统很少需要在两种架构中二选一。
较常见的混合方式是:
1. 使用Polars或Pandas处理原始数据。
2. 使用向量化计算完成因子、指标和信号初筛。
3. 将信号转换为带时间戳的目标仓位或目标订单。
4. 由事件驱动引擎逐时刻接收信号。
5. 通过撮合器模拟成交和滑点。
6. 由组合管理模块更新现金、持仓和风险暴露。
7. 将事件日志回写到研究数据库。
8. 对回测结果与向量化结果进行差异分析。
这里的关键不是“混合”两个词,而是定义接口。
向量化层输出什么?事件驱动层接收什么?信号时间戳如何表达?目标仓位和实际仓位如何区分?订单重复提交如何处理?如果这些边界没有定义,混合架构只会变成两套互相矛盾的代码。
信号接口应保持不可歧义
一个可用的信号对象至少需要包含:
- 标的。
- 生成时间。
- 数据截止时间。
- 信号方向。
- 目标仓位或订单数量。
- 信号有效期。
- 风险标签。
- 策略版本。
- 参数版本。
不要只传递一个布尔值。
“买入信号为真”无法说明:
- 什么时候生成。
- 是否已经执行。
- 是否允许重复下单。
- 目标仓位是多少。
- 现金不足时如何处理。
- 信号过期后是否自动撤销。
这些信息缺失后,事件驱动执行层只能自行猜测。
结果必须进行双重核对
同一策略在向量化和事件驱动环境中运行后,结果不应被简单要求“完全一致”。两种模型的成交假设不同,结果出现差异是正常的。
需要比较的是差异来源:
- 信号数量是否一致。
- 信号时间是否一致。
- 目标仓位是否一致。
- 成交价格差异来自何处。
- 成交数量差异来自何处。
- 手续费计算是否一致。
- 未成交订单是否被错误计入。
- 组合净值差异从哪一个时间点开始出现。
可以把回测过程拆成四组对照:
| 对照层级 | 比较内容 | 主要目的 |
|---|---|---|
| 信号层 | 信号方向、时间和数量 | 排除指标与时间对齐错误 |
| 订单层 | 提交、撤销、拒绝和重复订单 | 检查状态机 |
| 成交层 | 成交价、数量和滑点 | 检查撮合模型 |
| 账户层 | 现金、持仓、净值和风险 | 检查组合会计 |
差异从信号层开始,问题通常在数据或指标。差异只从成交层开始,问题通常在撮合和成本。差异只在账户层放大,问题可能在资金、保证金或组合计算。
这比直接比较最终收益率有效。
参数优化不能掩盖架构错误
向量化回测特别适合参数扫描。也因此更容易制造过拟合。
当参数空间不断扩张,研究者会获得大量看似优秀的局部结果。30组参数并不多。加入多个指标、多个持仓周期、多个止损比例和多个样本区间后,实际试验次数可能迅速增加。
需要记录每一次参数搜索,而不是只保留最优结果。
可以观察:
- 最优参数是否位于孤立尖峰。
- 邻近参数的收益是否接近。
- 不同时间区间的最优参数是否稳定。
- 样本外表现是否保持同方向。
- 成本变化后参数是否仍然有效。
- 换手率是否随参数微调急剧变化。
- 收益是否集中在少数日期或少数标的。
参数曲面平滑,不代表策略有效。参数曲面尖锐,通常说明模型对样本噪声敏感。
更严格的做法是采用滚动训练和验证:
1. 使用历史窗口估计参数。
2. 在后续窗口进行样本外测试。
3. 按时间向前滚动。
4. 汇总每个测试窗口的独立结果。
5. 比较样本内与样本外差异。
6. 在事件驱动环境中重新验证执行细节。
不要用全历史数据直接选择参数,再声称完成样本外检验。
最终判断:研究速度和交易真实性属于不同指标
向量化回测的优势是计算吞吐量。它适合因子研究、规则验证和大规模参数扫描。NumPy、Pandas、Polars和VectorBT可以显著降低研究阶段的迭代成本。
它的主要缺陷是执行过程容易被压缩成几列数组。未来函数、同K线成交、忽略滑点、理想化持仓和缺少订单状态,都会让结果偏离实际。
事件驱动回测的优势是逻辑边界清晰。它通过事件、订单和成交状态,模拟策略从信号到执行的完整链路。Backtrader、Zipline、vn.py或自研事件引擎,都可以承载更复杂的资金管理和撮合规则。
它的主要缺陷是计算成本高,系统实现复杂,数据准备要求更严格。逐事件执行并不自动保证结果正确。错误的时区、错误的K线合成、错误的滑点模型,仍然会产生错误结论。
因此,量化回测系统设计可以遵循一个简单原则:
- 信号研究优先使用向量化。
- 执行验证优先使用事件驱动。
- 高频、跨周期和复杂资金管理直接进入事件驱动验证。
- 研究层与执行层必须通过明确的数据接口连接。
- 最终决策不能只看净值曲线。
- 参数优化必须配合样本外测试和成本敏感性分析。
- 回测结果只代表历史模拟条件下的结果,不代表未来实盘收益。
系统的目标不是让回测跑得最快,也不是让代码看起来最复杂。
目标是明确:哪些部分被计算了,哪些部分被模拟了,哪些部分仍然没有被建模。
参数优化可以从较小搜索空间开始。先测试参数稳定性,再增加维度。撮合模型可以逐级提高。先处理时间戳和信号边界,再加入滑点、部分成交和订单延迟。不要用更复杂的框架修补未经验证的数据。
最终保留下来的,通常不是收益率最高的那条曲线,而是在数据、时间、成本和执行约束改变后,仍然没有立即失效的那组逻辑。
Related reading: 极速柜台真的比普通CTP快吗:量化交易柜台的选择与延迟实测.
