Bibliotecas: MT4Orders - página 63

 

Forum on trading, automated trading systems and testing trading strategies

Libraries: MT4Orders

fxsaber, 2021.06.02 10:09

At my request, the MetaQutoes has completely localized the latest update of the library into English. The latest build of the library is now available on the English page with comments in the source code translated into English.


Difference from the previous version that was available on the English-language page.

// List of changes:
// 02.11.2018
//   Fix: Now the MT4 position Open price cannot be zero before its triggering.
//   Fix: Some rare execution aspects of certain trading servers have been taken into account.
// 26.11.2018
//   Fix: Magic and comment of a closed MT4 position: Priority of the relevant fields of opening transactions is higher than that of closing ones.
//   Fix: Rare changes in MT5-OrdersTotal and MT5-PositionsTotal are taken into account while calculating MT4-OrdersTotal and MT4-OrderSelect.
//   Fix: Library does not take into account the orders which have opened a position, but have not been yet deleted from MT5.
// 17.01.2019
//   Fix: Fixed an unfortunate error in selecting pending orders.
// 08.02.2019
//   Add: Comment of a position is saved at partial closing via OrderClose.
//        If you need to modify the comment on an open position at partial closing, you can specify it in OrderClose.
// 20.02.2019
//   Fix: In case of no MT5 order, the library will expect the history synchronization from the existing MT5 transaction. In case of failure, it will inform about it.
// 13.03.2019
//   Add: Added OrderTicketID() - PositionID of an MT5 transaction or MT5 position, and the ticket of a pending MT4 order.
//   Add: SELECT_BY_TICKET works for all MT5 tickets (and MT5-PositionID).
// 02.11.2019
//   Fix: Corrected lot, commission, and Close price for CloseBy positions.
// 12.01.2020
//   Fix: OrderTicketID() for balance deals returns now a correct value.
//   Fix: Fixed SELECT_BY_TICKET - selection by OrderTicketID() (MT5-PositionID).
//   Fix: Changed name of the internal library method for greater compatibility with macros.
// 10.04.2020
//   Fix: Partially executed live pending order did not get into OrdersTotal().
// 09.06.2020
//   Add: StopLoss/TakeProfit/ClosePriceRequest for closed positions are now better defined.
// 10.06.2020
//   Add: Added milliseconds, removed price and order rounding in OrderPrint().
// 13.08.2020
//   Add: Added ability to check the performance of library parts via the MT4ORDERS_BENCHMARK_MINTIME macro.
// 20.08.2020
//   Fix: Taking into account the revealed features of partial order execution.
// 29.08.2020
//   Fix: Implemented faster working with the history of trades.
// 24.09.2020
//   Add: If you need to increase the priority of an MT5 order over an MT5 position when selecting a live MT4 order by SELECT_BY_TICKET (the same tickets),
//        this can be done by changing the ticket size to negative: OrderSelect(-Ticket, SELECT_BY_TICKET).
//   Add: If you need to specify the selection of only MT5 order when modifying a live MT4 order (the same tickets),
//        this can be done by changing the ticket size to negative: OrderModify(-Ticket, ...).
//   Add: OrderSelect(INT_MAX, SELECT_BY_POS) - switch to an MT5 position without checking the existence and updating.
//        OrderSelect(INT_MIN, SELECT_BY_POS) - switch to a live MT5 order without checking the existence and updating.
//   Fix: Implemented faster working with the history of trades.
// 30.09.2020
//   Fix: Implemented faster working with the history of trades.
// 08.10.2020
//   Fix: OrderSend of a market order could be executed longer due to a flaw in a fresh MT5 deal search.
// 21.10.2020
//   Add: To provide compatibility for MT4, added OrderTicketID() - returns OrderTicket().
// 11.11.2020
//   Fix: OrderTicketID() and OrderTicketOpen() return the value type specified in TICKET_TYPE.
// 06.12.2020
//   Fix: The cases of incorrect SL/TP execution records in the MT5 trading history are now taken into account.
//   Add: The MT4ORDERS_TESTER_SELECT_BY_TICKET market forces SELECT_BY_TICKET to work in the Tester only via OrderTicketID().
// 04.05.2021
//   Fix: The MT5 orders that open positions and fail to disappear are no longer added to the list of MT4 orders.
//   Fix: CloseBy MT5 orders no longer appear in the list of MT4 orders.
// 12.05.2021
//   Add: The MT4ORDERS_BYPASS_MAXTIME macro changes the constantly emerging cases of trading environment desynchronization in MT5.
// 13.05.2021
//   Fix: Fixed bug in OrderOpenReason().
// 14.05.2021
//   Fix: The BYPASS mechanism no longer affects OrderSelect(INT_MAX, SELECT_BY_POS) and OrderSelect(INT_MIN, SELECT_BY_POS).
// 01.06.2021
//   Fix: Compatibility with the compiler build 2449 and higher.
//   Fix: Improved synchronization. ByPass.mqh must be of the latest version.
//   Add: OrderLots(true) - synchronized size of the selected position, taking into account all orders which close this position.


I recommend using the latest version along with the synchronization mechanism. Then all the problems that no other trading library can solve will be imperceptible.

#define MT4ORDERS_BYPASS_MAXTIME 1000000 // Max time (in microseconds) to wait for the trading environment synchronization
#include <MT4Orders.mqh> // https://www.mql5.com/en/code/16006

For this mechanism to work, you need to download this library. All complex and effective checks of the correctness of the trading environment will be done automatically, without distracting the user when writing trading logic.

 
O MT4Orders (+ByPass) só funciona com HistorySelect(0, INT_MAX), de modo que não cria os problemas atuais com a adição de ordens apenas excluídas ao final da tabela de histórico (+sincronização).
 
fxsaber:
O MT4Orders (+ByPass) só funciona com HistorySelect(0, INT_MAX), de modo que não cria os problemas atuais com a adição de ordens apenas excluídas ao final da tabela de histórico (+sync).

Quebrado! Não recomendo a atualização do MT5. Quem entende, ajuda a explicar que o comportamento anterior do MT5 estava correto. Agora não está mais.

 
fxsaber:

Quebrado! Não recomendo a atualização do MT5. Quem entende, ajuda a explicar que o comportamento anterior do MT5 estava correto. Agora não está mais.

É triste.

Eu esbocei um código para rastrear a inserção de ordens no histórico e atualizá-lo na classe TradesID somente no período "deslocado" + não mais do que 100 posições do histórico, ou seja, com pouco sangue.

Eu NÃO testei o código e, além disso, é claro que ele não é o ideal - apenas uma demonstração da ideia. (amarelo - o que foi alterado em relação ao original)

//exemplo de ideia de rastreamento de inserção de pedido e cache de histórico
//!!!não rastreia exclusões ou alterações nos números dos tíquetes
// com base no ID de negociações
#include "Classificator.mqh"
class TRADESID
  {
   CLASSIFICATOR<ulong, ulong> OrdersID;
   CLASSIFICATOR<ulong, ulong> DealsID;

   int               LastTotalOrders;
   int               LastTotalDeals;

   //tickets uma ordem em cada centésima posição no histórico
   ulong             OrderTickets[];


   void              RefreshOrders(void)
     {
      static ulong LastOrderTicket = -1;     //ticket da ordem obtida na passagem anterior

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

         if(this.LastTotalOrders > 0 && LastOrderTicket != ::HistoryOrderGetTicket(this.LastTotalOrders - 1))
           {
            int i;
            //verificar cada centésimo tíquete na ordem inversa
            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++)
            
            // para cada centésima posição do histórico, adicione um tíquete à matriz
            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;
     }
  };

O rastreamento de exclusões/alterações de ordens é muito mais difícil, mas isso também não é resolvido por sua bíblia.

É claro que o ByPASS e o MT4HISTORY precisam de um algoritmo mais sofisticado para essa correção, mas nada complicado, ao que parece (ainda não os estudei).

 

Você também pode rastrear as transações TRADE_TRANSACTION_HISTORY_UPDATE e TRADE_TRANSACTION_HISTORY_DELETE como você escreveu:

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

Se eles fornecerem o número do tíquete e os pedidos no histórico forem classificados por tíquete, a posição do pedido no histórico poderá ser facilmente rastreada por meio da matriz OrderTickets.


P.S. Como último recurso, você também pode adicionar o HashMap...

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

É triste.

Se eles não devolverem como estava, podemos criar uma muleta. Esbocei um código que permite rastrear a inserção da ordem no histórico e atualizá-la na classe TradesID somente no período "deslocado" + não mais que 100 posições do histórico, ou seja, com pouco sangue.

Eu NÃO testei o código, além disso, é claro que ele não é o ideal - apenas uma demonstração da ideia. (amarelo - o que foi alterado em relação ao seu original)

Se entendi corretamente a ideia, você está procurando a centena em que a mudança ocorreu. Mas eu não entendi como o novo tíquete está nessa centena depois. Especialmente se houver vários deles e eles estiverem em centenas diferentes.

O rastreamento de exclusões/alterações de pedidos é muito mais difícil, mas sua bíblia também não resolveu isso.

Não estou entendendo. O que exatamente não é rastreado? Sugiro parar no b2958 por enquanto.

Se for para editar o histórico retroativamente, não vale a pena. As soluções são criadas não para fins de nerdice, mas para negociação.

É claro que o ByPASS e o MT4HISTORY exigem um algoritmo mais sofisticado para essa correção, mas parece não ser nada complicado (ainda não os estudei).

O problema é que quanto mais funções regulares forem chamadas em cada passagem, maior será a probabilidade de defasagens. O EA começa a travar. Vários Expert Advisors - ainda pior. Quando há vários terminais, a situação é bastante ruim. Até mesmo a chegada do OnTradeTransaction fica mais lenta - por exemplo, o OrderSend começa a demorar várias vezes mais do que o ping. Além do fato de que a muleta implica uma depuração selvagem, ela também criará atrasos. Imagine que, durante a enumeração, o histórico é atualizado, etc. Haverá um grande número de bugs.


Afinal de contas, o principal é que tudo funcionou perfeitamente. Eles simplesmente o quebraram em um local uniforme e não fazem nenhum comentário.


ZЫ Para mim, é um mistério o fato de quase ninguém entender do que se trata.

 
fxsaber:

ZЫ É um mistério para mim o fato de quase ninguém entender do que se trata.

Porque ninguém tentou implementar o trabalho com ordens no MT5 de forma a) fácil, b) correta e c) rápida. Isso inclui a mim.

 
fxsaber:

Se eu entendi a ideia corretamente, você está procurando a centena em que a mudança ocorreu. Mas não entendo como o novo tíquete em si está localizado nessa centena. Especialmente se houver vários deles e eles estiverem em centenas diferentes.


Se houve apenas inserções sem exclusões, então o loop

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

procura o início da primeira centena em que as inserções ocorreram. Não é necessário pesquisar o tíquete em si, basta percorrer todas as ordens a partir dessa centena e das próximas (mais recentes) e adicioná-las ao hashmap. Isso é feito como de costume em um loop while(this.LastTotalOrders < Total). Quase sempre serão 1-2 últimas centenas.

Talvez seja melhor reduzir a etapa - não 100, mas 40 ou 20.

Caso o histórico mude durante o for - algo é inserido ANTES da centena encontrada, você pode colocá-lo no loop:

 void              RefreshOrders(void)
     {
      static ulong LastOrderTicket = -1;     //ticket da ordem obtida na passagem anterior

      if(::HistorySelect(0, INT_MAX))
        {
         // precisamos adicionar uma verificação para IsStopped e tempo máximo de execução
         while(this.LastTotalOrders > 0 && LastOrderTicket != ::HistoryOrderGetTicket(this.LastTotalOrders - 1))
           {
            int i;
            //verificar cada centésimo tíquete na ordem inversa
            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);

            // para cada centésima posição do histórico, adicione um tíquete à matriz
            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;
     }

Mas isso será muito raro.

 
mktr8591:

Se houver apenas inserções sem exclusões, então o ciclo

procura o início da primeira centena em que as inserções ocorreram. Você não precisa pesquisar o tíquete em si, basta percorrer todos os pedidos a partir dessa centena e das próximas (mais recentes) e adicioná-las ao hashmap. Isso é feito como de costume no loop while(this.LastTotalOrders < Total). Quase sempre serão 1-2 últimas centenas.

Ou seja, o fato de adicionar repetidamente o mesmo tíquete ao hashmap não altera o hashmap?

Já tive ordens que atingiram a oitava centena. Na negociação ativa, esse é um fenômeno comum com novas construções. Nesse caso, é necessário fazer o hashmap de várias centenas de ordens.

 
fxsaber:

Ou seja, usar o fato de que adicionar o mesmo tíquete ao hashmap repetidamente não alterará o hashmap?


Sim, agora mesmo notei que, se você adicionar um tíquete OrdersID.Add(PositionID, Ticket) repetidamente, em OrdersID.ValuesID[] esse tíquete será revertido. Ou seja, o hashmap ficará inchado.

Precisamos fazer uma verificação de alguma forma. Ou usar HashSet em vez de uma estrutura de matriz para VALUESID. Ou algo semelhante.