Aceptación de órdenes SL/TP

 

Esta rama se ocupará de las órdenes que se crean como resultado de la activación de los niveles SL/TP de las posiciones abiertas.

Escribí una función complicada pero útil de obtener un tick que sirva como disparador para una orden SL/TP especificada.

#define  SEARCH_TICK(A, B)                             \
{                                                     \
  if (!(Ticks[Pos].##A  B Price) && ((Pos <= 1) ||     \
      (!StopLevel && (Ticks[Pos - 1].##A == Price)))) \
    Tick = Ticks[Pos];                                \
  else                                                \
  {                                                   \
    while ((Pos >= 0) && !(Ticks[Pos].##A  B Price))   \
      Tick = Ticks[Pos--];                            \
                                                      \
    if (!Tick.time)                                   \
    {                                                 \
      while ((Pos >= 0) && (Ticks[Pos].##A  B Price))  \
        Pos--;                                        \
                                                      \
      while ((Pos >= 0) && !(Ticks[Pos].##A  B Price)) \
        Tick = Ticks[Pos--];                          \
    }                                                 \
  }                                                   \
}

// Получение тика, который акцептировал TP/SL-ордер.
bool GetAcceptedTick( const ulong Ticket, MqlTick &Tick, const bool PrintFlag = false )
{
  bool Res = false;

  if (!IsStopped() && HistoryOrderSelect2(Ticket))
  {
    const ENUM_ORDER_REASON Reason = (ENUM_ORDER_REASON)HistoryOrderGetInteger(Ticket, ORDER_REASON);

    if ((Reason == ORDER_REASON_TP) || (Reason == ORDER_REASON_SL))
    {
      const long CreateTime = HistoryOrderGetInteger(Ticket, ORDER_TIME_SETUP_MSC);
      const long DoneTime = HistoryOrderGetInteger(Ticket, ORDER_TIME_DONE_MSC);
      const string Symb = HistoryOrderGetString(Ticket, ORDER_SYMBOL);
      const ENUM_ORDER_STATE State = (ENUM_ORDER_STATE)HistoryOrderGetInteger(Ticket, ORDER_STATE);
      const ENUM_ORDER_TYPE Type = (ENUM_ORDER_TYPE)HistoryOrderGetInteger(Ticket, ORDER_TYPE);
      const double Price = HistoryOrderGetDouble(Ticket, ORDER_PRICE_OPEN);

      const ulong TicketOpen = HistoryOrderGetInteger(Ticket, ORDER_POSITION_ID);

      if (SymbolInfoInteger(Symb, SYMBOL_EXIST) && TicketOpen && HistoryOrderSelect2(TicketOpen))
      {
      #define  TOSTRING(A) ", " + #A + " = " + (string)(A)
        const int digits = (int)SymbolInfoInteger(Symb, SYMBOL_DIGITS);

        const int StopLevel = (int)SymbolInfoInteger(Symb, SYMBOL_TRADE_STOPS_LEVEL);
        long PositionCreated = HistoryOrderGetInteger(TicketOpen, ORDER_TIME_DONE_MSC);
        
        // Условие может сработать при частичном исполнении.
        if ((PositionCreated >= CreateTime) && HistorySelectByPosition(TicketOpen) && HistoryDealsTotal())
        {
          PositionCreated = HistoryDealGetInteger(HistoryDealGetTicket(0), DEAL_TIME_MSC);
          
          HistoryOrderSelect(TicketOpen); // Не HistoryOrderSelect2, т.к. нужно HistoryOrdersTotal() <= 1.
        }

      #define  HOUR (3600 * 1000)
        long From = MathMax(PositionCreated,    // Время открытия позиции
                            CreateTime - HOUR); // Час - просто с запасом.

        MqlTick Ticks[];

        ResetLastError();
        int Pos = CopyTicksRange(Symb, Ticks, COPY_TICKS_INFO, From, CreateTime) - 1;

        if ((Pos < 0) && !_LastError && (From == PositionCreated))
          Pos = CopyTicksRange(Symb, Ticks, COPY_TICKS_INFO, From -= HOUR, CreateTime) - 1;

        if (Pos >= 0)
        {
          const MqlTick LastTick = Ticks[Pos];

          Tick.time = 0;

          if (Type == ORDER_TYPE_BUY)
          {
            if (Reason == ORDER_REASON_TP)
              SEARCH_TICK(ask, >)
            else
              SEARCH_TICK(ask, <)
          }
          else if (Reason == ORDER_REASON_TP)
            SEARCH_TICK(bid, <)
          else
            SEARCH_TICK(bid, >)

          if (!(Res = /*(Pos >= 0) && */ Tick.time))
            Alert(__FUNCSIG__ + ": Error!"); // Ошибка при расчетах
          else if (PrintFlag) // Выводим найденный тик.
          {
            Print("Last Tick " + TickToString(LastTick, digits));

            Print("Accepted Tick " + TickToString(Tick, digits));
            Print("Accepted Length = " + (string)(CreateTime - Tick.time_msc) + " ms.");
          }
        }
        else // В случае ошибки CopyTicks - сообщаем.
          Alert(__FUNCSIG__ + ": CopyTicksRange(" + Symb + ", " + TimeToString(From) + ", " +
                                                TimeToString(CreateTime) + ") = " + (string)(Pos + 1) + TOSTRING(_LastError));

        if (PrintFlag || !Res) // Распечатываем данные ордера.
          Print("Order " + (string)Ticket + " " + EnumToString(Type) + " " + Symb + " " + TimeToString(CreateTime) + " " +
                           DoubleToString(Price, digits) + " " + EnumToString(Reason) + " " + EnumToString(State) + " " +
                           TimeToString(DoneTime) + ", Position " + (string)TicketOpen + " created " +
                           TimeToString(PositionCreated) + TOSTRING(StopLevel) + "\n");
      }
    }
  }

  return(Res);
}

// Преобразование времени в миллисекундах в строку.
string TimeToString( const long time, const int FlagTime = TIME_DATE | TIME_SECONDS)
{
  return(TimeToString((datetime)time / 1000, FlagTime) + "." + IntegerToString(time % 1000, 3, '0'));
}

// Преобразование тика в строку.
string TickToString( const MqlTick &Tick, const int digits )
{
  return(TimeToString(Tick.time_msc) + " " + DoubleToString(Tick.bid, digits) + " " + DoubleToString(Tick.ask, digits));
}

// Правильный выбор исторического ордера.
bool HistoryOrderSelect2( const ulong Ticket)
{
  return(((HistoryOrderGetInteger(Ticket, ORDER_TICKET) == Ticket) || HistoryOrderSelect(Ticket)));
}


La aplicación de esta gran función es el motivo de la creación de esta rama. Estoy seguro de que no he cogido todos los fallos del código, pero para que quede constancia y se entienda que es realmente difícil, he dado el listado completo.

 

Al investigar la ejecución de órdenes TP, me di cuenta de que algunas órdenes TP se creaban con un retraso significativo respecto a los ticks que las aceptaban.

El informe mostró que esta situación se repite no sólo en los diferentes corredores, sino también en la situación cuando se negocia en el Terminal, que está en la misma máquina que el Servidor de Comercio. Es decir, con un ping muy bajo y la única cuenta de comercio para el servidor de comercio.



Escribir la funciónGetAcceptedTick nos permitió investigar a fondo el problema y demostrarlo de forma constructiva.


Guión.

Por lo tanto, la siguiente secuencia de comandos se encuentra en el remolque.

// Скрипт выводит самое длительное или конкретное акцептирование SL/TP-ордера.
#property script_show_inputs

input datetime inFrom = D'2020.01.01'; // С какого времени проверять ордера
input ulong inTicket = 0;              // Отдельно проверяемый тикет

// Возвращает самый медленный TP/SL-ордер с определенной даты.
ulong GetSlowestOrder( const datetime From );

// Распечатывает подробности акцепта SL/TP-ордера.
void PrintOrder( const ulong MaxTicket );

void OnStart()
{
  Print("\n\nStart " + MQLInfoString(MQL_PROGRAM_NAME) + TOSTRING(inFrom) + TOSTRING(inTicket) + "\n");
  
  PrintOrder(inTicket ? inTicket : GetSlowestOrder(inFrom));
}


El resultado de ejecutarlo en la MQ-Demo.

Total Orders (from 2020.09.01 00:00:00) = 58493, calculated = 439
Calculation time = 00:00:11.328, Performance = 38.0 orders/sec.

ServerName: MetaQuotes-Demo

Last Tick 2020.09.30 19:07:32.917 1.80181 1.80205
Accepted Tick 2020.09.30 19:07:32.716 1.80178 1.80202
Accepted Length = 357 ms.
Order 726444166 ORDER_TYPE_BUY GBPAUD 2020.09.30 19:07:33.073 1.80206 ORDER_REASON_TP ORDER_STATE_FILLED 2020.09.30 19:07:33.082, Position created 2020.09.30 17:21:17.933, StopLevel = 0

Orders (2) before 726444166 with PositionID = 725926764:
------------------------
Checked Orders = 0
------------------------


El script afirma haber encontrado una orden TP y un tick que fue el desencadenante de su creación (resaltado en color en el texto). Parece que si el precio ha alcanzado el nivel de TP de una posición abierta en el servidor de operaciones (especialmente en la demo), la orden de TP correspondiente debería crearse (no necesariamente ejecutarse) inmediatamente. Sin embargo, en esta situación, no ocurrió inmediatamente, sino después de 357 milisegundos.


Permítanme decir por adelantado que incluso un retraso de un milisegundo no es demasiado poco. Estar en el tiempo es un verbo significativo en algotrading.


Verificación.

No confiemos ciegamente en el guión y comprobemos esta situación manualmente. Así que, aquí está nuestra orden.


La correspondiente garrapata de aceptación encontrada por el script puede verse aquí.


La flecha muestra que entre los ticks nació la orden de TP. Las capturas de pantalla muestran claramente que el script era correcto y que la creación de la orden de TP ocurrió con un gran retraso por parte del servidor de comercio.


En resumen.

Ahora hay una herramienta que muestra los valores de retardo en el lado del servidor de comercio cuando se negocia a través de los niveles TP/SL. Por el momento son enormes. Y esto es definitivamente una seria desventaja de la plataforma que debe ser corregida.

Lamentablemente, es imposible registrar la aceptación de órdenes pendientes, ya que esta información no está disponible en el lado de la Terminal. Pero casi invariablemente, la presencia de rezagos significativos en el lado de la orden TP/SL no puede sino afectar los rezagos al ejecutar las órdenes. Como la causa parece ser de la misma naturaleza.


En definitiva, la plataforma MT5 se retrasa actualmente al 100% específicamente en estas situaciones. Y requiere arreglos hasta que haya cero retraso.


Os animo a compartir los resultados de vuestras cuentas. ¡Contribuya a mejorar MT5!

Archivos adjuntos:
 
fxsaber:

Anímate a compartir los resultados de tus cuentas. ¡Ayude a mejorar MT5!

Total Orders (from 2020.11.01 00:00:00) = 21725, calculated = 10465
Calculation time = 00:04:33.609, Performance = 38.0 orders/sec.

ServerName: RannForex-Server

Last Tick 2020.11.16 00:34:35.201 104.630 104.640
Accepted Tick 2020.11.16 00:34:06.309 104.627 104.639
Accepted Length = 28894 ms.
Order 1715452 ORDER_TYPE_SELL USDJPY 2020.11.16 00:34:35.203 104.627 ORDER_REASON_TP ORDER_STATE_REJECTED 2020.11.16 00:34:35.217, Position created 2020.11.16 00:33:51.196, StopLevel = 0

Orders (4) before 1715452 with PositionID = 1715287:
-----------------------
Last Tick 2020.11.16 00:34:06.309 104.627 104.639
Accepted Tick 2020.11.16 00:34:06.309 104.627 104.639
Accepted Length = 3 ms.
Order 1715425 ORDER_TYPE_SELL USDJPY 2020.11.16 00:34:06.312 104.625 ORDER_REASON_TP ORDER_STATE_REJECTED 2020.11.16 00:34:06.327, Position created 2020.11.16 00:33:51.196, StopLevel = 0

Checked Orders = 1
------------------------

¡28 segundos de retraso! Probablemente lo mejor sea ponerse en contacto con el corredor en estas situaciones ya.

 
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) ServerName: ICMarkets-MT5
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) 
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) Last Tick 2020.11.24 23:00:49.327 1.33569 1.33570
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) Accepted Tick 2020.11.24 23:00:49.327 1.33569 1.33570
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) Accepted Length = 7 ms.
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) Order 106887648 ORDER_TYPE_BUY GBPUSD 2020.11.24 23:00:49.334 1.33572 ORDER_REASON_TP ORDER_STATE_FILLED 2020.11.24 23:00:49.830, Position created 2020.11.24 22:57:47.071, StopLevel = 0
2020.11.25 02:42:17.718 CheckOrders (EURUSD,H1) 
2020.11.25 02:42:17.719 CheckOrders (EURUSD,H1) Orders (2) before 106887648 with PositionID = 106886713:
2020.11.25 02:42:17.719 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:42:17.719 CheckOrders (EURUSD,H1) Checked Orders = 0
2020.11.25 02:42:17.719 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:47:22.624 CheckOrders (EURUSD,H1) ServerName: ICMarkets-MT5
2020.11.25 02:47:22.624 CheckOrders (EURUSD,H1) 
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) Last Tick 2020.11.18 12:44:37.354 1.18748 1.18748
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) Accepted Tick 2020.11.18 12:44:37.354 1.18748 1.18748
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) Accepted Length = 17 ms.
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) Order 105637485 ORDER_TYPE_SELL EURUSD 2020.11.18 12:44:37.371 1.18749 ORDER_REASON_SL ORDER_STATE_FILLED 2020.11.18 12:44:37.476, Position created 2020.11.17 22:24:15.116, StopLevel = 0
2020.11.25 02:47:22.633 CheckOrders (EURUSD,H1) 
2020.11.25 02:47:22.634 CheckOrders (EURUSD,H1) Orders (2) before 105637485 with PositionID = 105516718:
2020.11.25 02:47:22.634 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:47:22.634 CheckOrders (EURUSD,H1) Checked Orders = 0
2020.11.25 02:47:22.634 CheckOrders (EURUSD,H1) ------------------------
 
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) ServerName: OctaFX-Real
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) 
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) Last Tick 2020.11.23 18:14:35.081 1.18108 1.18115
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) Accepted Tick 2020.11.23 18:14:35.081 1.18108 1.18115
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) Accepted Length = 11 ms.
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) Order 8950107 ORDER_TYPE_SELL EURUSD 2020.11.23 18:14:35.092 1.18105 ORDER_REASON_TP ORDER_STATE_FILLED 2020.11.23 18:14:35.104, Position created 2020.11.23 18:11:38.678, StopLevel = 20
2020.11.25 02:50:58.687 CheckOrders (EURUSD,H1) 
2020.11.25 02:50:58.688 CheckOrders (EURUSD,H1) Orders (2) before 8950107 with PositionID = 8950014:
2020.11.25 02:50:58.688 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:50:58.688 CheckOrders (EURUSD,H1) Checked Orders = 0
2020.11.25 02:50:58.688 CheckOrders (EURUSD,H1) ------------------------
 
2020.11.25 02:54:37.912 CheckOrders (EURUSD,H1) ServerName: Pepperstone-MT5-Live01
2020.11.25 02:54:37.912 CheckOrders (EURUSD,H1) 
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) Last Tick 2020.09.03 01:00:02.426 106.199 106.199
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) Accepted Tick 2020.09.03 01:00:02.426 106.199 106.199
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) Accepted Length = 4 ms.
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) Order 18982771 ORDER_TYPE_SELL USDJPY 2020.09.03 01:00:02.430 106.191 ORDER_REASON_TP ORDER_STATE_FILLED 2020.09.03 01:00:02.466, Position created 2020.09.02 22:57:47.081, StopLevel = 0
2020.11.25 02:54:37.934 CheckOrders (EURUSD,H1) 
2020.11.25 02:54:37.935 CheckOrders (EURUSD,H1) Orders (2) before 18982771 with PositionID = 18975080:
2020.11.25 02:54:37.935 CheckOrders (EURUSD,H1) ------------------------
2020.11.25 02:54:37.935 CheckOrders (EURUSD,H1) Checked Orders = 0
2020.11.25 02:54:37.935 CheckOrders (EURUSD,H1) ------------------------
 

otra explosión de cerebro de fxsaber. no sé ni qué decir.

Creo que la única solución viable es encontrar el cuello de botella junto con el corredor y, si es posible, tratar de arreglarlo.

para un arreglo interno, tendrá que

- soportar un aluvión de críticas por parte de los desarrolladores y demostrar que el lag se ha producido (teniendo en cuenta cosas que quizá no conozca, por ejemplo, el hardware del servidor del corredor)

- convencerte de que es fundamental

- esperar a que se solucione

- presionando celosamente al corredor para que se actualice a la última compilación, lo que puede ser mucho más difícil que todos los puntos anteriores.

 
y la manida MT no es para los HFT )
 
ServerName: RannForex-Server
Accepted Length = 28894 ms.

Aquí hay una fuerte sospecha de que la tecnología del broker es muy buena.

Algo se está ralentizando en los plugins de procesamiento de límites personalizados.

 
Andrey Khatimlianskii:

Aquí es donde hay una fuerte sospecha de la tecnología muy fría del corredor para el que está negociando.

... Los servidores del corredor pueden ser lo que quieras, o puede ser un enlace a un hilo sobre los retrasos en la sección de intercambio, sólo podemos adivinar.

 
Andrei Trukhanovich:

Para un arreglo interno, tendrá que

- Tendrás que sufrir un aluvión de críticas por parte de los desarrolladores y demostrar que el lag tiene lugar (teniendo en cuenta los matices que puedes desconocer, por ejemplo, el hardware de la parte del servidor del corredor).

Foro sobre comercio, sistemas de comercio automatizados y prueba de estrategias de comercio

Aceptación de órdenes SL/TP

fxsaber, 2020.11.25 00:47

Resultado de ejecutarlo en MQ-Demo.

Total Orders (from 2020.09.01 00:00:00) = 58493, calculated = 439
Calculation time = 00:00:11.328, Performance = 38.0 orders/sec.

ServerName: MetaQuotes-Demo


Se ha dicho repetidamente en otro hilo que incluso el Terminal se ralentiza por un gran número de factores. Como consecuencia, el mucho más complejo Trading Server está destinado a ralentizarse aún más. Todavía espero que la optimización algorítmica sea posible. Incluso un retraso de 5 ms ya es muy malo. Y mucho menos cientos de milisegundos.

Razón de la queja: