连续前行优化 (第六部分): 自动优化器的逻辑部分和结构·综合运用
◍ 把参数落盘再拼终端配置
回测前先把 EA 参数写回文件,避免优化器读到旧值。下面这段用 FindIndex 定位变量名,命中后改 Value 再存回 botParams,最后交给 SetFileManager 落盘。 [CODE] int ind = botParams.FindIndex(x => x.Variable == item.Variable); if (ind != -1) { var param = botParams[ind]; param.Value = item.Value; botParams[ind] = param; } // Save settings to a file SetFileManager setFile = new SetFileManager(file.FullName, false) { Params = botParams }; setFile.SaveParams(); [/CODE] 逐行看:FindIndex 按 Variable 字段找下标,返回 -1 表示没匹配到;命中后取 param 副本改 Value 再写回数组,这是 C# 结构体赋值的惯用法。SetFileManager 以 false 表示不追加,直接覆盖保存。 参数落盘后紧接生成终端 config。代码从 TerminalChangeableDirectory 抓 common.ini,复制到以 TerminalID 命名的 ini,再逐项写 Tester 段:货币对、余额、延迟、EA 路径、参数文件名。 [CODE] Config config = new Config(Optimiser.TerminalManager .TerminalChangeableDirectory .GetDirectory("config") .GetFiles("common.ini") .First().FullName); config = config.DublicateFile(Path.Combine(workingDirectory.WDRoot.FullName, $"{Optimiser.TerminalManager.TerminalID}.ini")); config.Tester.Currency = optimiserInputData.Currency; config.Tester.Deposit = optimiserInputData.Balance; config.Tester.ExecutionMode = optimiserInputData.ExecutionDelay; config.Tester.Expert = optimiserInputData.RelativePathToBot; config.Tester.ExpertParameters = setFile.FileInfo.Name; config.Tester.ForwardMode = (Forward == new DateTime() ? ENUM_ForvardMode.Disabled : ENUM_ForvardMode.Custom); if (config.Tester.ForwardMode == ENUM_ForvardMode.Custom) config.Tester.ForwardDate = Forward;OnPropertyChanged("StopTest"); else config.DeleteKey(ENUM_SectionType.Tester, "ForwardDate"); config.Tester.FromDate = FromDate; config.Tester.ToDate = ToDate; config.Tester.Leverage = $"1:{optimiserInputData.Laverage}"; config.Tester.Model = optimiserInputData.Model; config.Tester.Optimization = ENUM_OptimisationMode.Disabled; [/CODE] Forward 为空日期时关前向测试并删键,否则写自定义日期;杠杆写成 1:N 字符串,优化模式显式置 Disabled——说明这套配置只跑单组回测。外汇与贵金属杠杆可调至数百倍,回测设定的 Deposit 与 Leverage 若偏离实盘账户,样本外表现可能明显漂移。
class="type">int ind = botParams.FindIndex(x => x.Variable == item.Variable); if (ind != -class="num">1) { var param = botParams[ind]; param.Value = item.Value; botParams[ind] = param; } class=class="str">"cmt">// Save settings to a file SetFileManager setFile = new SetFileManager(file.FullName, class="kw">false) { Params = botParams }; setFile.SaveParams(); Config config = new Config(Optimiser.TerminalManager .TerminalChangeableDirectory .GetDirectory("config") .GetFiles("common.ini") .First().FullName); config = config.DublicateFile(Path.Combine(workingDirectory.WDRoot.FullName, $"{Optimiser.TerminalManager.TerminalID}.ini")); config.Tester.Currency = optimiserInputData.Currency; config.Tester.Deposit = optimiserInputData.Balance; config.Tester.ExecutionMode = optimiserInputData.ExecutionDelay; config.Tester.Expert = optimiserInputData.RelativePathToBot; config.Tester.ExpertParameters = setFile.FileInfo.Name; config.Tester.ForwardMode = (Forward == new DateTime() ? ENUM_ForvardMode.Disabled : ENUM_ForvardMode.Custom); if (config.Tester.ForwardMode == ENUM_ForvardMode.Custom) config.Tester.ForwardDate = Forward;OnPropertyChanged("StopTest"); else config.DeleteKey(ENUM_SectionType.Tester, "ForwardDate"); config.Tester.FromDate = FromDate; config.Tester.ToDate = ToDate; config.Tester.Leverage = $"class="num">1:{optimiserInputData.Laverage}"; config.Tester.Model = optimiserInputData.Model; config.Tester.Optimization = ENUM_OptimisationMode.Disabled;
「把测试配置塞进终端并等它跑完」
这段逻辑干的事很直接:先把优化器要用的周期、品种、关终端标志和可视化开关写进 config.Tester,再让 TerminalManager 以普通窗口拉起 MT5 终端跑回测。 其中 ShutdownTerminal 设成 false,意味着跑完不会自动杀进程,方便你手动进终端翻日志;Visual 设 false 则跳过逐笔图形,回测速度会明显快于可视化模式。 真正卡住主线程的是 WaitForStop()——终端不关,这段代码就一直等。若终端异常卡死,调用方也会被挂住,所以外层套了 try-catch 抛异常。跑完触发 OnPropertyChanged("StopTest") 通知界面刷新按钮状态。 开 MT5 验证时,把 optimiserInputData.TF 换成 PERIOD_M15、Symb 换成 XAUUSD,就能在普通窗口看一次无图回测的全流程。
config.Tester.Period = optimiserInputData.TF; config.Tester.ShutdownTerminal = class="kw">false; config.Tester.Symbol = optimiserInputData.Symb; config.Tester.Visual = class="kw">false; class="macro">#endregion class=class="str">"cmt">// Configure the terminal and launch it Optimiser.TerminalManager.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal; Optimiser.TerminalManager.Config = config; Optimiser.TerminalManager.Run(); class=class="str">"cmt">// Wait for the terminal to close Optimiser.TerminalManager.WaitForStop(); } catch (Exception e) { ThrowException(e.Message); } OnPropertyChanged("StopTest"); }); }
别急着下结论
前面几篇把自动优化器的算法、GUI 和项目结构都拆开了,这一节只补一个最容易被忽略的落点:编译方式直接决定你跑的是哪份程序。Visual Studio 里按 CTRL+SHIFT+B 是静默编译;点绿色箭头会进调试模式顺带编译;走菜单 Build 也行。选了调试就落在 MetaTrader Auto Optimiser/bin/Debug,选 Release 则在 bin/Release,两份二进制不是同一套行为。 附件的 Auto_Optimiser.zip 是 125.7 KB,里面是第四篇讲过的带交易机器人的优化器工程。真要跑起来,先编译优化器主体和测试机器人,再把第一篇文章里的 ReportManager.dll 拷进 MQL5/Libraries,否则 EA 起不来。 社区里有人拿 Bee Man MT5 回测,说「总是获胜」就怀疑没读历史。这种直觉没错——连续不败往往不是读不到数据,就是拟合过头。外汇和贵金属杠杆高、滑点随机,任何优化器在历史里漂亮,实盘都可能被流动性打脸。先把 DLL 路径和编译目录核对清楚,再谈信不信结果。