Как гарантированно выставить один отложенный ордер в МТ5 ?

 

В ходе портирования одной из своих старых разработок с MQL4 на MQL5 столкнулся с различиями при выставлениями отложенных ордеров в платформе МТ5 по сравнению с МТ4. А может просто не разобрался. В любом случае, хочу попросить совета у опытных разработчиков.

Итак, согласно логике работы советника, в терминале всегда должен находиться один (и только один) отложенный ордер типа BUY LIMIT.

В MQL4 c этой целью в функции OnTick осуществлялся перебор активных ордеров и при выявлении факта отсутствия ордеров типа BUY LIMIT отправлялся запрос на выставление ордера данного типа. Поскольку функция OrderSend в MQL4 является синхронной, поток выполнения эксперта останавливался до момента получения ответа от торгового сервера об успешном выставлении ордера. Вопрос обработки ошибок пока оставим за скобками — будем считать, что запрос всегда обрабатывается успешно. Таким образом, на следующем тике ордер типа BUY LIMIT гарантированно был выставлен (вспомним наше допущение об отсутствии ошибок) и второй ордер этого типа не мог быть выставлен до тех пор, пока существующий не исполнится или не будет удалён.

В MQL5 же я столкнулся с тем, что функция OrderSend является асинхронной. В том смысле, что возвращаемое ей значение true не гарантирует того, что отложенный ордер был выставлен, а лишь подтверждает тот факт, что торговый сервер успешно принял запрос.

В тестере исполнение ордеров происходит молниеносно и там всё работает хорошо. А при торговле в реальном времени я столкнулся с тем, что иногда следующий вызов OnTick происходит раньше, чем ордер BUY LIMIT, отправленный на предыдущем тике, был фактически выставлен. И в таких случаях запрос на его выставление отправляется повторно и появляются два активных ордера BUY LIMIT, что противоречит логике торговой стратегии.

Порекомендуйте, пожалуйста, как наиболее простым способом решить эту задачу?

Иными словами, как, находясь в обработчике OnTick, дождаться фактического (гарантированного) выставления отложенного ордера, отправленного из этого обработчика функцией OrderSend ?

 

Не выйдя из OnTick наверно не получится, так как обработчики выполняются в блокируемом режиме.
То есть, если зациклиться в каком то обработчике, то другому обработчику не будет передано управление. 
Заводить глобальный флаг, и ловить событие в обработчике OnTrade

tr

 
Roman #:
Заводить глобальный флаг, и ловить событие в обработчике OnTrade

Есть поверье, что вместо этой функции лучше использовать OnTradeTransaction. Я сейчас как раз с этим разбираюсь.

Но это же в любом случае означает выход из обработчика OnTick, верно? А вот находясь внутри OnTick и отправив запрос посредством OrderSend, нет ли способа дождаться выставления ордера в терминале?
 
Roman #:
Не выйдя из OnTick наверно не получится, так как обработчики выполняются в блокируемом режиме.
То есть, если зациклиться в каком то обработчике, то другому обработчику не будет передано управление. 

Понял. Буду копать в заданном направлении.

 
Janis Ozols:

В MQL5 же я столкнулся с тем, что функция OrderSend является асинхронной. 

Не используйте асинхронную  OrderSendAsync() , используйте синхронную OrdersSend() , не выходя из OnTick(),  дожидайтесь ответа и анализируйте структуру  MqlTradeResult на наличие тиккета ордера.

Как то так наверное.


ЗЫ. Есть нюанс, если пинг больше 400мс то функция OrdersSend() может завершиться не дождавшись ответа. 

 

Не знаю, как у других специалистов реализовано, но у меня (правда, сразу предупрежу, что спецом в программировании не являюсь) по условию:

if(OrdersTotal() == 0)
{

   // здесь размещаете свою функцию на установку отложенного ордера

}

всегда устанавливается только один отложенный ордер.

С уважением, Владимир.

 
Janis Ozols:

В MQL5 же я столкнулся с тем, что функция OrderSend является асинхронной. В том смысле, что возвращаемое ей значение true не гарантирует того, что отложенный ордер был выставлен, а лишь подтверждает тот факт, что торговый сервер успешно принял запрос.

OrderSend() не является асинхронной. Поэтому общая логика ее использования точно такая же, как OrderSend() в MQL4.

Другое дело, что анализировать нужно не то, что возвращает функция в bool, а то, что она возвращает в аргументе result. Об этом прямо написано в документации:

Для получения более подробного описания результата выполнения функции следует анализировать поля структуры result.
Достаточно проанализировать три первых поля структуры MqlTradeResult (retcode, deal, order), чтобы понять, выставлен ордер (открыта позиция) или нет.
 
Aleksandr Slavskii #:
Не используйте асинхронную  OrderSendAsync() , используйте синхронную OrdersSend()

Я специально несколько раз упомянул, что использую именно OrdersSend, а не OrderSendAsync. Если почитать описание OrdersSend в справочнике, то там сказано, что она отличается от OrderSendAsync тем, что дожидается ответа от торгового сервера о принятии запроса для обработки. Но это не означает (точнее, не гарантирует), что ордер был или будет выставлен.

Aleksandr Slavskii #:
не выходя из OnTick(),  дожидайтесь ответа и анализируйте структуру  MqlTradeResult на наличие тиккета ордера

А как быть, если в этой структуре поле order окажется не заполненным? В документации сказано, что это поле заполняется только в том случае, если ордер был выставлен.

Aleksandr Slavskii #:
ЗЫ. Есть нюанс, если пинг больше 400мс то функция OrdersSend() может завершиться не дождавшись ответа. 

Я так понял, что если даже она дождётся ответа, от этого не станет легче. Ведь это будет означать только то, что торговый сервер принял запрос на выставление ордера, разве нет?  

 
Janis Ozols #:

А как быть, если в этой структуре поле order окажется не заполненным? В документации сказано, что это поле заполняется только в том случае, если ордер был выставлен.

Сначала анализируйте retcode, потом уже deal и order

 
MrBrooklin #:

Не знаю, как у других специалистов реализовано, но у меня (правда, сразу предупрежу, что спецом в программировании не являюсь) по условию:

if(OrdersTotal() == 0)

всегда устанавливается только один отложенный ордер.

С уважением, Владимир.

У меня в 95% случаев тоже так. А вот в оставшихся 5% случаев выставляется два. Именно поэтому и возник вопрос, вынесенный в заголовок темы.

 
Ihor Herasko #:
OrderSend() не является асинхронной. Поэтому общая логика ее использования точно такая же, как OrderSend() в MQL4.

Да, наверное, я выразился некорректно. Имел в виду, что возвращаемое этой функцией значение true не означает, что ордер был выставлен.

Ihor Herasko #:
Достаточно проанализировать три первых поля структуры MqlTradeResult (retcode, deal, order), чтобы понять, выставлен ордер (открыта позиция) или нет.

Скажите, пожалуйста, в вашей практике никогда не бывало так, что поле order этой структуры не было заполнено?
У меня ситуация такая, что тики идут очень интенсивно, как из пулемёта, а вот торговые запросы исполняются очень медленно, от 5 секунд до одной минуты.

Ihor Herasko #:
Сначала анализируйте retcode, потом уже deal и order

Спасибо, попробую это. 

Сейчас пока реализовал торговую логику так, как вчера порекомендовал @Roman — с глобальным счётчиком запросов, отправленных на сервер и обработкой события TradeTransaction.