一份 MT5 回测报告,说的是某一批具体的交易在某一段具体的价格历史上跑出来的结果。几乎所有的误读,都来自把这句话丢掉一半。头条上的盈利因子被当成了智能交易系统的属性。它其实是另外两样东西的属性:这份报告覆盖的那批交易,以及测试器被喂进去的那些 tick。
这篇文章讲的是那套能产出决定的阅读顺序:报告在打印任何东西之前假定了什么,哪个指标回答哪个问题,每个数字会在哪里骗你,以及每一种读法在告诉你去改什么。产出一份报告是另一件活——怎么做一次回测把那一半从头到尾讲了一遍。
| 测试条件 | |
|---|---|
| 实验编号 | EXP-REPORT-READING-001 |
| 上级实验 | EXP-BACKTEST-RUNBOOK-001 |
| 来源 | data/run-manifests/*.json → results, ledger_recomputed, shadow_runs |
| 样本总体 | all 23 runs published on mt5depot at the time of derivation |
| MT5 版本号 | 6090 and 6140 |
| 模型 | Every tick generated from M1 bars (Model 0) and Every tick based on real ticks (Model 4) |
| 账户 | 10,000 USD deposit on all 23 runs |
| 最近验证 | 2026-08-26 |
下面每一个数字都出自回测,而这 23 次运行全部带着 PASS 判定——它们是越过了上架关卡的那些运行。所以这是一组幸存者,这里没有任何内容能说明一次回测通过的概率有多大。它说的是:一份通过了的报告,从内部看是什么样子。
设置:报告在打印第一个数字之前假定了什么
MT5 报告顶端的 Settings 区块不是开场白。它是底下每一个数字都继承下来的假设清单,而其中有六项决定了剩下的部分值不值得读。经纪商名称和终端版本号写在报告自己的标题行里——我们这份读作 Exness-MT5Trial5 (Build 6090)。
| Settings 项 | 它真正钉死了什么 | 我们这组记录的是 |
|---|---|---|
Symbol: / Period: | 这个结果是哪些行情格局的一个样本 | 22 次运行从 2019 年 1 月开始;cairn 从 2021 年 6 月开始 |
| 模型(tick 生成方式) | 每根K线内部的 tick 是怎么造出来的 | 12 次运行用 Model 0(由 M1 K线生成),11 次用 Model 4(真实 tick) |
Initial Deposit: | 页面上每一个百分比的分母 | 23 次全部是 10,000 USD |
| 点差 | 每一条腿上被扣掉的成本 | 23 次里只有 1 次真正测过——其余的都继承了价格历史自带的那个 |
| 手续费 | 只有你自己设了,测试器才会施加的一项成本 | 23 次全部为 0 |
Inputs: | 产生这份结果的那一整套设置,一个不漏 | 每一次运行都对着报告核实过 |
Inputs: 这一行是人们会跳过的一行,而它恰恰是让一份报告真正可复现的那一行:它是你要把同一个页面拿回来,就必须重新录入的那一整套完整取值。
其中两行值得停一下。手续费那一行写着零,不等于手续费被忽略了。它的意思是被测品种上没有收取手续费。这是两句不同的话,而只有运行记录才能告诉你适用的是哪一句。另外,一个没测过的点差不是零点差:我们 23 次运行里有 22 次这一栏是空的,因为测试期间没有任何记录器在旁边运行。每一条腿就是拿了 M1 历史数据自带的那个点差。只有 tidewell-slack 能说出自己的均值,19.14 点。
这里还有一个命名陷阱。老一些的指南叫作建模质量的那一栏,MT5 打印出来的名字是 History Quality:,位置在 Results 区块里,紧挨着 Bars:、Ticks: 和 Symbols:。在一份 Build 6090 的报告里搜 “modelling quality”,你什么也搜不到。在我们自己的记录里,23 份清单中只有 2 份带着这个数字,因为它只在源报告写明了的时候才会被保留下来——这是这批记录的一个属性,而不是对 MetaTrader 打印它的频率的测量。实际的后果是:对于不是你自己生成的报告,你没法拿它当筛选条件。它底下真正的那个问题是 tick 数据的来源,而那个问题永远有答案:去问这次运行用的是哪一份历史数据。
逐个指标读这份报告
按这个顺序读这一页。它刻意不是 MetaTrader 打印的顺序,因为两个最省事的否决项都待在报告的底部。
- 先读
Settings。模型、Initial Deposit:、点差和手续费。底下每一个百分比都继承它们,而一次点差没被测过的运行,不是一次没有点差的运行。 - 在任何比率之前,先读
Total Trades:。一个比率和它的样本量是一个事实,不是两个。把笔数写在比率旁边。 - 问一句:头条覆盖的到底是哪些交易。如果旁边一并发布了成交清单,就检查它的总数是否和
Total Trades:对得上。我们自己那 23 份报告里有一份对不上。 - 读
Equity Drawdown Maximal:,而不是余额那一行,并且记下你取的是Maximal还是Relative那个数字——它们是分开的两行。 - 找到价格历史。哪家经纪商、哪个来源、哪一段时期。在我们的记录里,这才是那个改变了判定的字段;tick 模型不是。
下面这张表把整套读法放在一起,用的是报告真正打印出来的那些标签。“在我们这组里”这一列,是每个指标在 23 次已发布运行上的实际表现。它比教科书上的区间更管用,因为它测的就是你手上拿着的这一类报告。
| 报告标签 | 它回答的问题 | 在我们这组里 | 危险信号 |
|---|---|---|---|
Total Trades: | 证据有多少 | 每次运行 108 到 4,725 笔 | 低于约 100;20 笔交易上的比率是传闻 |
Profit Factor: | 毛利润除以毛亏损(盈利因子) | 23 次全部落在 1.22 到 1.59 之间 | 在一段很短的窗口上高于约 2.0;先看 Total Trades: |
Profit Trades (% of total): | 胜率——分布的形状,不是它的正负号 | 30.80% 到 82.27%,全部盈利 | 单独引用,旁边不放盈利因子 |
Total Net Profit: | 赢到的钱,还没有放进语境里 | 同样的 10,000 USD 入金上,386.05 到 28,687.43 USD | 引用时不带 Initial Deposit: 和年数 |
Balance Drawdown Maximal: | 已平仓交易上最糟的一段下探(最大回撤) | 0.67% 到 18.24% | 同一页上明明有净值那一行,却引用了这一行 |
Equity Drawdown Maximal: | 把未平仓持仓算在内最糟的一段下探 | 23 次里 23 次都比余额那条更深 | 被忽略——你的保证金活在这个数字上 |
Expected Payoff: | 每笔交易的平均结果,以货币计 | 我们的清单里没有携带 | 被当成预测来读,而不是平均值 |
Recovery Factor: / Sharpe Ratio: | 每单位痛苦换来的回报,两种算法 | 我们的清单里没有携带 | 拿去和交易笔数不同的报告比较 |
History Quality: | tick 序列能不能分辨出你的止损 | 23 次里有 2 次写明 | 既缺席而且数据来源也不明 |
那个区块里有两个惯例,会在任何解读开始之前就把人绊倒。
Total Trades: 和 Total Deals: 是两个不同的计数。在 MetaTrader 5 里,一个来回是两笔 deal——一进一出——所以一份写着 Total Trades: 50 的报告,旁边会写着 Total Deals: 100,而部分平仓会增加 deal 却不增加 trade。比率要对着 trade 读,绝不能对着 deal 读。
回撤一共有六行,不是一行。报告会为余额和净值各打印 Absolute、Maximal 和 Relative。更糟的是,其中两行里金额和百分比互换了位置:Balance Drawdown Maximal: 36.84 (0.37%) 把货币放在前面,而 Balance Drawdown Relative: 0.37% (36.84) 把百分比放在前面。两份报告可以分别从相邻的两行里引用 “0.37%” 和 “36.84”,说的是同一件事——也可能是两件不同的事。
Results 区块剩下的部分——Z-Score:、AHPR:、GHPR:、LR Correlation:、LR Standard Error:、Margin Level: 以及 MFE/MAE 相关系数——描述的是资金曲线的形状,而不是它的大小。它们没有一个能救回一份交易笔数太少的报告,也没有一个在价格历史更换之后活得比盈利因子更久。请在上面那五步之后再读它们,或者干脆不读。
指标里有两行在实践中造成的伤害最大,所以请把它们放在一起读,而不是先后读。
净利润需要它的分母和它的日历。我们这 23 次运行全部从同样的 10,000 USD 起步,这让它们出奇地可比。它们的年化成绩依然跨越了 0.51% 到 57.38%。低的那一端很有教育意义。orrery 的盈利因子读作 1.46,最大回撤 0.67%——整个目录里最好看的一对数字。它在 7.58 年里挣了 386.05 USD。这份报告没有任何不诚实的地方。它回答的问题,和大多数读者以为自己在问的那个问题,不是同一个。
胜率和盈利因子在这里几乎是彼此独立的。在这 23 次已发布运行上,两者的相关系数是 0.37。因此,决定一个 EA 到底赚不赚钱的绝大部分因素,在胜率那一行里是看不见的。nautical 赢下 30.80% 的交易,盈利因子 1.22;gyre 赢下 82.27%,盈利因子 1.59。两个都盈利,而胜率相差 51 个百分点。
你的报告没给你看的那个盈利因子
这一部分是没有任何报告会给你看的,而这也正是我们能用自己的数据写出这篇文章的原因。每一次已发布的运行都保留着完整的平仓交易清单,所以每一份报告都能一分为二。一边是 EA 被挑选出来的那段切片——上架关卡据以判定的那段开发窗口。另一边是它上线之后发生的那些交易,没有任何东西是在它们身上被挑选出来的。我们 23 次运行里有 20 次同时公布了两段切片;另外三次完全没有上架后的切片。
| EA | 开发切片 | 上架后切片 | 头条 |
|---|---|---|---|
orrery | 1.28(195 笔) | 6.43(15 笔) | 1.46(210 笔) |
windrose | 1.31(101 笔) | 3.58(7 笔) | 1.38(108 笔) |
cairn | 1.48(4,583 笔) | 1.64(142 笔) | 1.48(4,725 笔) |
gyre | 1.55(136 笔) | ——(5 笔,零亏损单) | 1.59(141 笔) |
tessera | 1.28(624 笔) | 0.88(21 笔) | 1.27(645 笔) |
zerqon | 1.53(232 笔) | 0.72(21 笔) | 1.43(253 笔) |
把 orrery 那一行的第一列和最后一列放在一起读。头条说 1.46;EA 真正被挑中的那段时期说 1.28;差别就是那 15 笔交易——占全部记录的 7%——跑出了 6.43 的盈利因子。用同样的方式读 zerqon 那一行,方向正好相反:开发切片 1.53,上架之后那 21 笔是 0.72,而 1.43 的头条把两者都藏了起来。
在公布了两段切片的那 20 次运行里,头条比开发切片更好看的有 14 次,更差的有 6 次。另外三次是有意被排除在外的:它们只有一段切片,所以它们的头条和它们的开发数字覆盖的是完全相同的那批交易,两者之间的差别根本不是样本总体效应——那只是报告自己保留两位小数,与重算出来的成交清单之间的差。almanac 打印的是 1.52,而清单重算出来是 1.5153。把同样这条四舍五入的下限套到那 20 次上,其中 13 次的差距依然大到四舍五入解释不了,其中 8 次是往好看的方向。
这种不对称不是丑闻。一个横跨两段时期的头条,会被其中运气更好的那一段拖过去。它的意思只是:当你要拿一个数字去对照关于未来表现的说法时,头条永远不是那个数字。
陷阱:这些数字是怎么误导人的
这五条底下的失败模式是同一个:一份报告是对一个样本总体的测量,而页面上的每一个指标,都在不声不响地继承测试器当时被指向的那个样本总体。
改进:每一种读法在告诉你去改什么
每次迭代只改一样东西,并且每次都重读同样这三个数字:交易笔数、盈利因子和净值回撤。下面的顺序是按成本排的——便宜的检查放在前面,因为其中两项经常直接把调查结束掉。
- 如果交易笔数很少,就把时期拉长——别去动参数。一个建立在大约 100 笔以下交易上的盈利因子,从一段更长的窗口里得到的变化,比你能调的任何设置都大。我们已发布的运行里最小的一次有 108 笔交易,而它也正是我们引用比率时最小心的那一次。
- 如果头条和开发切片对不上,就只在开发切片上重读一遍。那才是设置据以挑选出来的那个数字。它才是拿去和任何其他候选比较的那一个。
- 如果净值回撤明显高于余额回撤,就按净值那个数字来定仓位。这个差距告诉你 EA 会在同一段行情里持有多少个仓位。chrysalis 那次运行直说了:最多同时七个。
- 如果这份报告来自别人的数据,那就先在第二个来源上重跑一遍,其他都往后放。在我们整组记录里,这项检查的实测影响最大,而它是人们最后才做的那一项。
真正改变了数字的是什么:数据来源,不是 tick 模型
我们有一个 EA 被刻意重跑过,就是为了把这两个变量分开,而运行记录给每一次影子运行都标明了它隔离的是什么。
tidewell-slack 运行 | 改了什么 | 交易笔数 | 盈利因子 | 最大回撤 | 历史质量 | 判定 |
|---|---|---|---|---|---|---|
| 已发布 | Exness M1 历史数据,Model 0 | 303 | 1.35 | 9.92% | 99% | PASS |
| 影子——隔离数据来源 | Dukascopy 历史数据,Model 0 | 351 | 1.13 | 18.18% | 99% | FAIL |
| 影子——隔离真实 tick | Dukascopy 历史数据,Model 4 | 345 | 1.11 | 18.20% | 100% | FAIL |
把它当成两个独立的实验来读。只改价格历史——第一行到第二行,tick 模型相同——把盈利因子从 1.35 拉到了 1.13,回撤几乎翻倍,判定也从通过翻成了不通过。在那份新历史数据上只改 tick 模型——第二行到第三行——盈利因子只动了 0.02,回撤只动了 0.02 个百分点。而且在那两次没通过的运行上,历史质量读作 99% 和 100%,也就是说大多数人拿来筛选的那个字段,全程都很优秀。
另一个 EA 从另一个角度指向同一件事。kestrel-hover 是在 Dukascopy 真实 tick 上发布的,盈利因子 1.33,回撤 7.11%,而它在 Exness M1 历史数据、Model 0 上的影子运行读作 1.30 和 6.76%——来源和模型同时都变了,结果却几乎没动。跨数据来源的稳定性是可能的。它只是没法靠单独一份报告来证明。
实用的规则是:一份报告作为可移植证据的程度,取决于它的价格历史有多可移植。在第二个来源上重跑一遍,成本是一个晚上。在我们的记录里,这是这篇文章里唯一一项真的改变过决定的检查。
下一步:从一份报告到一个决定
把报告读好是四步里的第二步。顺序是回测 → 阅读 → 前进分析 → 模拟盘,每一步都拿掉一种不同的犯错方式。一份四步都活下来的报告,赢得了一个小仓位;只活过前两步的那份,赢得的是再做一次测试。
- 拿记录完整的东西来练。已发布的 EA每一项都带着完整的平仓交易清单和运行清单,所以你可以自己把头条重算一遍,看清楚到底是哪些交易产生了它。这是唯一一个能让这套读法真正留在手上的练习。
- 如果某个数字把你送回策略本身而不是测试,那么 Builder 才是规则本身发生改变的地方。在设置上做搜索又是另一件活,写在参数优化里。
- 在你根据刚读到的回撤数字去定任何仓位之前,EA 交易者的风险管理会把它换算成一个入金和一个手数。
- 我们如何产出、打分并记录这一切,写在我们的测试方法里。
测试器里的过往结果不是预测,上面任何一次运行都不是对未来 12 个月的承诺。把一份报告读对,目的比预测更小,也更有用。它告诉你的是:什么已经被证明了,什么只是被打印出来了。