Backtest Ready 阶段 - 回测就绪验证
目录
- 阶段定义
- 为什么需要 Backtest Ready 阶段
- 核心验证内容
- Dual Engine 验证要求
- Semantic Gap 检查
- 风险评估要求
- Abnormal Performance Sanity Check
- Formal Gate 要求
- 常见错误和反模式
- 输出 Artifact 规范
- 与下一阶段的交接标准
阶段定义
**Backtest Ready(回测就绪)**是量化研究流程中,验证冻结后的交易规则在独立样本外窗口是否可交易的阶段。
核心目标
- 可交易性验证:确认策略在 Backtest 窗口上可以执行交易
- 规则完整性:验证交易规则完整且无歧义
- 双引擎一致性:确保结果不是某个回测引擎的 bug 导致
- 风险评估:评估容量、自冲击、流动性等实际交易风险
阶段定位
Test Evidence → Backtest Ready → Holdout Validation
↑
验证可交易性
Backtest Ready 是策略从”信号研究”转向”策略实现”的关键阶段。
为什么需要 Backtest Ready 阶段
问题场景:研究结论不等于可交易策略
场景 1:规则不完整
Test Evidence: 信号方向预测准确
实际交易: 缺少明确的入场、出场、仓位管理规则
结果: 无法构建可执行的交易策略
场景 2:引擎依赖性
使用单一引擎: 回测结果看起来很好
实际原因: 该引擎的 bug 或特殊假设
结果: 策略在真实环境中完全失效
场景 3:忽略成本
回测收益: 基于 spread-unit 的理想化收益
实盘现实: 交易成本吞噬所有利润
结果: 策略理论上可行,实际上不可行
Backtest Ready 的解决方案
通过 Backtest Ready 阶段,我们:
- 补充完整规则:明确入场、出场、仓位、风控规则
- 双引擎验证:使用 vectorbt 和 backtrader 两套引擎确保一致性
- 正式收益口径:基于资金记账的正式回测收益
- 评估实际风险:容量、自冲击、流动性、滑点
核心验证内容
1. 交易规则完整性
必需的交易规则组件
入场规则:
- 信号触发条件
- 入场时机(开盘/收盘/盘中)
- 入场价格(市价/限价)
- 仓位分配方式(等权重/按信号强度/按市值)
出场规则:
- 止盈条件
- 止损条件
- 时间止损(持仓周期)
- 信号反转处理
仓位管理:
- 单个标的最大仓位
- 组合最大仓位
- 杠杆使用(如有)
- 资金分配逻辑
风控规则:
- 单笔最大损失
- 日最大损失
- 最大回撤控制
- 异常情况处理规则冻结要求
来自 Test Evidence 阶段的冻结内容:
- Whitelist: 验证通过的标的白名单
- Best Horizon: 验证确定的最佳预测期
- Thresholds: 冻结的阈值、分位切点
- 质量过滤: 冻结的数据质量标准
Backtest Ready 新增冻结:
- 完整交易规则
- 参数组合
- 执行假设
- 成本模型2. 回测窗口独立性
Backtest 窗口要求:
- 必须是独立于 Train/Test 的样本外数据
- 不能参与任何规则或参数的调整
- 严格按照 Mandate 阶段的时间切分
禁止行为:
- 根据 Backtest 结果回头调整参数
- 在 Backtest 上优化交易规则
- 多次运行后选择最优结果3. 正式收益口径
收益计算要求:
- 必须基于资金记账(P&L accounting)
- 不能使用 spread-unit 冒充正式收益
- 明确初始资金
- 明确再投资假设
成本模型:
- 交易手续费
- 滑点模型
- 资金成本(如使用杠杆)
- 任何其他执行成本Dual Engine 验证要求
为什么需要双引擎
使用单一回测引擎的风险:
- 引擎 bug:特定引擎的实现错误
- 隐藏假设:引擎默认的假设可能与策略不符
- 计算差异:不同引擎对同一规则的理解可能不同
双引擎对照检查
必需的引擎
引擎 1: vectorbt
特点:
- 向量化计算,速度快
- 基于 pandas,易于数据处理
- 适合快速迭代和初步验证
引擎 2: backtrader
特点:
- 事件驱动,更接近实盘
- 支持复杂交易逻辑
- 提供更详细的交易记录双引擎对照检查表
| 检查项 | vectorbt | backtrader | 一致性要求 |
|---|---|---|---|
| 总收益率 | ✓ | ✓ | 差异 < 2% |
| 夏普比率 | ✓ | ✓ | 差异 < 0.1 |
| 最大回撤 | ✓ | ✓ | 差异 < 5% |
| 交易次数 | ✓ | ✓ | 完全一致 |
| 持仓天数 | ✓ | ✓ | 平均差异 < 1 天 |
| 逐日收益序列 | ✓ | ✓ | 相关系数 > 0.98 |
一致性验证流程
步骤 1: 确保输入一致
- 两引擎使用相同的数据
- 两引擎使用相同的参数
- 两引擎使用相同的交易规则
步骤 2: 运行双引擎回测
- vectorbt: 向量化快速回测
- backtrader: 事件驱动详细回测
步骤 3: 逐项对比检查
- 收益指标对比
- 风险指标对比
- 交易统计对比
- 逐日收益序列对比
步骤 4: 调查差异
- 如果发现显著差异
- 追踪差异来源
- 确认哪个引擎实现正确
- 或发现需要明确规则
步骤 5: 记录验证结果
- 一致性验证报告
- 任何有解释的差异
- 确认策略可以进入下一阶段差异处理原则
可接受的差异:
- 计算精度导致的微小差异
- 取整或时间戳处理导致的差异
- 有明确合理解释的差异
不可接受的差异:
- 交易规则理解不同
- 时间对齐问题
- 成本计算差异
- 未知来源的差异
处理方式:
- 不可接受的差异必须解决
- 不能假设某个引擎正确
- 需要手动验证或第三方验证
- 解决后才能宣布 Backtest ReadySemantic Gap 检查
什么是 Semantic Gap
**Semantic Gap(语义差异)**指不同回测引擎对同一策略的理解和实现不一致。
常见的语义差异来源
时间语义:
- 信号时间 vs 执行时间
- 当日收盘信号何时执行
- T+1 vs T+0 执行假设
成交假设:
- 市价单成交价格假设
- 限价单成交概率假设
- 部分成交处理
仓位计算:
- 基于总资产 vs 基于可用资金
- 杠杆计算方式
- 再投资假设
成本计算:
- 手续费计算基数
- 滑点模型假设
- 资金成本计算方式检查方法
逐笔检查(Spot Check)
选择检查样本:
- 随机选择 5-10 个代表性交易
- 包含不同类型的交易(盈利/亏损/持仓时间长/短)
检查内容:
- 入场时间是否一致
- 入场价格是否一致
- 持仓数量是否一致
- 出场时间是否一致
- 出场价格是否一致
- 该笔交易盈亏是否一致
记录方式:
- 创建对照表格
- 标记差异项
- 分析差异原因逐日检查(Spot Check)
选择检查样本:
- 随机选择 5-10 个代表性日期
- 包含市场正常日、波动剧烈日
检查内容:
- 当日持仓是否一致
- 当日交易是否一致
- 当日盈亏是否一致
- 当日总资产是否一致
记录方式:
- 创建对照表格
- 标记差异项
- 分析差异原因检查记录模板
## Semantic Gap 检查记录
### 逐笔检查
| 交易ID | 入场时间 | 入场价格 | 出场时间 | 出场价格 | vectorbt盈亏 | backtrader盈亏 | 差异 | 原因 |
|--------|----------|----------|----------|----------|--------------|----------------|------|------|
| T001 | 2024-01-05 | 100.5 | 2024-01-10 | 105.2 | 467 | 465 | 2 | 取整差异 |
| T002 | ... | ... | ... | ... | ... | ... | ... | ... |
### 逐日检查
| 日期 | 开仓持仓 | 当日交易 | 当日盈亏 | vectorbt总资产 | backtrader总资产 | 差异 | 原因 |
|------|----------|----------|----------|----------------|------------------|------|------|
| 2024-01-10 | BTC, ETH | 无 | +520 | 10520 | 10518 | 2 | 取整差异 |
| 2024-01-11 | ... | ... | ... | ... | ... | ... | ... |
### 结论
- [ ] 两引擎语义一致
- [ ] 存在可解释的差异(列明原因)
- [ ] 存在不可接受的差异(需要解决)风险评估要求
1. Capacity(容量)评估
定义
策略能够容纳的资金规模上限。
评估方法
流动性约束:
- 各标的日均交易量
- 策略交易量占市场交易量的比例
- 建议参与率 < 1%
自冲击评估:
- 策略交易对价格的影响
- 大额订单的滑点成本
- 分批执行的必要性
容量瓶颈识别:
- 找出容量瓶颈标的
- 评估去掉瓶颈标的后策略是否仍然有效
- 决定是否剔除瓶颈标的
容量结论:
- 给出策略容量上限
- 说明达到容量时的收益衰减情况容量评估示例
# 伪代码示例
def estimate_capacity(universe, participation_rate=0.01):
"""
估算策略容量
参数:
universe: 标的列表
participation_rate: 目标市场参与率(默认1%)
返回:
capacity_estimate: 容量估算(美元)
bottleneck_symbols: 容量瓶颈标的
"""
capacity_estimates = []
for symbol in universe:
daily_volume = get_avg_daily_volume(symbol, backtest_window)
symbol_capacity = daily_volume * participation_rate
capacity_estimates.append(symbol_capacity)
# 策略容量受限于最小容量标的
overall_capacity = min(capacity_estimates)
# 识别瓶颈
bottleneck_symbols = [
s for s, c in zip(universe, capacity_estimates)
if c == overall_capacity
]
return overall_capacity, bottleneck_symbols2. Self-impact(自冲击)评估
定义
策略自身交易对价格的冲击,规模增大后收益会被成本吞噬。
评估方法
分规模测试:
- 小规模: 1万-10万美元
- 中规模: 10万-100万美元
- 大规模: 100万-1000万美元
对比指标:
- 收益率衰减
- 滑点成本增加
- 夏普比率下降
评估结论:
- 找出收益开始显著衰减的规模点
- 作为建议的容量上限自冲击评估示例
## Self-impact 评估结果
| 资金规模 | 年化收益 | 滑点成本 | 夏普比率 | 收益衰减 |
|----------|----------|----------|----------|----------|
| 1万 | 25% | 0.5% | 1.8 | 基准 |
| 10万 | 23% | 1.2% | 1.6 | -8% |
| 50万 | 18% | 3.5% | 1.2 | -28% |
| 100万 | 12% | 6.8% | 0.8 | -52% |
**结论**: 策略容量上限约 20万美元,超过此规模收益快速衰减。3. 流动性评估
流动性指标:
- 日均交易量
- 买卖价差
- 深度数据
流动性风险:
- 某些时段流动性枯竭
- 市场剧烈波动时流动性下降
- 小市值币种流动性不足
应对方案:
- 流动性过滤条件
- 分批执行策略
- 避开低流动性时段4. 滑点评估
滑点模型:
- 基于买卖价差的滑点估计
- 基于历史执行的滑点分析
- 大额订单的额外滑点
滑点成本:
- 单笔交易平均滑点
- 策略总滑点成本
- 滑点对收益的影响
滑点控制:
- 限价单策略
- 分批执行
- 避开波动剧烈时段Abnormal Performance Sanity Check
触发条件
当回测收益明显好得不正常,超出常识范围时,必须触发异常收益复核。
触发信号:
- 年化收益 > 50%
- 夏普比率 > 3
- 胜率 > 80%
- 回撤极小但收益很高
- 收益曲线过于平滑检查内容
1. 前视偏差检查
检查项目:
- 是否使用了未来数据
- 信号计算是否使用了当日收盘价
- 交易执行时间是否合理
- 是否有时间对齐问题
常见问题:
- 用当日收盘价做当日交易决策
- 用后发布的宏观数据
- 用未来公布的财报数据
- 时间戳对齐错误2. 成本检查
检查项目:
- 交易成本是否合理
- 滑点假设是否保守
- 是否遗漏重要成本
常见问题:
- 忽略交易手续费
- 假设零滑点
- 忽略资金成本
- 忽略市场冲击成本3. 异常 Bar 检查
检查项目:
- 是否有异常高收益的单一时间段
- 是否有异常大笔交易
- 收益是否集中少数交易
分析方法:
- 按月/按周分析收益分布
- 识别贡献最大的前10笔交易
- 分析收益集中度
常见问题:
- 收益来自少数异常时间段
- 单笔大额交易贡献大部分收益
- 特殊市场环境下的一次性收益4. 收益集中度检查
检查项目:
- 收益是否集中在少数标的
- 收益是否集中在少数时间段
- 收益是否集中在少数交易
分析方法:
- 计算收益的基尼系数
- 分析标的收益贡献分布
- 分析时间收益贡献分布
常见问题:
- 某个标的贡献大部分收益
- 某个月份贡献大部分收益
- 策略实际是不可分散的5. 多引擎一致性检查
检查项目:
- vectorbt 和 backtrader 结果是否一致
- 如果不一致,哪个更可信
分析价值:
- 如果两引擎差异很大
- 说明可能存在实现问题
- 需要深入调查原因检查记录
## Abnormal Performance Sanity Check
### 触发原因
- 年化收益: 58%(阈值 50%)
- 夏普比率: 3.2(阈值 3)
### 检查结果
#### 前视偏差检查
- [ ] 未发现前视偏差
- [ ] 信号计算使用 T-1 数据
- [ ] 交易执行时间合理
#### 成本检查
- [ ] 交易成本合理
- [ ] 滑点假设保守(0.1%)
- [ ] 包含所有成本
#### 异常 Bar 检查
- ⚠️ 收益集中在 2024-03(贡献 40%)
- [ ] 需要分析该月份特殊情况
#### 收益集中度检查
- [ ] 收益分散度良好
- [ ] 前5大标的贡献 < 50%
#### 多引擎一致性
- [ ] vectorbt 和 backtrader 一致
- [ ] 差异在可接受范围内
### 结论
- 需要调查 2024-03 的异常收益
- 其他检查通过
- 建议进入 Holdout 验证Formal Gate 要求
Formal Gate 是硬性要求,不满足不能宣布 Backtest Ready。
Gate 必需项
FG-1: 交易规则完整冻结
检查标准:
- 入场规则明确无歧义
- 出场规则明确无歧义
- 仓位管理规则明确
- 风控规则完整
验收方式:
- 规则文档审查
- 不同人能根据规则得到相同实现FG-2: 双引擎验证完成
检查标准:
- vectorbt 回测完成
- backtrader 回测完成
- 两引擎结果一致性验证通过
验收方式:
- 双引擎结果对比报告
- 一致性指标符合要求FG-3: Semantic Gap 检查完成
检查标准:
- 完成逐笔 spot check
- 完成逐日 spot check
- 无不可接受的语义差异
验收方式:
- Semantic Gap 检查记录
- 差异有合理解释或已解决FG-4: 风险评估完成
检查标准:
- 容量评估完成
- 自冲击评估完成
- 流动性评估完成
- 滑点评估完成
验收方式:
- 风险评估报告
- 容量上限明确FG-5: 异常收益检查(如触发)
检查标准:
- 如果收益异常高,完成 sanity check
- 未发现严重问题
验收方式:
- Abnormal Performance Sanity Check 报告
- 问题已解释或解决FG-6: 输出 Artifact 完整
检查标准:
- 机器可读产物完整
- 人类可读产物完整
- field_dictionary 完整
验收方式:
- 文件存在性检查
- 格式验证Gate 决策术语
PASS:
所有 FG 满足,可以进入 Holdout Validation
CONDITIONAL PASS:
核心要素满足,次要问题可以后续补充
必须明确列出条件
RETRY:
存在可以修复的问题,需要修改后重新提交
NO-GO:
策略不可交易,不建议继续常见错误和反模式
错误 1:单一引擎回测
反模式:
# 只使用一个引擎
results = vectorbt.backtest(signal, rules)
# 直接宣布策略有效为什么错误:
- 可能是引擎的 bug 或特殊假设导致的好结果
- 无法验证结果的可靠性
正确做法:
# 使用两个引擎
vbt_results = vectorbt.backtest(signal, rules)
bt_results = backtrader.backtest(signal, rules)
# 验证一致性
assert_results_consistent(vbt_results, bt_results)错误 2:忽略 Semantic Gap
反模式:
两引擎结果略有差异
假设 vectorbt 正确
直接继续
为什么错误:
- 差异可能代表规则理解不同
- 实盘可能完全不同
正确做法:
两引擎有差异
逐笔、逐日 spot check
找出差异原因
解决后才继续
错误 3:不评估容量
反模式:
回测收益很好
直接宣布策略可交易
不考虑规模问题
为什么错误:
- 小资金可行,大资金完全不行
- 实盘资金规模可能远超容量上限
正确做法:
回测收益好
评估容量上限
评估自冲击
明确建议规模
错误 4:异常收益不检查
反模式:
年化收益 80%
夏普比率 4
太好了!直接通过
为什么错误:
- 异常好往往意味着有问题
- 可能是前视、bug、或数据问题
正确做法:
年化收益 80%
触发 sanity check
检查前视、成本、异常 bar
确保没有问题
错误 5:使用 spread-unit 冒充正式收益
反模式:
# 使用价差单位计算收益
returns = (sell_price - buy_price) / buy_price
# 声称这是回测收益为什么错误:
- 没有考虑资金分配
- 没有考虑交易成本
- 不能反映真实资金增长
正确做法:
# 基于资金记账
initial_capital = 100000
for trade in trades:
capital -= trade.cost
capital += trade.pnl输出 Artifact 规范
必需的输出文件
1. 机器可读产物
backtest_vectorbt.parquet:
用途: vectorbt 回测结果
粒度: 逐日或逐笔
主键: [timestamp, symbol]
消费者: 对比分析、报告生成
backtest_backtrader.parquet:
用途: backtrader 回测结果
粒度: 逐日或逐笔
主键: [timestamp, symbol]
消费者: 对比分析、报告生成
dual_engine_comparison.csv:
用途: 双引擎对比结果
内容: 关键指标对比、差异分析
消费者: 一致性验证
semantic_gap_checks.csv:
用途: Semantic Gap 检查记录
内容: 逐笔、逐日检查结果
消费者: 质量保证
risk_assessment.json:
用途: 风险评估结果
内容: 容量、自冲击、流动性、滑点
消费者: 决策支持
trading_rules.yml:
用途: 冻结的交易规则
内容: 入场、出场、仓位、风控规则
消费者: Holdout Validation2. 人类可读产物
backtest_validation_report.md:
用途: Backtest Ready 验证报告
内容: 按"验证报告模板"撰写
消费者: 团队评审、决策参考
gate_decision.md:
用途: 门禁决策文档
必需字段:
- stage: "BacktestReady"
- status: "PASS" / "CONDITIONAL PASS" / "NO-GO"
- decision_basis: [决策依据]
- frozen_scope: [确认冻结的内容]
- next_steps: [下一步行动]
field_dictionary.md:
用途: 解释机器产物里的字段
最低要求: 字段名、类型、含义、单位、是否可空
消费者: 新成员理解数据结构
artifact_catalog.md:
用途: 列出阶段所有关键产物
内容: 文件名、用途、粒度、主键、消费者
消费者: 产物导航
negative_results/:
用途: 保存失败的参数、失败的 gate 记录
重要性: 避免幸存者偏差Backtest Ready 验证报告模板
# Backtest Ready 验证报告
## 基本信息
- **Lineage ID**: [谱系标识]
- **Run ID**: [运行标识]
- **Backtest 窗口**: [起始日期] - [结束日期]
- **验证时间**: [时间戳]
## 验证参数
- **参数组合**: [Param ID]
- **交易规则**: [规则版本]
- **Universe**: [标的数量]
- **初始资金**: [金额]
## Dual Engine 验证
### 关键指标对比
| 指标 | vectorbt | backtrader | 差异 | 一致性 |
|------|----------|------------|------|--------|
| 总收益率 | | | | |
| 夏普比率 | | | | |
| 最大回撤 | | | | |
| 交易次数 | | | | |
### 一致性结论
- [ ] 两引擎结果一致
- [ ] 存在可解释的差异
- [ ] 存在不可接受的差异(需解决)
## Semantic Gap 检查
- [ ] 逐笔检查完成
- [ ] 逐日检查完成
- [ ] 无不可接受的语义差异
## 风险评估
### 容量评估
- 策略容量上限: [金额]
- 容量瓶颈标的: [列表]
- 收益衰减情况: [描述]
### 自冲击评估
- 小规模表现: [描述]
- 中规模表现: [描述]
- 大规模表现: [描述]
- 建议规模: [金额]
### 流动性评估
- 流动性良好: [是/否]
- 流动性风险: [描述]
- 应对方案: [描述]
### 滑点评估
- 平均滑点: [百分比]
- 滑点成本: [金额]
- 滑点对收益影响: [描述]
## Abnormal Performance Check
- [ ] 未触发(收益正常)
- [ ] 触发但检查通过
- [ ] 触发且发现问题
## 结论
**Verdict**: [PASS / CONDITIONAL PASS / NO-GO]
**决策依据**:
- [列出关键判断依据]
**冻结内容**:
- 交易规则
- 参数组合
- 执行假设
- 成本模型
**下一步**:
- [通过后] 进入 Holdout Validation
- [未通过] 触发 Rollback 或 Child Lineage与下一阶段的交接标准
Holdout Validation 的输入要求
Backtest Ready 完成后,Holdout Validation 需要明确的输入:
交接清单
| 项目 | 交付物 | 格式 | 用途 |
|---|---|---|---|
| 交易规则 | trading_rules.yml | YAML | 指导 Holdout 执行 |
| 参数组合 | risk_assessment.json | JSON | Holdout 使用参数 |
| Universe | frozen_spec | 文件 | 交易标的范围 |
| 执行假设 | backtest_validation_report.md | Markdown | 执行语义说明 |
| 成本模型 | risk_assessment.json | JSON | 成本计算说明 |
交接验收标准
Holdout Validation 可以开始的条件:
✅ 交易规则完整冻结
✅ 参数组合明确
✅ 双引擎验证通过
✅ 风险评估完成
✅ 所有 artifact 完整
验收方式:
- 规则文档审查
- 参数配置验证
- Artifact 完整性检查
Gate 决策:
Backtest Ready PASS → 可以开始 Holdout Validation
Backtest Ready CONDITIONAL PASS → 满足条件后开始
Backtest Ready RETRY → 修改后重新提交
Backtest Ready NO-GO → 终止当前研究方向Frozen Spec 的传递
Backtest Ready Frozen Spec:
包含内容:
- 完整交易规则(入场、出场、仓位、风控)
- 参数组合(来自 Test Evidence)
- Whitelist(来自 Test Evidence)
- Best Horizon(来自 Test Evidence)
- 执行假设
- 成本模型
传递方式:
- trading_rules.yml 作为 Holdout 的输入
- Holdout 只能验证,不能修改
违反后果:
- 如果 Holdout 修改了冻结内容
- 整条研究线失效
- 需要从 Backtest Ready 重新开始总结:Backtest Ready 的核心价值
防止什么
- 不可交易策略:防止将无法执行的信号策略投入实盘
- 引擎依赖性:防止因某个引擎的 bug 导致的错误结论
- 语义误解:防止对策略规则的不同理解导致实盘失败
- 容量误判:防止小资金可行但大资金失败的策略
- 异常收益陷阱:防止因前视、bug 等导致的虚假好收益
确保什么
- 规则完整:入场、出场、仓位、风控规则明确
- 结果可靠:双引擎验证确保不是 bug
- 语义一致:对策略规则的理解一致
- 风险明确:容量、自冲击、流动性、滑点评估清楚
- 收益真实:异常收益经过 sanity check
成功的 Backtest Ready 特征
一个成功的 Backtest Ready 应该:
规则完整:
- 不同人能根据规则得到相同实现
- 没有模糊或歧义的地方
验证充分:
- 双引擎都完成回测
- 一致性验证通过
- Semantic Gap 检查完成
风险清楚:
- 容量上限明确
- 自冲击评估清楚
- 流动性风险明确
- 滑点成本合理
收益真实:
- 使用正式资金口径
- 异常收益经过检查
- 没有发现严重问题学习要点
核心原则
- 双引擎必须:单一引擎结果不可信
- 语义要对齐:确保对规则理解一致
- 风险要评估:容量、自冲击、流动性、滑点
- 异常要检查:异常好往往有问题
- 冻结即冻结:Holdout 不能修改任何内容
常见疑问
Q:为什么必须用两个引擎? A:单一引擎可能有 bug 或特殊假设。双引擎确保结果可靠。
Q:两引擎结果略有差异怎么办? A:需要逐笔、逐日 spot check,找出差异原因,确保没有语义误解。
Q:如何评估策略容量? A:通过各标的流动性、市场参与率、自冲击评估,找出容量上限。
Q:异常收益一定是问题吗? A:不一定,但必须触发 sanity check 确保没有前视、bug、数据问题。
Q:Backtest Ready 和 Test Evidence 的区别? A:Test Evidence 验证信号有效性,Backtest Ready 验证策略可交易性。
文档版本: v1.0 最后更新: 2026-03-26 维护者: 量化研究团队