模式搜索的暴力方法(第六部分):循环优化·综合运用
(3/3)·从想法到实盘维护,九步常规流程如何靠算法压缩一个数量级人力
多数交易者把优化当成偶尔点一下终端按钮的动作,却没意识到想法生成、代码改写、持续重优化和EA筛选本可以串成一条自动流水线。当计算资源到位,手工介入反而成了链路里最慢的瓶颈。这一篇把前两部分铺好的零件拼成完整闭环。
「在多个图表里随机挑一个写数据」
做跨图表采样时,先得知道终端里开了几张图、各自 ID 是多少。下面这段逻辑用 ChartFirst / ChartNext 遍历,排除当前图表后统计可用图表数,再用均匀随机挑一张。 随机索引靠 MathRand() 实现,它返回 0–32767 的整数,除以 32767.0 得到 [0,1] 浮点,再映射到 [start, end] 区间。注意 end-start+1 才是正确的索引个数,漏掉 +1 会少取最后一个。 SelectAnyChart 两次遍历图表:第一次只数数,第二次按 randomChartIndex 定位并填 SymbolX 和 PeriodX。若终端只开了一张图,chartCount 为 0,Randomindex(0,-1) 会越界,实盘前务必先判断图表数量。外汇与贵金属波动剧烈,这类自动选图脚本若误写当前图可能造成数据串台,建议先在模拟盘验证。
class="kw">struct ChartData { class="type">class="kw">string FileNameString; class="type">class="kw">string SymbolX; ENUM_TIMEFRAMES PeriodX; }; class="type">int Randomindex(class="type">int start, class="type">int end) { class="kw">return start + class="type">int((class="type">class="kw">double(MathRand())/class="num">32767.0)*class="type">class="kw">double(end-start+class="num">1)); } ChartData SelectAnyChart() { ChartData chosenChart; chosenChart.FileNameString = ""; class="type">int chartCount = class="num">0; class="type">long currentChartId, previousChartId = ChartFirst(); class=class="str">"cmt">// Calculate number of charts class="kw">while (currentChartId = ChartNext(previousChartId)) { if(currentChartId < class="num">0) { class="kw">break; } previousChartId = currentChartId; if (currentChartId != ChartID()) { chartCount++; } } class="type">int randomChartIndex = Randomindex(class="num">0, chartCount - class="num">1); chartCount = class="num">0; currentChartId = ChartFirst(); previousChartId = currentChartId; class=class="str">"cmt">// Select random chart class="kw">while (currentChartId = ChartNext(previousChartId)) { if(currentChartId < class="num">0) { class="kw">break; } previousChartId = currentChartId; class=class="str">"cmt">// Fill in selected chart data if (chartCount == randomChartIndex) { chosenChart.SymbolX = ChartSymbol(currentChartId);
随机挑图表的退出与回传逻辑
上面这段是遍历客户端已开图表、按随机索引抽取目标图表后的收口代码。先给抽中的图表补上周期与文件名:用 ChartPeriod 取当前图 ID 的周期存进 PeriodX,再把 SymbolX、周期经 CorrectPeriod 修正后转字符串,拼成 "DataHistory 品种 周期" 的命名,方便后续落盘或读取。 退出循环靠两个判断:一是 chartCount 超过 randomChartIndex 就 break,确保只取第 randomChartIndex 个非当前图;二是 currentChartId 不等于 ChartID() 才让 chartCount 自增,等于主动跳过主图自身。 最后 return chosenChart 把结构体交回调用方。你在 MT5 里跑这段时,若 randomChartIndex 设得比实际非主图数量还大,chosenChart 可能带回未初始化字段,建议先数一下 ChartsTotal 再定上限。外汇与贵金属图表切换频繁,多图遍历存在竞态,实盘前请在模拟盘验证。
chosenChart.PeriodX = ChartPeriod(currentChartId); chosenChart.FileNameString = "DataHistory" + " " + chosenChart.SymbolX + " " + IntegerToString(CorrectPeriod(chosenChart.PeriodX)); } if (chartCount > randomChartIndex) { class="kw">break; } if (currentChartId != ChartID()) { chartCount++; } } class="kw">return chosenChart; }
◍ 凹曲线族让余额模型更贴近实盘
本文给出的新优化标准里,曲线因子和曲线族是核心,而凹曲线族补上了正向/反向周期背景下的现实余额形态。它不像理想化曲线那样把资金增长画成平滑直线,而是把回撤与恢复的非对称结构纳入考量。 对每条曲线计算拟合因子后,自动优化器能在候选参数里筛掉那些纸面收益好、但曲线形态脆弱的设置。开发时间因此压缩,所得参数的稳健度也更高。 外汇与贵金属品种波动跳空频繁,这类高风险的真实环境里,用凹曲线族做二次过滤,比单看最终净值更能暴露过拟合倾向。开 MT5 跑自动优化时,把该因子纳入标准即可验证差异。
「相关文章与社区争论的余波」
这节原本是系列文末的链接与评论区,但里面有一条关于过拟合的实战争论值得单独拎出来。用户 mytarmailS 在 2024 年 6 月 10 日直言,前文作者推崇的暴力形态搜索本质上就是原始历史拟合(再训练),在新数据上几乎从未起作用,而他声称用模拟系统加 50 次环境复算的平均作为拟合目标,效果至少比原始拟合好十倍。 评论区另一头 Aleksey Vyazmikin 则反驳说,作者只是分享自己的视野和公式,没强塞结论,战略规则未知就谈不上盖棺。两边都没贴可复跑的代码,但「50 次模拟取均值」这个数据点可以直接搬进 MT5 的脚本里验证。 页面底部还列了同站几篇延续阅读:时间序列挖掘数据标签(两篇)、MQL5 坐标下降弹性网络回归、可移动 GUI 等,都是围绕 AI 模型喂数据和降过拟合的邻近主题。外汇与贵金属行情受杠杆与跳空影响大,任何历史拟合策略上线前都先用模拟账户跑通再谈实盘。