Problema de entrada de órdenes múltiples para la cuenta real con un corredor específico - página 2

 
Malacarne:

HolaBlindMist, tiene sentido comprobar su base de datos local para verificar si su cuenta está sincronizada con el servidor del broker.

Por favor, echa un vistazo al post sugerido para solucionar este problema.

Acabo de revisar el post sugerido y no menciona cómo evitar que las órdenes se ejecuten varias veces...

Incluso con la función Sleep(), ¿cuánto tiempo hay que esperar para tener la certeza de que la operación ha fallado?

En mi EA tengo una solicitud de envío de orden que se agota después de 10 segundos antes de intentarlo de nuevo... pero a veces la orden se ejecuta 15 -20 segundos después de la solicitud inicial; por lo tanto, resultando en una doble operación no deseada.

 
BlindMist:

Acabo de revisar el post sugerido y no menciona cómo evitar que las órdenes se ejecuten varias veces...

Incluso con la función Sleep(), ¿cuánto tiempo hay que esperar para tener la certeza de que la operación ha fallado?

En mi EA he hecho que una solicitud de envío de orden se agote después de 10 segundos antes de intentarlo de nuevo... pero a veces la orden se ejecuta 15 -20 segundos después de la solicitud inicial; por lo tanto, resultando en una doble operación no deseada.

HolaBlindMist, mi idea sobre este tema, que sigo pensando que es la única manera de comprobarlo (en lugar de una sola prueba de PositionSelect o un solo Sleep), es crear algo así como un error fatal después de esperar mucho tiempo, o saltar tan pronto como tenga la posición del símbolo (código de abajo).

Lo único bueno de este problema es que probablemente PositionSelect, pronto o tarde, obtendrá la posición actualizada del servidor, así que lo que tenemos que hacer es esperar un tiempo máximo (nuestro timeout) para indicar un error fatal y hacer pequeñas muestras para comprobar si está bien (100 ms en mi ejemplo).

bool fatalError=false; // atention: declare this as global

....

if (fatalError==false) {
  if (m_Trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, LotSize, Price, 0, 0)) {
    Print("Position opened in ", Symbol());
    int maxTimeout=0;
    while (!PositionSelect(Symbol())) {
       Sleep(100);
       maxTimeout++;
       if (maxTimeout>100) {
          Print("### PositionSelect fatal error!");
          fatalError=true;
          break;
       }
    }
    Print("--> PositionSelect delay=",maxTimeout*100);
    break;
  }
}

Otra forma de hacer esto más modular es crear una función para controlar el timeout, por ejemplo:

bool PositionSelectTimeout(string symbol,int timeout) 
  { // timeout in seconds
   int maxTimeout=0;
   while(!PositionSelect(symbol)) 
     {
      Sleep(100);
      maxTimeout++;
      if(maxTimeout>(timeout*10)) return(false); // fatal error (timeout)
     }
   return(true); // position selected
  }

La idea principal aquí es que mi PositionSelectTimeout() sustituya a la PositionSelect() original, como una solución de trabajo por supuesto, ya que sólo MQ puede abordar una solución realmente buena y definitiva.

Por ejemplo:

if (PositionSelectTimeout(Symbol(),60)) { // 60 seconds timeout
 ...
}

// instead of ...

if (PositionSelect(Symbol())) {
 ...
}

Así que, en mi opinión,FinanceEngineer debe hacer lo mismo para solucionar el problema, e insertar esta prueba dentro de su bucle, para comprobar dos veces si la posición está bien para tomar un descanso.

 
figurelli:

HolaBlindMist, mi idea sobre este tema, que sigo pensando que es la única forma de comprobarlo (en lugar de un solo test de PositionSelect o un solo Sleep), es crear algo así como un error fatal después de esperar mucho tiempo, o saltar en cuanto se tenga la posición del símbolo (código de abajo).

Lo único bueno de este problema es que probablemente PositionSelect, pronto o tarde, obtendrá la posición actualizada del servidor, así que lo que tenemos que hacer es esperar un tiempo máximo (nuestro timeout) para indicar un error fatal y hacer pequeñas muestras para comprobar si está bien (100 ms en mi ejemplo).

Otra forma de hacer esto más modular es crear una función para controlar el tiempo de espera, por ejemplo:

La idea principal aquí es que mi PositionSelectTimeout() sustituya a la original PositionSelect(), como una solución provisional, por supuesto, ya que sólo MQ puede abordar una solución realmente buena y definitiva.

Por ejemplo:

Así que, en mi opinión,FinanceEngineer debe hacer lo mismo para solucionar el problema, e insertar esta prueba dentro de su bucle, para comprobar dos veces si la posición está bien para tomar un descanso.

Gracias figurelli, respuesta muy detallada. Lo probaré y veré si mejora mi sistema.
 
BlindMist:
Gracias figurelli, respuesta muy detallada. Lo probaré y veré si mejora mi sistema.
Gracias, de nada.
 
BlindMist:

Acabo de revisar el post sugerido y no menciona cómo evitar que las órdenes se ejecuten varias veces...

Incluso con la función Sleep(), ¿cuánto tiempo hay que esperar para tener la certeza de que la operación ha fallado?

En mi EA tengo una solicitud de envío de orden que se agota después de 10 segundos antes de intentarlo de nuevo... pero a veces la orden se ejecuta 15 -20 segundos después de la solicitud inicial; por lo tanto, resultando en una doble operación no deseada.

15 segundos para la ejecución de una orden. Esto es realmente malo. El problema aquí es que no podemos obtener nada del servidor del Broker (Por ejemplo, incluso una simple pieza de código de comprobación de estado, etc)
 
FinanceEngineer:
15 segundos para la ejecución de una orden. Esto es realmente malo. El problema aquí es que no podemos obtener nada del servidor del Broker (Por ejemplo, incluso una simple pieza de código de comprobación de estado, etc)

HolaFinanceEngineer, tienes razón, sin embargo lo primero que hay que gestionar es seleccionar un broker de baja latencia, ya que los mercados son cada vez más rápidos, y será habitual este tipo de problemas.

Además, siempre es bueno pensar en el peor de los casos, ya que puedes tener un broker de baja latencia pero en algunos momentos del día un gran retraso, por ejemplo cuando tienes noticias relevantes.

De todas formas, OrderSend() en MT5 no es tan fácil de gestionar como en MT4, porque el valor devuelto por MT4 es un Ticket. Este cambio fue necesario en MT5 porque la comunicación asíncrona de los mercados de valores, introducida en la arquitectura MQL5, está habilitada para comunicarse con el protocolo OMS del broker (como FIX, por ejemplo).

Pero creo que este es el gran cambio de OMS para la gestión de órdenes hoy en día, ya que es muy difícil conseguir un Ticket en tiempo real, y MT5 se actualiza a este nuevo escenario, principalmente si utilizamos los mercados de valores, donde tenemos más latencia.

En este sentido, lo más relevante que se hace después de un OrderSend() en MT5 es comprobar PositionSelect(), y sugiero encarecidamente utilizar mi propuesta de solución de PositionSelectTimeout(), por todas las razones anteriores.

La única forma que veo para pensar en los peores casos es gestionar todas las condiciones if { } else { } después de enviar una orden al mercado, de forma que se pueda gestionar cualquier situación.

Me gustaría tener catch { } también, pero podemos usar GetLastError() para hacer algo cercano a esto.

Esto porque también se necesita el Ticket para confirmar una posición y MT5 OrderSend() no devuelve el ticket de forma sicrónica como lo hace MT4.

 
BlindMist:

Acabo de revisar el post sugerido y no menciona cómo evitar que las órdenes se ejecuten varias veces...

Incluso con la función Sleep(), ¿cuánto tiempo hay que esperar para tener la certeza de que la operación ha fallado?

En mi EA tengo un tiempo de solicitud de envío de orden después de 10 segundos antes de intentar de nuevo... pero a veces la orden se ejecuta 15 -20 segundos después de la solicitud inicial; por lo tanto, lo que resulta en el comercio doble no deseado.

Este es mi código que estoy usando actualmente. Hasta ahora, no tengo ningún problema. Usted puede probar este código y si funciona para ese corredor.

      bool checkOrderSend = OrderSend(request, result);
     
      if(result.retcode==10009 || result.retcode==10008)
      {
          Print("OrderSend was successful. Code: ",result.retcode);

          
          break;
      }
      else
      {
          Print(ResultRetcodeDescription(result.retcode));
      }
     

 
FinanceEngineer:

Este es el código que estoy utilizando actualmente. Hasta ahora, no tengo ningún problema. Usted puede probar este código y si funciona para ese corredor.

      bool checkOrderSend = OrderSend(request, result);
     
      if(result.retcode==10009 || result.retcode==10008)
      {
          Print("OrderSend was successful. Code: ",result.retcode);

          
          break;
      }
      else
      {
          Print(ResultRetcodeDescription(result.retcode));
      }
     

¿Qué haces con la variable checkOrderSend?

¿Cómo evitas que se ejecuten múltiples órdenes sin comprobar la finalización de la operación en el servidor?

 
figurelli:

¿Qué se hace con la variable checkOrderSend?

¿Cómo se evita que se ejecuten múltiples órdenes sin comprobar la finalización del trato con el servidor?

Hola figurelli

Mi punto era comprobar tanto el código 10009 como el 10008 al final de la función OrderSend. Porque he visto que mucha gente sólo comprueba uno de los dos códigos de retorno (es decir, 10009 o 10008) y obtiene muchas órdenes múltiples, ya que normalmente colocan un bucle for para evitar que no haya ninguna situación de orden.

En mi caso, mi bucle for intentará 10 veces si no obtengo ninguna orden con ese corredor. Así que probablemente valga la pena aclarar si alguien está recibiendo múltiples órdenes, entonces deberían comprobar si están parando su bucle Ordersending comprobando tanto 10009 como 10008.

Sin embargo, irónicamente, en la cuenta demo, comprobar sólo un código de retorno está bien. No le dará ningún problema de orden múltiple. Así que aquí encontré que la cuenta real y la cuenta demo se comportan de manera ligeramente diferente.

Saludos cordiales.

 
FinanceEngineer:

Hola figurelli

Mi punto era comprobar tanto el código 10009 como el 10008 al final de la función OrderSend. Porque he encontrado que mucha gente sólo comprueba uno de los dos códigos de retorno (es decir, 10009 o 10008) y obtiene muchas órdenes múltiples, ya que normalmente colocan un bucle for para evitar una situación de no orden.

En mi caso, mi bucle for intentará 10 veces si no obtengo ninguna orden con ese corredor. Así que probablemente valga la pena aclarar si alguien está recibiendo múltiples órdenes, entonces deberían comprobar si están parando su bucle de órdenes comprobando tanto 10009 como 10008.

Sin embargo, irónicamente, en la cuenta demo, comprobar sólo un código de retorno está bien. No le dará ningún problema de orden múltiple. Así que aquí encontré que la cuenta real y la cuenta demo se comportan de manera ligeramente diferente.

Saludos cordiales.

HolaFinanceEngineer, tal vez sería mejor empezar a comprobar su código original problema de órdenes múltiples, ya que si hacemos esto probablemente vamos a abordar otros puntos críticos aquí y no perder el foco, ¿qué te parece?