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

В первой части мы разобрали устройство советника и расчёт объёма от расстояния до стопа. Теперь про то, чего почти нет в русскоязычных руководствах: как проверять гипотезы, не открывая 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)
Чтобы оставить комментарий, необходимо войти в систему
Пока нет комментариев
Будьте первым, кто оставит комментарий!
Хотите больше полезных статей?
Подпишитесь на наш блог и получайте новые статьи прямо на почту
Читать все статьи