Problema de entrada de pedidos múltiplos para conta ativa com um corretor específico - página 2

 
Malacarne:

OláBlindMist, faz sentido verificar seu banco de dados local para verificar se sua conta está sincronizada com o servidor do corretor.

Por favor, dê uma olhada no post sugerido para resolver este problema.

Acabei de ler o post sugerido e ele não menciona como evitar que as ordens sejam executadas várias vezes...

Mesmo com a função Sleep(), quanto tempo você tem que esperar para ter certeza de que a negociação falhou?...

No meu EA eu tinha um tempo de envio de pedido após 10 segundos antes de tentar novamente... mas às vezes o pedido é executado 15 -20 segundos após o pedido inicial; assim, resultando em dupla negociação indesejada.

 
BlindMist:

Acabei de passar pelo posto sugerido e não menciona como evitar que as ordens sejam executadas várias vezes...

Mesmo com a função Sleep(), quanto tempo você tem que esperar para ter certeza de que a negociação falhou?...

No meu EA eu tinha um tempo de envio de pedido após 10 segundos antes de tentar novamente... mas às vezes o pedido é executado 15 -20 segundos após o pedido inicial; assim, resultando em dupla negociação indesejada.

OláBlindMist, minha idéia sobre esse tópico, que ainda acho que é a única maneira de verificá-lo (ao invés de apenas um teste de PositionSelect ou apenas um Sleep), é criar algo como um erro fatal depois de esperar muito tempo, ou pular assim que você tiver a posição do símbolo (código abaixo).

A única coisa boa sobre este problema é que provavelmente o PositionSelect, logo ou tarde, obterá a posição atualizada do servidor, então o que temos que fazer é esperar um tempo máximo (nosso timeout) para indicar um erro fatal e fazer pequenas amostras para verificar se está tudo bem (100 ms no meu exemplo).

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;
  }
}

Outra maneira de fazer isto mais modular é criar uma função para controlar o timeout, por exemplo:

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
  }

A idéia principal aqui é meu PositionSelectTimeout() substituir o PositionSelect original(), como uma alternativa, é claro, uma vez que apenas o MQ pode abordar uma solução realmente boa e definitiva.

Por exemplo, a PositionSelectTimeout() é uma solução muito boa e definitiva:

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

// instead of ...

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

Portanto, na minha opinião, oFinanceEngineer deve fazer o mesmo para corrigir o problema, e inserir este teste dentro de seu laço, para verificar duas vezes se a posição está OK para fazer uma pausa.

 
figurelli:

OláBlindMist, minha idéia sobre esse tópico, que ainda acho que é a única maneira de verificá-lo (em vez de apenas um teste de PositionSelect ou apenas um Sleep), é criar algo como um erro fatal depois de esperar muito tempo, ou pular assim que você tiver a posição do símbolo (código abaixo).

A única coisa boa sobre este problema é que provavelmente o PositionSelect, logo ou tarde, obterá a posição atualizada do servidor, então o que temos que fazer é esperar um tempo máximo (nosso timeout) para indicar um erro fatal e fazer pequenas amostras para verificar se está tudo bem (100 ms no meu exemplo).

Outra maneira de fazer isto mais modular é criar uma função para controlar o timeout, por exemplo:

A idéia principal aqui é meu PositionSelectTimeout() substituir o PositionSelect original(), como uma alternativa, é claro, uma vez que apenas o MQ pode abordar uma solução realmente boa e definitiva.

Por exemplo, a PositionSelectTimeout() é uma solução muito boa e definitiva:

Portanto, na minha opinião, oFinanceEngineer deve fazer o mesmo para corrigir o problema, e inserir este teste dentro de seu laço, para verificar duas vezes se a posição está OK para fazer uma pausa.

Obrigado figurelli, resposta muito detalhada. Vou tentar e ver se isso melhora o meu sistema.
 
BlindMist:
Obrigado figurelli, resposta muito detalhada. Vou tentar e ver se isso melhora o meu sistema.
Obrigado, você é bem-vindo.
 
BlindMist:

Acabei de passar pelo posto sugerido e não menciona como evitar que as ordens sejam executadas várias vezes...

Mesmo com a função Sleep(), quanto tempo você tem que esperar para ter certeza de que a negociação falhou?...

No meu EA eu tinha um tempo de envio de pedido após 10 segundos antes de tentar novamente... mas às vezes o pedido é executado 15 -20 segundos após o pedido inicial; assim, resultando em dupla negociação indesejada.

15 segundos para a execução de um pedido. Isto é muito ruim. O problema aqui é que não podemos obter nada do corte da Corretora (por exemplo, até mesmo um simples código de verificação de status, etc.)
 
FinanceEngineer:
15 segundos para a execução de um pedido. Isto é muito ruim. O problema aqui é que não podemos obter nada da separação da Corretora (por exemplo, até mesmo um simples código de verificação de status, etc.)

OláFinanceEngineer, você está certo, entretanto a primeira coisa a ser gerenciada é selecionar um corretor de baixa latência, já que os mercados são cada vez mais rápidos, e será comum tais problemas.

Além disso, é sempre bom pensar no pior caso, porque você pode ter um corretor de baixa latência, mas em alguns momentos do dia um grande atraso, por exemplo, quando você tem notícias relevantes.

De qualquer forma, o OrderSend() no MT5 não é tão fácil de gerenciar como o MT4, porque o valor retornado do MT4 é um Ticket. Esta mudança foi necessária no MT5 porque a comunicação assíncrona das bolsas de valores, introduzida na arquitetura MQL5, que permite a comunicação com o protocolo OMS do corretor (como o FIX, por exemplo).

Mas eu acho que esta é a grande mudança da OMS para a gestão de pedidos hoje, já que é muito difícil conseguir um Ticket em tempo real, e a MT5 está atualizada para este novo cenário, principalmente se utilizarmos as bolsas de valores, onde temos mais latência.

Neste sentido, a coisa mais relevante que você faz após um OrderSend() na MT5 é verificar PositionSelect(), e eu sugiro fortemente que use minha proposta PositionSelectTimeout() como alternativa, por todas as razões acima.

A única maneira que vejo de pensar nos piores casos é administrar todas as condições, se { } de outra forma { } após o envio de uma ordem ao mercado, de uma maneira que você possa administrar qualquer situação.

Eu também gostaria de ter pegado { }, mas podemos usar GetLastError() para fazer algo próximo a isto.

Isto porque você também precisa do Ticket para confirmar uma posição e o MT5 OrderSend() não devolve o ticket tão síncrono como o MT4.

 
BlindMist:

Acabei de passar pelo posto sugerido e não menciona como evitar que as ordens sejam executadas várias vezes...

Mesmo com a função Sleep(), quanto tempo você tem que esperar para ter certeza de que a negociação falhou?...

No meu EA eu tinha um tempo de envio de pedido após 10 segundos antes de tentar novamente... mas às vezes o pedido é executado 15 -20 segundos após o pedido inicial; assim, resultando em dupla negociação indesejada.

Este é o meu código que estou usando atualmente. Até agora, não tenho nenhum problema. Você pode tentar este código e se ele funcionar para aquele corretor.

      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 é o meu código que estou usando atualmente. Até agora, não tenho nenhum problema. Você pode tentar este código e se ele funcionar para aquele corretor.

      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));
      }
     

O que você faz com a variável checkOrderSend?

Como você evita que várias ordens sejam executadas sem verificar a conclusão do negócio do servidor?

 
figurelli:

O que você faz com a variável checkOrderSend?

Como você evita que várias ordens sejam executadas sem verificar a conclusão do negócio do servidor?

Olá figurelli

Meu objetivo era verificar os códigos 10009 e 10008 no final da função OrderSend. Porque encontrei muitas pessoas verificando apenas um dos códigos de retorno (isto é, 10009 ou 10008) e recebendo muitos pedidos múltiplos como eles normalmente colocam um loop para evitar nenhuma situação de pedido.

No meu caso, meu for loop tentará 10 vezes se eu não receber nenhuma ordem com aquele corretor. Portanto, provavelmente vale a pena esclarecer se alguém está recebendo pedidos múltiplos, então eles devem verificar se estão parando seu loop de pedidos, verificando tanto o 10009 como o 10008.

No entanto, ironicamente, em conta demo, verificar apenas um código de retorno está bem. Isto não lhe dará nenhum problema de pedidos múltiplos. Portanto, aqui eu encontrei uma conta ativa e uma conta demo comportando-se de forma ligeiramente diferente.

Cordiais cumprimentos.

 
FinanceEngineer:

Olá figurelli

Meu objetivo era verificar os códigos 10009 e 10008 no final da função OrderSend. Porque encontrei muitas pessoas verificando apenas um dos códigos de retorno (isto é, 10009 ou 10008) e recebendo muitos pedidos múltiplos como eles normalmente colocam um loop para evitar nenhuma situação de pedido.

No meu caso, meu for loop tentará 10 vezes se eu não receber nenhuma ordem com aquele corretor. Portanto, provavelmente vale a pena esclarecer se alguém está recebendo pedidos múltiplos, então eles devem verificar se estão parando seu loop de pedidos, verificando tanto o 10009 como o 10008.

No entanto, ironicamente, em conta demo, verificar apenas um código de retorno está bem. Isto não lhe dará nenhum problema de pedidos múltiplos. Portanto, aqui eu encontrei uma conta ativa e uma conta demo comportando-se de forma ligeiramente diferente.

Cordiais cumprimentos.

OláFinanceEngineer, talvez seja melhor começar a verificar seu problema de pedidos múltiplos de código original, pois se fizermos isso provavelmente abordaremos outros pontos críticos aqui e não perderemos o foco, sobre o que você pensa?