Советник на MQL5 с нуля. Часть 2: компиляция и тестер без единого клика

Как компилировать советник через metaeditor64.exe и гонять его в тестере стратегий из ini-конфига: один прогон занимает десять секунд вместо десяти минут ручного ритуала. С разбором граблей, на которые мы наступили.

Admin
Обложка статьи: Советник на MQL5 с нуля. Часть 2: компиляция и тестер без единого клика

В первой части мы разобрали устройство советника и расчёт объёма от расстояния до стопа. Теперь про то, чего почти нет в русскоязычных руководствах: как проверять гипотезы, не открывая MetaEditor и тестер мышкой.

Разница ощутимая. Ручной цикл — открыть редактор, нажать F7, переключиться в терминал, открыть тестер, выставить символ, период, даты, вкладку с параметрами, нажать «Старт», дождаться, посмотреть отчёт — занимает минут десять и требует внимания. Тот же прогон из командной строки занимает около десяти секунд и не требует ничего. Именно поэтому мы смогли перебрать больше сотни конфигураций советника за вечер; руками столько никто перебирать не станет.

Компиляция из командной строки

Компилятор — это metaeditor64.exe в папке терминала. Он умеет собирать файл без интерфейса:

"C:\Program Files\XM Global MT5\metaeditor64.exe" /compile:"...\MQL5\Experts\MyEA.mq5" /log:"%TEMP%\compile.log"

Три вещи, которые стоит знать сразу.

Исходник должен лежать внутри папки данных терминала. Не в проекте, а в MQL5\Experts того каталога, который терминал считает своим. Иначе компилятор не найдёт стандартные заголовки и выдаст «Trade.mqh not found» — при том, что файл на месте. Мы на это наступили: помогает либо класть исходник в папку данных (как делаем мы — копируем перед сборкой), либо добавить ключ /portable, если терминал запущен в портативном режиме.

Лог пишется в UTF-16. Обычное чтение файла даст кашу из пустых символов. В PowerShell нужно явно указывать кодировку:

$result = Get-Content $log -Encoding Unicode | Select-String 'Result' | Select-Object -Last 1
if ($result -notmatch '0 errors') { throw "не собралось: $result" }

Код возврата не всегда информативен. Надёжнее разбирать строку Result: 0 errors, 0 warnings из лога, как выше, и прерывать прогон, если сборка не прошла. Иначе тестер отработает на предыдущей, устаревшей версии .ex5 — и вы полдня будете объяснять себе результат, которого в коде уже нет.

Прогон тестера через ini-конфиг

Терминал принимает ключ /config:путь.ini и, если в конфиге есть секция [Tester], стартует сразу в режиме тестирования. Минимальный рабочий конфиг:

[Tester]
Expert=TradeaproRangeBreakout
Symbol=GOLD#
Period=M15
Model=1
Optimization=0
FromDate=2025.01.01
ToDate=2025.12.31
Deposit=10000
Currency=USD
Leverage=1:100
Report=C:\Temp\report
ReplaceReport=1
ShutdownTerminal=1
Visual=0

Ключевые строки — две последние пары. Visual=0 отключает визуализацию, ShutdownTerminal=1 заставляет терминал закрыться по завершении: без этого скрипт будет ждать вечно, а вы не поймёте, закончился прогон или нет. Model=1 — расчёт по ценам открытия; для стратегии, работающей по закрытию свечей, этого достаточно и это в разы быстрее «каждого тика».

Входные параметры советника задаются отдельной секцией — имена совпадают с input-переменными в коде:

[TesterInputs]
RewardRatio=3.0
BreakevenAtR=1.5
MinRangePct=0.15

Файл нужно сохранять в UTF-16 (-Encoding Unicode в PowerShell). В UTF-8 терминал молча проигнорирует конфиг и откроется обычным окном — ошибки не будет, просто ничего не произойдёт.

Где брать результат

Главная неожиданность безоконного режима: HTML-отчёт, ради которого всё затевалось, часто не создаётся вовсе. Полагаться на него нельзя.

Работающий способ — считать метрики внутри самого советника и печатать их в OnDeinit, который вызывается в конце прогона:

void OnDeinit(const int reason)
{
   double balance  = AccountInfoDouble(ACCOUNT_BALANCE);
   double winrate  = trades > 0 ? 100.0 * wins / trades : 0;
   double pf       = grossLoss > 0 ? grossProfit / grossLoss : 0;

   PrintFormat("[RESULT] balance=%.2f trades=%d winrate=%.1f PF=%.2f maxDD=%.1f",
               balance, trades, winrate, pf, maxDrawdownPct);
}

Печать уходит в журнал тестового агента:

%APPDATA%\MetaQuotes\Tester\<ID>\Agent-127.0.0.1-3000\logs\<дата>.log

Оттуда скрипт достаёт итог одной строкой. Заодно полезно печатать причины отказа от входа — [SKIP] spread, [SKIP] range, [SKIP] lot — и группировать их:

$skips = $txt | Select-String '\[SKIP\] (\w+)' -AllMatches |
  ForEach-Object { $_.Matches[0].Groups[1].Value } | Group-Object | Sort-Object Count -Desc

Именно это спасло нас, когда первая версия советника не совершила ни одной сделки за четыре года. Отчёт показывал пустоту, а журнал — что фильтр диапазона отклонил всё до единого дня. Без такой печати причину пришлось бы искать вслепую.

Грабли, на которые мы наступили

Терминал закрылся за четыре секунды и ничего не сделал. Он в этот момент устанавливал обновление. Первый запуск после обновления надо просто пережить руками.

Прогон на трёх месяцах занял девять минут вместо десяти секунд. Терминал был залогинен в счёт с истёкшим доступом и каждый раз ждал сервер, чтобы синхронизировать историю. Для тестов нужен терминал с живым счётом — годится любой демо-счёт, история от этого не меняется.

Кстати, о брокерах: проверять стратегию стоит минимум на двух. Спред, разрядность котировок и даже название инструмента отличаются — у одного брокера золото называется GOLD#, у другого XAUUSD, и наш советник на второй паре дал профит-фактор 1,41 против 1,33 на первой. Мы гоняли тесты на XM и перепроверяли на RoboForex; демо-счёт открывается за пару минут и историю котировок отдаёт сразу.

Не редактируйте руками terminal.ini и шаблоны терминала. Мы «прибрались» в конфиге и обнулили поля логина — терминал перестал стартовать вовсе. Всё, что нужно передать тестеру, передаётся отдельным ini-файлом через /config; трогать конфигурацию терминала для этого не требуется.

Один прогон — один терминал. Перед стартом стоит закрывать предыдущий процесс (Stop-Process -Name terminal64), иначе новый запуск подхватит чужой конфиг. Если нужно параллелить, ставьте несколько копий терминала с разными папками данных — каждая копия займёт около гигабайта памяти, так что рабочий ноутбук на четырёх гигабайтах больше двух прогонов одновременно не потянет.

Когда конфигурация найдена и советник переходит на счёт, машина для тестов уже не годится: терминал должен работать круглосуточно и не зависеть от того, закрыли вы крышку ноутбука или нет. Мы держим боевые терминалы на VPS рядом с сервером брокера — задержка в единицы миллисекунд для пробойной стратегии заметна, потому что вход происходит ровно в момент выхода цены за границу диапазона.

Что это даёт

Собранный скрипт — сборка, конфиг, запуск, разбор журнала — умещается в сотню строк PowerShell и вызывается так:

.\run-test.ps1 -Symbol GOLD# -From 2025.01.01 -To 2025.12.31 -Inputs @{ RewardRatio = 3; BreakevenAtR = 1.5 }

Дальше это оборачивается в цикл по параметрам, и вы получаете не мнение о стратегии, а таблицу. Мы прогнали свой советник по сетке параметров на 2022–2024 годах и проверили лучшую конфигурацию на 2025–2026, которых подбор не видел: профит-фактор 1,33, просадка 3,9%, 145 сделок на проверке.

Самое ценное в такой таблице — не максимум, а его окрестности. Если соседние по параметрам прогоны дают близкий результат, это плато, и настройка, скорее всего, отражает свойство рынка. Если максимум одиноко торчит среди убыточных соседей — это подгонка под историю, и на живом счёте от неё ничего не останется. Ручным перебором такую разницу не увидеть просто потому, что руками никто не сделает сто прогонов.

Советник, на котором всё это проверялось, лежит в каталоге вместе с исходником, а его сделки на нашем демо-счёте видны в мониторинге.

В третьей части — про то, как отличить рабочую стратегию от подогнанной: форвард-тест, разбиение выборки и почему красивый бэктест почти ничего не значит.

Ссылки на брокера и VPS в тексте партнёрские: если вы зарегистрируетесь по ним, мы получим комиссию, а вы — те же условия, что и по прямой ссылке. Мы упоминаем только то, чем пользуемся сами.

Поделиться статьёй:

Комментарии (0)

Чтобы оставить комментарий, необходимо войти в систему

Пока нет комментариев

Будьте первым, кто оставит комментарий!

Хотите больше полезных статей?

Подпишитесь на наш блог и получайте новые статьи прямо на почту

Читать все статьи