Библиотеки: MT4Orders - страница 63

 

Форум о трейдинге, автоматизированных торговых системах и тестировании торговых стратегий

Библиотеки: MT4Orders

fxsaber, 2021.06.02 10:09

По моей просьбе MetaQutoes полностью локализовала последнее обновление библиотеки на английский язык. Последняя сборка библиотеки теперь доступна на английской странице с комментариями в исходном коде, переведенными на английский язык.


Это отличается от предыдущей версии, которая была доступна на англоязычной странице.

// Список изменений:
// 02.11.2018
// Исправление: теперь цена открытия позиции в MT4 не может быть нулевой до ее срабатывания.
// Исправление: учтены некоторые редкие аспекты исполнения некоторых торговых серверов.
// 26.11.2018
// Исправление: Магия и комментарий закрытой позиции MT4: приоритет соответствующих полей для открывающих сделок выше, чем для закрывающих.
// Исправление: редкие изменения в MT5-OrdersTotal и MT5-PositionsTotal учитываются при расчете MT4-OrdersTotal и MT4-OrderSelect.
// Исправление: Библиотека не учитывала ордера, которые открыли позицию, но еще не были удалены из MT5.
// 17.01.2019
// Исправление: Исправлена досадная ошибка при выборе отложенных ордеров.
// 08.02.2019
// Добавление: Комментарий позиции сохраняется при частичном закрытии через OrderClose.
// Если вам нужно изменить комментарий к открытой позиции при частичном закрытии, вы можете указать его в OrderClose.
// 20.02.2019
// Исправление: В случае отсутствия ордера MT5, библиотека будет ожидать синхронизации истории от существующей транзакции MT5. В случае неудачи она сообщит об этом.
// 13.03.2019
// Добавление: Добавлена функция OrderTicketID() - идентификатор позиции сделки MT5 или позиции MT5, а также тикет отложенного ордера MT4.
// Добавьте: SELECT_BY_TICKET работает для всех тикетов MT5 (и MT5-PositionID).
// 02.11.2019
// Исправление: исправлены лот, комиссия и цена закрытия для позиций CloseBy.
// 12.01.2020
// Исправление: OrderTicketID() для сделок с балансом теперь возвращает корректное значение.
// Исправление: Исправлен SELECT_BY_TICKET - выбор по OrderTicketID() (MT5-PositionID).
// Исправление: изменено название метода внутренней библиотеки для большей совместимости с макросами.
// 10.04.2020
// Исправление: частично исполненный живой отложенный ордер не попадал в OrdersTotal().
// 09.06.2020
// Добавление: StopLoss/TakeProfit/ClosePriceRequest для закрытых позиций теперь лучше определены.
// 10.06.2020
// Добавление: Добавлены миллисекунды, удалено округление цены и ордера в OrderPrint().
// 13.08.2020
// Добавление: Добавлена возможность проверки работоспособности частей библиотеки с помощью макроса MT4ORDERS_BENCHMARK_MINTIME.
// 20.08.2020
// Фикс: Учет выявленных особенностей выполнения частичных заказов.
// 29.08.2020
// Исправление: Реализована более быстрая работа с историей сделок.
// 24.09.2020
// Добавить: Если вам нужно увеличить приоритет ордера MT5 над позицией MT5 при выборе ордера MT4 по SELECT_BY_TICKET (те же самые билеты),
// это можно сделать, изменив размер билета на отрицательный: OrderSelect(-Ticket, SELECT_BY_TICKET).
// Добавить: Если вам нужно указать выбор только MT5-ордера при модификации живого MT4-ордера (те же тикеты),
// это можно сделать, изменив размер билета на отрицательный: OrderModify(-Ticket, ...).
// Добавляем: OrderSelect(INT_MAX, SELECT_BY_POS) - переключение на позицию MT5 без проверки существования и обновления.
// OrderSelect(INT_MIN, SELECT_BY_POS) - переключение на живой ордер MT5 без проверки существования и обновления.
// Исправление: Реализована более быстрая работа с историей сделок.
// 30.09.2020
// Исправление: Реализована более быстрая работа с историей сделок.
// 08.10.2020
// Исправление: OrderSend рыночного ордера мог выполняться дольше из-за недостатка в свежем поиске сделок в MT5.
// 21.10.2020
// Добавление: Для обеспечения совместимости с MT4 добавлена функция OrderTicketID() - возвращает OrderTicket().
// 11.11.2020
// Исправление: OrderTicketID() и OrderTicketOpen() возвращают тип значения, указанный в TICKET_TYPE.
// 06.12.2020
// Исправление: Теперь учитываются случаи некорректных записей об исполнении SL/TP в истории торговли MT5.
// Добавление: Рынок MT4ORDERS_TESTER_SELECT_BY_TICKET заставляет SELECT_BY_TICKET работать в тестере только через OrderTicketID().
// 04.05.2021
// Исправление: Ордера MT5, которые открывают позиции и не исчезают, больше не добавляются в список ордеров MT4.
// Исправление: ордера CloseBy MT5 больше не отображались в списке ордеров MT4.
// 12.05.2021
// Добавить: Макрос MT4ORDERS_BYPASS_MAXTIME изменяет постоянно возникающие случаи рассинхронизации торговых сред в MT5.
// 13.05.2021
// Исправление: Исправлена ошибка в функции OrderOpenReason().
// 14.05.2021
// Исправление: механизм BYPASS больше не влияет на OrderSelect(INT_MAX, SELECT_BY_POS) и OrderSelect(INT_MIN, SELECT_BY_POS).
// 01.06.2021
// Исправление: Совместимость с компилятором сборки 2449 и выше.
// Исправление: улучшена синхронизация. ByPass.mqh должен быть последней версии.
// Добавляем: OrderLots(true) - синхронизированный размер выбранной позиции, учитывающий все ордера, которые закрывают эту позицию.


Я рекомендую использовать последнюю версию вместе с механизмом синхронизации. Тогда все проблемы, которые не может решить ни одна торговая библиотека, будут незаметны.

#define  MT4ORDERS_BYPASS_MAXTIME 1000000 // Максимальное время (в микросекундах) ожидания синхронизации торговой среды
#include <MT4Orders.mqh> // https://www.mql5.com/en/code/16006

Чтобы механизм заработал, необходимо скачать эту библиотеку. Все сложные и эффективные проверки корректности работы торговой среды будут выполняться автоматически, не отвлекая пользователя при написании торговой логики.

 
 
fxsaber:
MT4Orders (+ByPass) работает только с HistorySelect(0, INT_MAX), поэтому не создает текущих проблем с добавлением только что удаленных отложек в конец таблицы истории (+синхронизация).

Сломали! Не рекомендую обновлять MT5. Кто понимает, помогите объяснить, что прежнее поведение MT5 было правильным. Сейчас - нет.

 
fxsaber:

Сломали! Не рекомендую обновлять MT5. Кто понимает, помогите объяснить, что прежнее поведение MT5 было правильным. Сейчас - нет.

Печально.

Если не вернут как было, то можно сделать костыль.  Я навскидку набросал код, как можно отследить вставку ордера в историю и обновить ее в классе TradesID только на "сдвинутом" периоде + не более 100 позиций истории, т.е. малой кровью.

НЕ тестировал код, плюс он конечно, неоптимален - просто демонстрация идеи. (желтым - что изменено к вашему оригиналу)

//примерная идея отслеживания вставки ордеров и кэш истории
//!!не отслеживает удаление или изменения номеров тикетов
//на основе Trades ID
#include "Classificator.mqh"
class TRADESID
  {
   CLASSIFICATOR<ulong, ulong> OrdersID;
   CLASSIFICATOR<ulong, ulong> DealsID;

   int               LastTotalOrders;
   int               LastTotalDeals;

   //тикеты ордера на каждой сотой позиции в истории
   ulong             OrderTickets[];


   void              RefreshOrders(void)
     {
      static ulong LastOrderTicket = -1;     //тикет ордера, взятого из предыдущего прохода

      if(::HistorySelect(0, INT_MAX))
        {
         const int Total = ::HistoryOrdersTotal();

         if(this.LastTotalOrders > 0 && LastOrderTicket != ::HistoryOrderGetTicket(this.LastTotalOrders - 1))
           {
            int i;
            //проверка каждого сотого тикета в обратном порядке
            for(i = ArraySize(OrderTickets) - 1; i >= 0 && OrderTickets[i] !=::HistoryOrderGetTicket(i * 100) ; i--)
               ;
            if(i < 0)
               LastTotalOrders = 0;
            else
               {LastTotalOrders = i * 100 + 1; LastOrderTicket = OrderTickets[i];}
            ArrayResize(OrderTickets, i + 1);
           }

         while(this.LastTotalOrders < Total)
           {
            const ulong Ticket = LastOrderTicket = ::HistoryOrderGetTicket(this.LastTotalOrders); //(this.LastTotalOrders++)
            
            //для каждой сотой позиции истории добавляем тикет в массив
            if(LastTotalOrders++ % 100 == 0)
               OrderTickets[::ArrayResize(OrderTickets, ::ArraySize(OrderTickets) + 1) - 1] = Ticket;


            const ulong PositionID = ::HistoryOrderGetInteger(Ticket, ORDER_POSITION_ID);

            if(PositionID)
              {
               this.OrdersID.Add(PositionID, Ticket);

               const ulong PositionBy = ::HistoryOrderGetInteger(Ticket, ORDER_POSITION_BY_ID);

               if(PositionBy)
                  this.OrdersID.Add(PositionBy, Ticket);

              }
           }
        } 

      return;
     }
  };

Отследить удаление/изменения ордеров намного сложнее, но это и ваша библа не решала.

Конечно, для подобной корректировки ByPASS и MT4HISTORY нужен  алгоритм понавороченнее, но ничего сложного, кажется нет (пока не изучил их).

 

Также можно отслеживать транзакции TRADE_TRANSACTION_HISTORY_UPDATE и TRADE_TRANSACTION_HISTORY_DELETE, как вы писали:

https://www.mql5.com/ru/forum/366029/page2#comment_22442705

Если они дадут номер тикета, и ордера в истории отсортированы по тикету, то положение  ордера в истории легко отследить через массив OrderTickets.


P.S. на крайняк, можно еще HashMap добавить...

Библиотеки: TradesID
Библиотеки: TradesID
  • 2021.05.13
  • www.mql5.com
Статьи и техническая библиотека по автоматическому трейдингу: Библиотеки: TradesID
 
mktr8591:

Печально.

Если не вернут как было, то можно сделать костыль.  Я навскидку набросал код, как можно отследить вставку ордера в историю и обновить ее в классе TradesID только на "сдвинутом" периоде + не более 100 позиций истории, т.е. малой кровью.

НЕ тестировал код, плюс он конечно, неоптимален - просто демонстрация идеи. (желтым - что изменено к вашему оригиналу)

Если правильно понял идею, Вы ищите сотню, в которой произошел сдвиг. Но не понял, как находится после этого в этой сотне сам новый Ticket. Особенно, если их несколько и они лежат в разных сотнях.

Отследить удаление/изменения ордеров намного сложнее, но это и ваша библа не решала.

Не понял. Что именно не отслеживается? Предлагаю пока остановиться на b2958.

Если идет речь про правку истории задним числом - это не стоит того. Не занудства ради все же создаются решения, а для торговли.

Конечно, для подобной корректировки ByPASS и MT4HISTORY нужен  алгоритм понавороченнее, но ничего сложного, кажется нет (пока не изучил их).

Проблема в том, что чем больше вызывается штатных функций на каждом проходе, тем выше вероятность лага. Советник начинает подвешиваться. Несколько советников - еще хуже. Когда же несколько терминалов - совсем плохо. Тормозит даже приход OnTradeTransaction - например, OrderSend начинает выдавать время в несколько раз больше пинга. Помимо того, что костыль предполагает дикую по скурпулезности отладку, так и еще он будет создавать лаги. Представьте только, что во время перебора история обновилась и т.д. Там огромное количество багов будет вылезать.


Ведь главное, что все идеально работало. Просто поломали на ровном месте и никак не комментируют.


ЗЫ Для меня загадка, почему почти никто не понимает, о чем идет речь.

 
fxsaber:

ЗЫ Для меня загадка, почему почти никто не понимает, о чем идет речь.

Потому что никто не пытался реализовать работу с ордерами в МТ5 а) легко, б) правильно и в) быстро. В том числе, я.

 
fxsaber:

Если правильно понял идею, Вы ищите сотню, в которой произошел сдвиг. Но не понял, как находится после этого в этой сотне сам новый Ticket. Особенно, если их несколько и они лежат в разных сотнях.


Если произшли только вставки без удаления, то цикл

for(i = ArraySize(OrderTickets) - 1; i >= 0 && OrderTickets[i] !=::HistoryOrderGetTicket(i * 100) ; i--)
               ;

ищет начало самой ранней сотни, в которой произошли вставки. Сам тикет искать не надо - надо  просто заново пройти все ордера, начиная с этой сотни и следущие (более новые), и добавить их в хэшмэп. Это делается как обычно в цикле    while(this.LastTotalOrders < Total).  Почти всегда это будет 1-2 последних сотни.

Может быть лучше уменьшить шаг - не по 100, а по 40 или по 20.

На случай, если во время for история изменится - что-то вставится ДО найденной сотни, то можно вложить в цикл:

 void              RefreshOrders(void)
     {
      static ulong LastOrderTicket = -1;     //тикет ордера, взятого из предыдущего прохода

      if(::HistorySelect(0, INT_MAX))
        {
         // надо добавить проверку на IsStopped и на макс время выполнения
         while(this.LastTotalOrders > 0 && LastOrderTicket != ::HistoryOrderGetTicket(this.LastTotalOrders - 1))
           {
            int i;
            //проверка каждого сотого тикета в обратном порядке
            for(i = ArraySize(OrderTickets) - 1; i >= 0 && OrderTickets[i] !=::HistoryOrderGetTicket(i * 100) ; i--)
               ;
            if(i < 0)
               LastTotalOrders = 0;
            else
              {LastTotalOrders = i * 100 + 1; LastOrderTicket = OrderTickets[i];}
            ArrayResize(OrderTickets, i + 1);
            ::HistorySelect(0, INT_MAX);
           }

         const int Total = ::HistoryOrdersTotal();

         while(this.LastTotalOrders < Total)
           {
            const ulong Ticket = LastOrderTicket = ::HistoryOrderGetTicket(this.LastTotalOrders);

            //для каждой сотой позиции истории добавляем тикет в массив
            if(LastTotalOrders++ % 100 == 0)
               OrderTickets[::ArrayResize(OrderTickets, ::ArraySize(OrderTickets) + 1) - 1] = Ticket;


            const ulong PositionID = ::HistoryOrderGetInteger(Ticket, ORDER_POSITION_ID);

            if(PositionID)
              {
               this.OrdersID.Add(PositionID, Ticket);

               const ulong PositionBy = ::HistoryOrderGetInteger(Ticket, ORDER_POSITION_BY_ID);

               if(PositionBy)
                  this.OrdersID.Add(PositionBy, Ticket);

              }
           }
        } 
      return;
     }

Но это будет очень редко.

 
mktr8591:

Если произшли только вставки без удаления, то цикл

ищет начало самой ранней сотни, в которой произошли вставки. Сам тикет искать не надо - надо  просто заново пройти все ордера, начиная с этой сотни и следущие (более новые), и добавить их в хэшмэп. Это делается как обычно в цикле    while(this.LastTotalOrders < Total).  Почти всегда это будет 1-2 последних сотни.

Т.е. использовать, что повторное добавление в хэшмэп одного и того же тикета не поменяет хэшмэп?

У меня ордера попадали и в восьмую сотню. При активной торговле это рядовое явление с новыми билдами.  В таком случае надо хэшмэпить несколько сотен ордеров.

 
fxsaber:

Т.е. использовать, что повторное добавление в хэшмэп одного и того же тикета не поменяет хэшмэп?


Да, только сейчас заметил - если  добавить тикет OrdersID.Add(PositionID, Ticket) повторно, то в OrdersID.ValuesID[] этот тикет задвоится. Т.е. хэшмэп будет разбухать.

Нужно как-то делать проверку. Или использвать для VALUESID не структуру  с массивом, а HashSet. Или что-то аналогичное.