Великий и ужасный МТ4 навсегда (или как грамотно выработать стратегию перехода) - страница 13

 
JRandomTrader:

Вот из документации:

"очередность поступления этих транзакций в терминал не гарантирована, поэтому нельзя свой торговый алгоритм строить на ожидании поступления одних торговых транзакций после прихода других." https://www.mql5.com/ru/docs/event_handlers/ontradetransaction

И по опыту, транзакции TRADE_TRANSACTION_ORDER_DELETE, TRADE_TRANSACTION_DEAL_ADD, TRADE_TRANSACTION_HISTORY_ADD могут приходить в любом порядке.

Отсюда и возникают ситуации, когда сделки и ордера в истории ещё нет, а ордера уже нет. Или наоборот, ордер ещё есть, а сделка уже есть. Вот только ситуация, когда ордер одновременно есть и в действующих, и в истории, едва ли возможна.

События не ловлю, смотрю на полную картину на новом тике.


JRandomTrader:

Собственно, именно поэтому отказался от использования класса CTrade - он на все эти грабли наступает.

Способ борьбы - каждый советник ведёт список своих ордеров и отслеживает их состояние. В т.ч. "нестандартные" состояния - "ордер отправлен, но в действующих ещё не появился" (вот тут они могут задваиваться), "ордер удалён, но не появился в истории". Заодно это помогает одновременной работе на одном символе при неттинге.

До недавнего времени использовал универсальный костыль, проверяющий пропавшие ордера. Но в какой-то момент он начал сбоить.

Добавил еще один личный костыль советнику, теперь он следить за своими ордерами отдельно.

Многовато-то костылей...

 
Andrey Khatimlianskii:

Многовато-то костылей...

Изучаю вопрос. Нарываюсь даже на такое: OrderSend маркет-ордера true, после чего PositionsTotal = 0, OrdersTotal = 0, исторические таблицы без изменений.

Похоже, удалось написать IsSynchronized(). Код тяжеловат. Пока не решил, в каком виде выкладывать.

 
// Демонстрация открытия дубля позиции в MT5.

#include <Trade\Trade.mqh>

void OnStart()
{
  CTrade Trade;
  
  while (!IsStopped() && (PositionsTotal() <= 1)) // Закончим, когда появится более одной позиции.
    if (PositionsTotal() == 1)
      Trade.PositionClose(PositionGetTicket(0)); // Если есть позиция - закрываем.
    else if (!OrdersTotal())
      Trade.Buy(0.01); // Если нет позиции и ордера - открываем позицию.
}

Запустите этот код на пустом демо-счете и убедитесь в открытии двух позиций через несколько секунд.


Эта же логика на MT4 выглядит так.

void OnStart()
{
  while (!IsStopped() && (OrdersTotal() <= 1)) // Закончим, когда появится более одной позиции.
    if (OrderSelect(0, SELECT_BY_POS))
      OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 0) // Если есть позиция - закрываем.
    else
      OrderSend(_Symbol, OP_BUY, 0.01, Ask, 0, 0, 0) // Если нет позиции и ордера - открываем позицию.
}

Понятно, что такой код на MT4 не вызовет задвоения позиции. Но не на MT5.

 
fxsaber:

Запустите этот код на пустом демо-счете и убедитесь в открытии двух позиций через несколько секунд.


Эта же логика на MT4 выглядит так.

Понятно, что такой код на MT4 не вызовет задвоения позиции. Но не на MT5.

Наконец-то! Это вы только-только это обнаружили? Этой проблеме столько же лет, сколько самому терминалу. Но наконец-то пользователи терминала ее заметили... спустя десятилетие.

Когда сам выполняешь торговые действия, проблему можно решить простым способом - вставить Sleep() на секунду после выполнения действия. А вот когда в эксперте используется стоплосс/тейкпрофит и рыночное закрытие - есть опасность нарваться на эту проблему, и в данном случае ее решения нет.

 
Dmitry Fedoseev:

Наконец-то! Это вы только-только это обнаружили? Этой проблеме столько же лет, сколько самому терминалу. Но наконец-то пользователи терминала ее заметили... спустя десятилетие.

Проблема обсуждается давно. Сталкивался почти каждый. Стабильно воспроизводящий ее код - впервые.

Когда сам выполняешь торговые действия, проблему можно решить простым способом - вставить Sleep() на секунду после выполнения действия. А вот когда в эксперте используется стоплосс/тейкпрофит и рыночное закрытие - есть опасность нарваться на эту проблему, и в данном случае ее решения нет.

Решение найдено.

 
fxsaber:

Запустите этот код на пустом демо-счете и убедитесь в открытии двух позиций через несколько секунд.

Странно. Не воспроизводится. Проверял на демо от MQ, билд 2900, EURUSD, спред нулевой. Прождал около пяти минут.

Возможно, нужно использовать какой-то конкретный сервер реального ДЦ/брокера, а не MQ-сервер?

 
Ihor Herasko:

Странно. Не воспроизводится. Проверял на демо от MQ, билд 2900, EURUSD, спред нулевой. Прождал около пяти минут.

Возможно, нужно использовать какой-то конкретный сервер реального ДЦ/брокера, а не MQ-сервер?

ForexTimeFXTM-Demo01

 
fxsaber:

ForexTimeFXTM-Demo01

Да, теперь скрипт останавливается. Но позиция все равно одна остается. Вторая, видимо, успевает закрываться?

 
Ihor Herasko:

Да, теперь скрипт останавливается. Но позиция все равно одна остается. Вторая, видимо, успевает закрываться?

У меня всегда две остается. Если одна остается, то это еще бОльший баг:

  1. PositionsTotal = 1 - отправляет ордер на закрытие.
  2. После чего PositionsTotal = 2 и происходит закрытие по ордеру из п.1.
 
fxsaber:

У меня всегда две остается. Если одна остается, то это еще бОльший баг:

  1. PositionsTotal = 1 - отправляет ордер на закрытие.
  2. После чего PositionsTotal = 2 и происходит закрытие по ордеру из п.1.

Да, и я о том же. Получается, что скрипт успевает закрыть одну из позиций, когда их на самом деле две, но PositionsTotal() возвращает 1. А потом, после закрытия, выполняется условие окончания цикла, т. е. PositionsTotal() возвращает 2.

Причина обращения: