MetaTrader 5 里的参数优化是一次搜索:你为每个输入参数声明一个范围,策略测试器把每一种组合都跑一遍,然后按你选定的指标排好序,把一张表交到你手上。难的不是把它跑起来。难的是这张表永远有第一行,而第一行几乎永远是错的。
你从这篇文章里带走的,是一套产出决定而不是产出数字的流程:一次你守得住的搜索,一种在遇到第二段时期之后仍然成立的通过表读法,以及一条停止规则。
| 测试条件 | |
|---|---|
| 实验编号 | EXP-PARAM-SEARCH-OUTCOMES-001 |
| 上级实验 | EXP-BUILDER-TEMPLATE-BASELINE-001 |
| 来源 | ea-templates-manifest.js → bt.explored |
| 样本总体 | 8 recorded searches of the 53 measured templates |
| 品种 / 时间周期 | USDJPYm, M5 and H1 |
| 模型 | M1 OHLC (Model=1), Exness MT5, measured 2026-06-18 |
| 变动的参数 | stop loss and take profit only |
| 最近验证 | 2026-08-25 |
设置:网格、切分与数据
有三项设置决定这次搜索到底值不值得跑。把它们设错了,通过表就是一台非常昂贵的随机数发生器。
| 项目 | 位置 | 该怎么设 | 为什么 |
|---|---|---|---|
| Optimisation | Settings 标签页 | 网格小就用 Slow complete algorithm | 遗传模式只是对这个空间做抽样;12–32 种组合,你完全有余力把它们全看一遍 |
| Start / Step / Stop | Inputs 标签页,逐个输入参数 | 两个参数,粗一点的步长 | 你每勾一个输入参数,网格就乘一次。我们只动了两个 |
| Forward | Settings 标签页 | 1/2、1/3 或 1/4 | 把区间切开,让测试器对后半段单独打分——这正是你跑这次搜索要做的那项检验 |
| Optimisation criterion | Settings 标签页 | 在你看到网格之前就定下来 | 它是测试器给各次通过排序所用的那个指标,所以是它决定了哪一行才是第一行 |
| Modelling | Settings 标签页 | 先用粗模式扫,再把活下来的那个拿真实 tick 重跑 | 扫描用的模式是用来给候选排序的,绝不能用于你要发布的数字 |
| Period | Settings 标签页 | 长到能装下不止一种行情格局 | 一次只在一段趋势里做的搜索,找到的是骑上了这段趋势的那个设置 |
这个准则值得你做一个决定,而不是用默认值。按净利润排序,奖励的是冒险最多的那次通过;按基于回撤的指标排序,奖励的是交易最少的那次——恢复因子之所以存在,就是因为这两个答案彼此矛盾。我们自己的搜索压根没有按测试器的排序来判断:每一个活下来的候选,都在三段各自独立的窗口上用盈利因子打分,而其中任何一段内部的排序,从来没有决定过任何事情。
数据质量排在最前面:在坏 tick 上做的搜索,优化的是那些缺口。简短版本是:建模质量低于 90% 会让日内的通过表变得没法用,而用插值 tick 数据搭出来的运行,分辨不出一个落在K线内部的止损。
- 先按默认值跑一次回测,并且把报告留下来。没有基线,通过表就没有可以超越的对象——怎么做一次回测把那一次通过从头到尾讲了一遍。
- 在 Settings 标签页里,把 Optimisation 设成适用于小网格的完全遍历,并把 Forward 设成
1/3,让测试器把区间的最后三分之一留出来。 - 在 Inputs 标签页里只勾选你真正要测的那些参数,并给每一个都设好 Start、Step 和 Stop。两个输入参数配粗步长,胜过四个配细步长。
- 按 Start,让它跑完。把 Optimisation Results 标签页当成一张表来读,把 Optimisation Graph 当成一个形状来读——孤零零的一根尖峰是警告,一片高原才是发现。
- 挑出活下来的那些——不是冠军——把每一个都当作单次回测,在优化窗口之前的一段时期上重跑一遍。我们这组里每一条否定判定都出自这一步,而这一步也正是人们会跳过的那一步。
读结果:三段时期,而不是一段
下面是我们记录在案的这一整组搜索,按每次搜索达到的最佳样本内盈利因子排序。IS 是设置被拟合的那段时期,OOS 是留出段,prior 是这次搜索从未见过的一段更早的窗口。
| 模板 | 搜索的网格 | 最佳 IS | OOS | 此前窗口 | 判定 |
|---|---|---|---|---|---|
ichimoku | 12 种组合 × 3 段窗口 | 1.37 | 0.89 | 0.80 | no_robust_edge |
ma_crossover | 20 + 12 种组合,两个时间周期 | 1.23 | 0.89–0.94 | 0.78 | no_robust_edge |
cci_level | 12 种组合 × 3 段窗口 | 1.07 | 1.05 | 0.92 | no_robust_edge |
adx_trend | 12 种组合 × 3 段窗口 | 1.04 | 0.91 | 0.80 | no_robust_edge |
breakout | 12 种组合 × 3 段窗口 | 1.04 | 0.79–0.89 | 0.64–0.84 | no_robust_edge |
macd_signal | 12 种组合 × 3 段窗口 | — | 1.14–1.15 | 0.74–0.77 | no_robust_edge |
rsi_reversal | 12 种组合 × 3 段窗口 | 0.91 | — | — | no_robust_edge |
bb_bounce | 12 种组合 × 3 段窗口 | 0.91 | — | — | no_robust_edge |
先把第一列数字从上往下读一遍,再横着读。这一组里样本内成绩最大的那一个,崩得也最狠:ichimoku 的 1.37 掉到 0.89,再掉到 0.80。这个先后次序不是巧合——最贴合一段窗口的那个设置,按其构造方式,正是把这段窗口的噪声吸收得最多的那一个。
现在来看真正最接近可用的那个设置。它不在上面的表里,因为它从来都不是任何东西的第一行:在同一张 ichimoku 网格上,SL50/TP150 拿到了样本内 1.18、样本外 0.99、此前窗口 1.00。三段时期,全都大致持平。它被记录为最接近的候选,而且依然没有被采用,因为在三段窗口上都只是打平并不是优势——那是优势不存在这件事,被仔细地测量了出来。
与之相对,这些搜索试图超越的那些基线,落在 0.92 到 1.03 之间。没有任何一次搜索动得了一个已经发布的默认值。
要避开的陷阱
这五条底下的失败模式是同一个。过拟合不是你在一次搜索的末尾犯下的错误——它是跑一次搜索的默认结果,而三段时期的纪律之所以存在,就是为了在你据此行动之前把它显出来。
改进与迭代:改什么,以及什么时候停
改一样东西,重跑,和你留下来的那条基线比较。最省时间的顺序是:
- 先把时期放宽,再把网格放宽。 更多的行情格局胜过更多的组合。一次只覆盖一段趋势的搜索,无论精度多高,找到的都是骑上了这段趋势的那个设置。
- 然后把步长变粗,而不是精调它。 如果一个结果只在
SL47上存在,那它就不存在。 - 然后,而且只有到了这时候,才去加一个参数。 我们的搜索从来没走到这一步,因为两个参数就已经过不了三段时期这道关。
符合下面任意一条就停下来,并且把是哪一条写下来:
- 有一个幸存者过了全部三段时期。 把它发出去,并且把你搜索过的整张网格都记录下来——不只是你留下的那次通过。
- 最佳样本内成绩低于 1.0。 你得到了一个真实的答案:我们八次搜索里有两次就止步于此,而在 36 次评估之后止步于此是很便宜的。
- 幸存者总是过了一段窗口又倒在另一段。 这条规则依赖行情格局。搜得更多,只会搜出更多依赖行情格局的设置。
- 你已经开始解释为什么此前那段窗口“不算数”。 就是在那一刻,这次搜索不再是一次测试了。
一次搜索的诚实记录,是你覆盖过的范围和判定,两者放在一起。我们那八次每一次都是这样存下来的,这也正是这篇文章能够完全从它们身上写出来的原因——光存一个赢家,什么都证明不了。
下一步:先做前进测试,再做决定
优化是四步里的第二步。顺序是回测 → 优化 → 前进分析 → 模拟盘,每一步都拿掉一种不同的犯错方式。
- 拿一个你自己掌控的东西来练这个循环:在 Builder 里搭一套策略,自己去搜索它的止损和目标,因为一张你亲手声明的网格,远比一张你继承来的网格更容易读得诚实。
- 三段时期检验的正式版本是前进分析,它把切分点向前滚动,而不是固定在某一处。
- 不管这次搜索交回来的是什么,交回它的那份报告仍然得读:读懂一份 MT5 回测报告讲的是每一个头条数字实际上是在替哪一个样本总体说话。
- 想看看数字真的活下来之后,一份完成的记录长什么样,已发布的 EA每一项都带着完整的平仓交易清单和运行清单。
- 我们如何测试、打分并记录这一切,写在我们的测试方法里。