Alain Verleyen #: Параметр m3.code не инициализируется в момент вызова функции print() и может принимать любое значение.
Я знаю, что не следует использовать неинициализированные значения. Мне просто любопытно, почему там оказывается именно то значение, которое будет присвоено после print().
поиск в этом окне стоит сделать без учета регистра для поля Описание, если в слове есть заглавная буква, поиск через строчную букву не находит символ по описанию
2026.10.3119:50:37.654 Tester "Examples\Moving Average\Moving Average.ex5" X64
2026.10.3119:50:37.659 MQL5 wrong program type, loading of Moving Average failed2026.10.3119:50:39.239 Tester GAZP_BidAsk: history data begins from 2026.10.0100:002026.10.3119:50:39.239 Tester GAZP_BidAsk: ticks data begins from 2026.10.0100:002026.10.3119:50:39.239 Core 1 connecting to 127.0.0.1:30002026.10.3119:50:39.241 Core 1 connected
2026.10.3119:50:39.250 Core 1 authorized (agent build 6295)
2026.10.3119:50:39.251 Tester GAZP_BidAsk,M1 (FINAM-AO): testing of Experts\Examples\Moving Average\Moving Average.ex5 from 2026.10.1600:00 to 2026.10.1700:002026.10.3119:50:39.258 Core 1 common synchronization completed
2026.10.3119:50:39.269 Core 1 test Experts\Examples\Moving Average\Moving Average.ex5 on GAZP_BidAsk,M1 thread finished
2026.10.3119:50:39.269 Core 1 prepare for shutdown
2026.10.3119:50:39.269 Core 1 shutdown finished
2026.10.3119:50:39.269 Core 1 login (build 6295)
2026.10.3119:50:39.269 Core 1 account info found with currency AUD
2026.10.3119:50:39.269 Core 11478 bytes of tester parameters loaded
2026.10.3119:50:39.269 Core 1708 bytes of input parameters loaded
2026.10.3119:50:39.269 Core 1 calculate profit in pips, initial deposit 10000, leverage 1:5002026.10.3119:50:39.269 Core 1 successfully initialized
2026.10.3119:50:39.269 Core 1682 bytes of total initialization data received
2026.10.3119:50:39.269 Core 1 Intel Core i7-2700K @ 3.50GHz, 12205 MB
2026.10.3119:50:39.269 Core 1 GAZP_BidAsk: symbol to be synchronized
2026.10.3119:50:39.269 Core 1 GAZP_BidAsk: symbol synchronized already, 28 bytes received
2026.10.3119:50:39.269 Core 1 GAZP_BidAsk,M1: history cached from 2026.10.0106:502026.10.3119:50:39.269 Core 1 GAZP_BidAsk,M1 (FINAM-AO): generating based on real ticks
2026.10.3119:50:39.269 Core 1 GAZP_BidAsk,M1: testing of Experts\Examples\Moving Average\Moving Average.ex5 from 2026.10.1600:00 to 2026.10.1700:00 started with inputs:
2026.10.3119:50:39.269 Core 1 inExpert=02026.10.3119:50:39.269 Core 1 GAZP_BidAsk : real ticks begin from 2026.10.1600:00:002026.10.3119:50:39.269 Core 1final balance 10000.00 pips
2026.10.3119:50:39.269 Core 1 GAZP_BidAsk,M1: 51527 ticks, 983 bars generated. Test passed in 0:00:00.010.
2026.10.3119:50:39.269 Core 1112 Mb memory used including 0.94 Mb of history data, 64 Mb of tick data
2026.10.3119:50:39.269 Core 1log file "C:\Program Files\MetaTrader 5\Tester\Agent-127.0.0.1-3000\logs\20261031.log" written
2026.10.3119:50:39.276 Core 1 connection closed
Но идет полный бэктест (можно включить Визуализатор) без советника.
Вроде, это неправильно. Но, возможно, это фишка такая.
b6295, Тестер на биржевом символе принудительно закрывает открытые позиции по last-цене. Соответственно, если last-цены нет, то происходит закрытие по нулевой цене.
b6295, Тестер на биржевом символе акцептирует исполнение TakeProfit для SELL-позиции по нулевой Last-цене. При этом исполняет по Ask-цене, создавая соответствующие отрицательные проскальзывания.
Правильно акцептировать по Ask-цене.
Для воспроизведения запустить в Тестере на кастомном символе отсюда следующий советник.
#include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006#define Bid SymbolInfoDouble(_Symbol, SYMBOL_BID)
voidOnTick()
{
if (!OrdersTotal() && (OrdersHistoryTotal() < 5))
Print(OrderSend(_Symbol, OP_SELLLIMIT, 1, Bid + _Point, 0, 0, Bid));
}
// Для видимости миллисекунд.#define REPORT_TESTER // В тестере будут автоматически записываться отчеты#define REPORT_BROWSER // Создание отчета с запуском браузера - требует разрешения DLL.#include <Report.mqh> // https://www.mql5.com/ru/code/18801
ЗЫ По этой же причине для BUY-позиции TP никогда не акцептируется - нулевая Last-цена. А правильно акцептироваться по Bid-цене.
Для разработчиков: если корректируете работу тестера для соответствия с реальной, то 30 октября (на счете к которому дал вам доступ) я торговал таким советником: Несколько версий советника тестировал, чтобы получить максимальную воспроизводимость в реале и в тестере. Входы по лимитным ордерам, выставляемым на первом тике минуты с округлением цены (на случай если первые тики в тестере и реале не совпадут по цене из за пропуска тиков в реале). При активации ордера - используется тралл, чтобы проверить срабатывания по SL, которые в тестере срабатывают по сильно устаревшим Ask | Bid, что дает положительные проскальзывания, которых нет в реале на актуальных Ask | Bid.
inputint StartHour=10;
inputint EndHour=18;
inputint CancelOrdersHour=19;
enum nums2 {__0=0,__1=1,__2=2,__3=3,__5=5,__7=7,__10=10,__14=14,__20=20,__30=30,__50=50,__70=70,__100=100,__150=150,__200=200,__300=300,__500=500,__700=700,__1000=1000,__1500=1500,__2000=2000,__3000=3000,__5000=5000,__7000=7000,__10000=10000,__15000=15000,__20000=20000,__32000=32000,__50000=50000,__100000=100000,__200000=200000};
inputENUM_ORDER_TYPE otype = 0;
inputdouble lot = 1;
input nums2 SL = 20;//SL in points, 0 to disableinput nums2 TP = 0;//TP in points, 0 to disableinput nums2 Trail = 10;//Trail SL in pointsinputint TrailStart = -10;//Trail Start in pointsinput nums2 TrailStep = 5;//Trail Step in pointsinputint LimitOrdersShift=10;
sinputbool PrintTicks=true;
#include <Trade\Trade.mqh>
CTrade ExtTrade;
double roundToLvl(double &v, double point, double roundLvl, bool up_or_down){
double rounded=v/point/roundLvl;
return (up_or_down?ceil(rounded):floor(rounded)) * point * roundLvl;
}
voidOnTick(void){
staticMqlTick Tick; staticint hour,positions,orders; staticdouble sl=SL*_Point,tp=TP*_Point,LimShift=LimitOrdersShift*_Point,open; staticlong type=otype; staticdatetime endMinute=0; staticbool M1FirstTick=false;
if (!SymbolInfoTick(_Symbol, Tick)){ return;}
if(Tick.time > endMinute){// в начале каждой минуты работает, для повышения воспроизводимости в тестере
endMinute = ((Tick.time/60))*60+59;//последняя секунда текущей минуты > будет началом следующей минуты (+59 для >, это быстрее, чем +60 и >=)
M1FirstTick=true;
hour=GetHour(Tick.time);
if(hour>=CancelOrdersHour){CancelOrders();}
}else{M1FirstTick=false;}
positions=PositionsTotal();
if(positions==0){//нет позиций - открытьif(hour>=StartHour && hour<EndHour){//торговля с 10 до 18 (гарантированно попадем в торговую сессию)if(M1FirstTick){
if(type==ORDER_TYPE_BUY ){ExtTrade.PositionOpen(_Symbol,ORDER_TYPE_BUY ,lot,n(Tick.ask),(SL==0?0:n(Tick.bid-sl)),(TP==0?0:n(Tick.bid+tp)));}
if(type==ORDER_TYPE_SELL){ExtTrade.PositionOpen(_Symbol,ORDER_TYPE_SELL,lot,n(Tick.bid),(SL==0?0:n(Tick.ask+sl)),(TP==0?0:n(Tick.ask-tp)));}
orders=OrdersTotal();
if(orders==0){
if(type==ORDER_TYPE_BUY_LIMIT){
open=Tick.ask-LimShift; Print("buy lim ask=",Tick.ask," open=",open);
open=roundToLvl(open,_Point,10,0);Print("rounded open=",open);
ExtTrade.OrderOpen(_Symbol,ORDER_TYPE_BUY_LIMIT,lot,0,n(open),n(open-(SL*_Point)),0);
}
if(type==ORDER_TYPE_SELL_LIMIT){
open=Tick.bid+LimShift; Print("sell lim bid=",Tick.bid," open=",open);
open=roundToLvl(open,_Point,10,1);Print("rounded open=",open);
ExtTrade.OrderOpen(_Symbol,ORDER_TYPE_SELL_LIMIT,lot,0,n(open),n(open+(SL*_Point)),0);
}
}
}
}
}else{//есть позиция - траллить
trail(Tick,positions);
}
//if(PrintTicks && hour>=StartHour && hour<EndHour){ Print(Tick.time,".",Tick.time_msc%1000," bid:",Tick.bid," ask:",Tick.ask," last:",Tick.last," vol:",Tick.volume," flags:",Tick.flags,Flags(Tick.flags));}if(PrintTicks){Print(Tick.time,".",Tick.time_msc%1000," bid:",Tick.bid," ask:",Tick.ask," last:",Tick.last," vol:",Tick.volume," flags:",Tick.flags,Flags(Tick.flags));}
}
void trail(MqlTick &Tick,int &positions){
staticdouble new_sl,old_sl,old_tp,openPr,trail=Trail*_Point,Trail_Step=TrailStep*_Point,Trail_Start=TrailStart*_Point; staticulong ticket;
for(int i=0; i<positions; i++){
ticket=PositionGetTicket(i);//--- получаем тикет очередной позиции, автоматически выбирая позицию для доступа к её свойствамif(ticket==0){continue;}
old_sl=PositionGetDouble(POSITION_SL);old_tp=PositionGetDouble(POSITION_TP);openPr=PositionGetDouble(POSITION_PRICE_OPEN);
if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY){
new_sl=Tick.bid - trail ;//цена стопа от текущей ценыif (new_sl > openPr+Trail_Start){//SL выше старта траллаif(new_sl > old_sl+Trail_Step){ExtTrade.PositionModify(ticket, n(new_sl),n(old_tp));}
}
}else{//sell
new_sl=Tick.ask + trail;//цена стопа от текущей ценыif (new_sl < openPr-Trail_Start){//SL выше старта траллаif(new_sl < old_sl-Trail_Step){ExtTrade.PositionModify(ticket, n(new_sl),n(old_tp));}
}
}
}
}
double n(double v){if(v<0){return0;} returnNormalizeDouble(v,_Digits);}
void CancelOrders(){
ulong ticket;
for(int i=0;i<OrdersTotal();i++){//--- пройдем в цикле по всем ордерамif((ticket=OrderGetTicket(i))>0){ExtTrade.OrderDelete(ticket);}//--- получим тикет ордера по его позиции в списке
}
}
int GetHour (datetime &t){return((int)((t / 3600) % 24));}//current hour in day. 3600 sec in hourstring Flags(ulong f){
string s="";if((f&TICK_FLAG_BID)>0){s+=" BID";}if((f&TICK_FLAG_ASK)>0){s+=" ASK";}if((f&TICK_FLAG_SELL)>0){s+=" SELL";}if((f&TICK_FLAG_BUY)>0){s+=" BUY";}if((f&TICK_FLAG_LAST)>0){s+=" LAST";}if((f&TICK_FLAG_VOLUME)>0){s+=" VOL";}
return s;
}
Настройки приложил. Создал свою версию скорректированных тиков в кастомном символе и получил: - полное совпадение по открытию позиций по цене. - небольшое отличие по времени из за срабатывания в реале по касанию цены, а в тестере срабатывает не от касания, а от полного выкупа уровня цены в стакане (не против такой логики).
Вот скрин для сравнения реальной торговои и в тестере на кастомном символе:
Результат 3х сделок совпал, остальные немного отличаются (из за срабатывания на касании, и остальные видимо из за сетевых задержек, котороых нет в тестере). Суммарный итог случано совпал с реальным -3.4 рубля. Для этого кастомного символа: - удалил все Ask|Bid тики и создал новые актуальные при изменении цен Last. - Ask|Bid тики в одной миллисекунде (когда происходит выкуп нескольких уровней в стакане) не создавал, а только по цене последнего тика в этой мс.
Уверен, что вы тоже сможете достичь подобного сходства с реальной торговлей, а может даже большего.
Результат работы имеющегося тестера на оригинальном GAZP символе: 13 сделок вместо 8 в реальной торговле. Общий итог значительно завыше из за Ask|Bid взятых из тиков котороые не обновлялись своевременно.
Так же пригагаю распечатки тиков при реальной торговле за 30 октября (там есть записи о выставлении ордеров, пример: sell lim bid=116.69 open=116.74) И прилагаю распечатку сделок за этот день.
Еще одно подтверждение, что имеющиеся в записанной истории Ask и Bid тики не правильны:
Ask и Bid тики выставлены на 30 пт выше идущих затем Last Buy и Last Sell. Поэтому в моей версии кастомного символа результаты ближе к реальным.
Пример актуализированных тиков выглядит так: (я еще объединил тики по одной цене в один тик с объемом = сумме этих тиков, для экономии диска и увеличения скорости тестирования раза в 3)
Проблема в том, что сначала торговые сессии начинались с 10:00, а с 2025 года с 07:00. И скоро снова изменят. Имеем 2 разных расписания в истории и одно расписание в спецификации.
Если установить его правильно на текущий момент (с 7:00), то оно будет неправильным до 2025 когда было с 10:00 и тогда котировочные тики с 9:50 до 10:00 будут считаться как торговые.
Потому и предлагаю сделать флаг для обозначения тиков из торговой сессии.
Демонстрация проблемы с отсутствием разметки и автоматического отсеивания тиков по торговым сессиям. Тот же эксперт, настройки приложены (просто увеличен размер тралла, чтобы сделки иногда проходили через вечерний и утренний ролловеры). В начале не торговой сессии ставится Bid > Ask, причем цены на несколлько процентов выше и ниже текущей цены. Ранее кто-то предлагал торговые сессии контролировать самостоятельно. Но на срабатывание стоп-лоссов (и др стоп ордеров) мы никак не можем повлиять, что-то фильтруя в OnTick(). Поэтому они срабатывают в том числе по тикам из не торговой сессии.
Выглядит так на дневном графике: (торговля по символу Gazp, который терминал закачал с сервера дилера)
Видны срабатывания стопов об утренние Ask < Bid, с ценой до 3-5-10 размеров дневной свечи ниже. Огромное положительное проскальзывание, делает даже такую примитивную стратегию тестерным граалем даже на реальных тиках.
Если поменять направление на BuyLimit, то будет так:
Такие большие выбросы Bid|Ask были до 2025г., сейчас сделали поменьше, но тестировать то надо не только на последнем годе истории...
Таким образом разработчик стратегии не может исключить неторговые тики из торговли в тестере. Это могут только разработчики. Самое простое решение озвучено в сообщении по ссылке - сделать флаг типа сессии и по нему тестер может отключать торговые операции со стоп ордерами и другие (но нужно попросить дилеров, у которых менялось расписание торговых сессий, каким то скриптом проставить эти флаги в прошлой истории, а в новой уже будет автоматически правильно указываться). При наличии флага и разработчики экспертов смогут останавливать торговые действия в не торговое время. Тут показал что тестер не может отличить не торгове время и принимает торговые команды.
Для авторизации и пользования сайтом MQL5.com необходимо разрешить использование файлов Сookie.
Пожалуйста, включите в вашем браузере данную настройку, иначе вы не сможете авторизоваться.
Вы вошли в аккаунт. Двухфакторная аутентификация отключена. Настройте её заново и отсканируйте новый QR-код или продолжите с отключённой двухфакторной аутентификацией.
Параметр m3.code не инициализируется в момент вызова функции print() и может принимать любое значение.
GodBolt (x86-64 clang 23.1.0 -O3):
GodBolt (x86-64 clang 23.1.0 -O3):
ИИ назвал это агрессивной оптимизацией. Думаю, вопрос можно считать закрытым. Главное - не забывать, что
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Новая версия платформы MetaTrader 5 build 6230: больше возможностей AI
Vladislav Boyko, 2026.10.29 15:34
не следует использовать неинициализированные значенияпоиск в этом окне стоит сделать без учета регистра для поля Описание, если в слове есть заглавная буква, поиск через строчную букву не находит символ по описанию
вот пример того о чём я говорю
то в логе появляется такая запись
Но идет полный бэктест (можно включить Визуализатор) без советника.
Вроде, это неправильно. Но, возможно, это фишка такая.
b6295, Тестер на биржевом символе принудительно закрывает открытые позиции по last-цене. Соответственно, если last-цены нет, то происходит закрытие по нулевой цене.
Для воспроизведения создать кастомный символ.
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Библиотеки: TicksShort
fxsaber, 2026.10.22 22:11
И на нем в Тестере запустить такой советник по реальным тикам.
Получите такую картину - закрытие по нулевой цене.
Строка для поиска: Oshibka 173.
b6295, Тестер на биржевом символе акцептирует исполнение TakeProfit для SELL-позиции по нулевой Last-цене. При этом исполняет по Ask-цене, создавая соответствующие отрицательные проскальзывания.
Правильно акцептировать по Ask-цене.
Для воспроизведения запустить в Тестере на кастомном символе отсюда следующий советник.
ЗЫ По этой же причине для BUY-позиции TP никогда не акцептируется - нулевая Last-цена. А правильно акцептироваться по Bid-цене.
Строка для поиска: Oshibka 174.
если корректируете работу тестера для соответствия с реальной, то 30 октября (на счете к которому дал вам доступ) я торговал таким советником:
Несколько версий советника тестировал, чтобы получить максимальную воспроизводимость в реале и в тестере.
Входы по лимитным ордерам, выставляемым на первом тике минуты с округлением цены (на случай если первые тики в тестере и реале не совпадут по цене из за пропуска тиков в реале).
При активации ордера - используется тралл, чтобы проверить срабатывания по SL, которые в тестере срабатывают по сильно устаревшим Ask | Bid, что дает положительные проскальзывания, которых нет в реале на актуальных Ask | Bid.
Настройки приложил.

Создал свою версию скорректированных тиков в кастомном символе и получил:
- полное совпадение по открытию позиций по цене.
- небольшое отличие по времени из за срабатывания в реале по касанию цены, а в тестере срабатывает не от касания, а от полного выкупа уровня цены в стакане (не против такой логики).
Вот скрин для сравнения реальной торговои и в тестере на кастомном символе:
Результат 3х сделок совпал, остальные немного отличаются (из за срабатывания на касании, и остальные видимо из за сетевых задержек, котороых нет в тестере). Суммарный итог случано совпал с реальным -3.4 рубля.

Для этого кастомного символа:
- удалил все Ask|Bid тики и создал новые актуальные при изменении цен Last.
- Ask|Bid тики в одной миллисекунде (когда происходит выкуп нескольких уровней в стакане) не создавал, а только по цене последнего тика в этой мс.
Уверен, что вы тоже сможете достичь подобного сходства с реальной торговлей, а может даже большего.
Результат работы имеющегося тестера на оригинальном GAZP символе:
13 сделок вместо 8 в реальной торговле. Общий итог значительно завыше из за Ask|Bid взятых из тиков котороые не обновлялись своевременно.
Так же пригагаю распечатки тиков при реальной торговле за 30 октября (там есть записи о выставлении ордеров, пример: sell lim bid=116.69 open=116.74)
И прилагаю распечатку сделок за этот день.
Еще одно подтверждение, что имеющиеся в записанной истории Ask и Bid тики не правильны:

Ask и Bid тики выставлены на 30 пт выше идущих затем Last Buy и Last Sell.
Поэтому в моей версии кастомного символа результаты ближе к реальным.
Пример актуализированных тиков выглядит так: (я еще объединил тики по одной цене в один тик с объемом = сумме этих тиков, для экономии диска и увеличения скорости тестирования раза в 3)

Проблема в том, что сначала торговые сессии начинались с 10:00, а с 2025 года с 07:00. И скоро снова изменят.
Имеем 2 разных расписания в истории и одно расписание в спецификации.
Если установить его правильно на текущий момент (с 7:00), то оно будет неправильным до 2025 когда было с 10:00 и тогда котировочные тики с 9:50 до 10:00 будут считаться как торговые.
Потому и предлагаю сделать флаг для обозначения тиков из торговой сессии.
Демонстрация проблемы с отсутствием разметки и автоматического отсеивания тиков по торговым сессиям.
Тот же эксперт, настройки приложены (просто увеличен размер тралла, чтобы сделки иногда проходили через вечерний и утренний ролловеры).
В начале не торговой сессии ставится Bid > Ask, причем цены на несколлько процентов выше и ниже текущей цены.
Ранее кто-то предлагал торговые сессии контролировать самостоятельно. Но на срабатывание стоп-лоссов (и др стоп ордеров) мы никак не можем повлиять, что-то фильтруя в OnTick(). Поэтому они срабатывают в том числе по тикам из не торговой сессии.
Выглядит так на дневном графике: (торговля по символу Gazp, который терминал закачал с сервера дилера)

Видны срабатывания стопов об утренние Ask < Bid, с ценой до 3-5-10 размеров дневной свечи ниже. Огромное положительное проскальзывание, делает даже такую примитивную стратегию тестерным граалем даже на реальных тиках.
Если поменять направление на BuyLimit, то будет так:

Такие большие выбросы Bid|Ask были до 2025г., сейчас сделали поменьше, но тестировать то надо не только на последнем годе истории...
Таким образом разработчик стратегии не может исключить неторговые тики из торговли в тестере.
Это могут только разработчики. Самое простое решение озвучено в сообщении по ссылке - сделать флаг типа сессии и по нему тестер может отключать торговые операции со стоп ордерами и другие (но нужно попросить дилеров, у которых менялось расписание торговых сессий, каким то скриптом проставить эти флаги в прошлой истории, а в новой уже будет автоматически правильно указываться).
При наличии флага и разработчики экспертов смогут останавливать торговые действия в не торговое время.
Тут показал что тестер не может отличить не торгове время и принимает торговые команды.