Ordens Duplicadas - EA - MQL5

 
    //| VERIFICAR SE ESTOU POSICIONADO                                  
         
       bool comprado = false;
       bool vendido = false;
       
       if(PositionSelect(_Symbol))
         {
            if (PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
               {
                  comprado = true;
               }
         
            if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
               {
                  vendido = true;
               }
         }  
     
     
     
     //| LOGICA DE ROTEAMENTO                                            
     
     if(!comprado && !vendido)
        {
           if(sinalCompra && !comprado)
              {
                  trade.Buy(var_lote,_Symbol,Bid,(Bid - sl_buy+ var_variacaoMedia),(Bid + tp_buy + var_variacaoMedia),"Compra a Mercado");
              }
           
           
           if(sinalVenda && !vendido)
              {
                  trade.Sell(var_lote,_Symbol,Ask,(Ask + sl_sell - var_variacaoMedia),(Ask-tp_sell - var_variacaoMedia),"Venda a Mercado");
              }
        }
     
       
     else
        {
           if(comprado)
               {
                  if(sinalVenda && !vendido)
                     {
                        trade.Sell(var_lote*2,_Symbol,Ask,(Ask+ sl_sell - var_variacaoMedia),(Ask-tp_sell - var_variacaoMedia),"Virada de mão (compra->venda)");
                     }
               }
           
           else if (vendido)
            {
               if(sinalCompra && !comprado)
                  {
                     trade.Buy(var_lote*2,_Symbol,Bid,(Bid - sl_buy + var_variacaoMedia),(Bid + tp_buy + var_variacaoMedia),"Virada de mão (venda->compra)");
                  }
           
            }
        }

Olá, 

Criei um EA para rodar no MT5 com algumas regras para se eu já estiver posicionado, ele não entrar novamente, porém percebo que ele acaba entrando duplicado quando tenho o sinal de compra ou de venda. ordens vão em um intervalo de milésimos de segundos. e nem todas as vezes duplica também. 


O código que eu criei para essa validação e a ordem, sabem o que pode estar acontecendo para ele duplicar as ordens?

 
iamfelipesena:

Olá, 

Criei um EA para rodar no MT5 com algumas regras para se eu já estiver posicionado, ele não entrar novamente, porém percebo que ele acaba entrando duplicado quando tenho o sinal de compra ou de venda. ordens vão em um intervalo de milésimos de segundos. e nem todas as vezes duplica também. 


O código que eu criei para essa validação e a ordem, sabem o que pode estar acontecendo para ele duplicar as ordens?

ok, mas ONDE você enfiou esse código??

De nada adianta mostrar um pedaço... O PRINCIPAL você não mencionou...

 
Flavio Jarabeck #:

ok, mas ONDE você enfiou esse código??

De nada adianta mostrar um pedaço... O PRINCIPAL você não mencionou...

//+------------------------------------------------------------------+
//|                                                        Teste.mq5 |
//|                                                      Felipe Sena |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Felipe Sena"
#property link      ""
#property version   "1.00"

//+------------------------------------------------------------------+
//| INCLUDES                                                        |
//+------------------------------------------------------------------+

#include  <Trade\Trade.mqh>
CTrade         trade;    

//+------------------------------------------------------------------+
//| INPUTS                                                           |
//+------------------------------------------------------------------+

input int var_lote = 1; // Lotes

input int var_periodoMedia = 9;

input float var_variacaoMedia = 50.0;

input float tp_buy = 250.0; // Gain em Operações de Compra.
input float tp_sell = 250.0; // Gain em Operações de Venda.

input float sl_buy = 300.0; // Loss em Operações de Compra.
input float sl_sell = 300.0; // Loss em Operações de Venda.

input string var_horario_Inicio = "09:10"; // Hora Inicio
input string var_horario_limite = "17:30"; // Hora Fim
input string var_encerraPosicao = "17:40"; // Encerrar Posições

string CurrentTime;
bool TradingIsAllowed=false;
bool EncerrarPosicao=false;

bool fezParcial=false;
bool fezBreakEven=false;

bool CheckTradingTime()
   {
      if(StringSubstr(CurrentTime,0,5) == var_horario_Inicio)
         TradingIsAllowed=true;
         EncerrarPosicao=false;
   
      if(StringSubstr(CurrentTime,0,5) == var_horario_limite)
         TradingIsAllowed=false;
     
      return
         TradingIsAllowed;
         //EncerrarPosicao;
   }
   
bool  CheckEncerrarPosicao()
   {
      if(StringSubstr(CurrentTime,0,5) == var_encerraPosicao)
         EncerrarPosicao=true;
     
      return
         EncerrarPosicao;
   }  


//  GLOBAIS  ////////////////////////////////////////////////////////////////

int mediaHandle = INVALID_HANDLE;
double media[];
double high[];
double low[];
MqlRates PriceInformation[];

////////////////////////////////////////////////////////////////////////////

int OnInit()
  {
      ArraySetAsSeries(media, true);
      mediaHandle = iMA(_Symbol,_Period,var_periodoMedia,0,MODE_EMA,PRICE_CLOSE);
      return(INIT_SUCCEEDED);
  }

////////////////////////////////////////////////////////////////////////////

void OnTick() //| Inicio On Tick
  {
 
     //| OBTER DADOS                                                      
     int copy = CopyBuffer(mediaHandle,0,0,7,media);
     int data = CopyRates(_Symbol,_Period,0,Bars(_Symbol,_Period),PriceInformation);
     
     double preco = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   
     bool sinalCompra = false;
     bool sinalVenda = false;
     
     double BarHigh0=iHigh(Symbol(),NULL,0);
     double BarHigh1=iHigh(Symbol(),NULL,1);
     double BarHigh2=iHigh(Symbol(),NULL,2);
     double BarHigh3=iHigh(Symbol(),NULL,3);
     double BarHigh4=iHigh(Symbol(),NULL,4);
     double BarHigh5=iHigh(Symbol(),NULL,5);
     double BarHigh6=iHigh(Symbol(),NULL,6);
     
     double BarLow0=iLow(Symbol(),NULL,0);
     double BarLow1=iLow(Symbol(),NULL,1);
     double BarLow2=iLow(Symbol(),NULL,2);
     double BarLow3=iLow(Symbol(),NULL,3);
     double BarLow4=iLow(Symbol(),NULL,4);
     double BarLow5=iLow(Symbol(),NULL,5);
     double BarLow6=iLow(Symbol(),NULL,6);
     
     double BarClose0=iClose(Symbol(),NULL,0);  

     datetime time = TimeLocal();
     
     CurrentTime = TimeToString(time,TIME_MINUTES);
     
     double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
     double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
     
     // LOGICA SINAIS DE COMPRA E VENDA
   
     if (copy==7 && CheckTradingTime()==true)
        {
         if
            (
               BarClose0 <= (media[0] + var_variacaoMedia)
               && BarClose0 > (media[0] - 20)
               && BarLow1 > media[1]
             )
            {
               sinalCompra = true;
            }
           
         if
            (
               BarClose0 >= (media[0] - var_variacaoMedia)
               && BarClose0 < (media[0] + 20)
               && BarHigh1 < media[1]
            )
            {
               sinalVenda = true;
            }  
        }
     
     
     //| VERIFICAR SE ESTOU POSICIONADO                                  
         
       bool comprado = false;
       bool vendido = false;
       
       if(PositionSelect(_Symbol))
         {
            if (PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
               {
                  comprado = true;
               }
         
            if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
               {
                  vendido = true;
               }
         }  
     
     
     
     //| LOGICA DE ROTEAMENTO                                            
     
     if(!comprado && !vendido)
        {
           if(sinalCompra && !comprado)
              {
                  trade.Buy(var_lote,_Symbol,Bid,(Bid - sl_buy+ var_variacaoMedia),(Bid + tp_buy + var_variacaoMedia),"Compra a Mercado");
              }
           
           
           if(sinalVenda && !vendido)
              {
                  trade.Sell(var_lote,_Symbol,Ask,(Ask + sl_sell - var_variacaoMedia),(Ask-tp_sell - var_variacaoMedia),"Venda a Mercado");
              }
        }
     
       
     else
        {
           if(comprado)
               {
                  if(sinalVenda && !vendido)
                     {
                        trade.Sell(var_lote*2,_Symbol,Ask,(Ask+ sl_sell - var_variacaoMedia),(Ask-tp_sell - var_variacaoMedia),"Virada de mão (compra->venda)");
                     }
               }
           
           else if (vendido)
            {
               if(sinalCompra && !comprado)
                  {
                     trade.Buy(var_lote*2,_Symbol,Bid,(Bid - sl_buy + var_variacaoMedia),(Bid + tp_buy + var_variacaoMedia),"Virada de mão (venda->compra)");
                  }
           
            }
        }
         
     
     //| ENCERRAR POSIÇÃO
     
     if(comprado && CheckEncerrarPosicao()==true)
         {
            trade.Sell(var_lote,_Symbol,Ask,0,(Ask * _Point),"Encerrar Posição");
         }
         
     if(vendido && CheckEncerrarPosicao()==true)
         {
            trade.Buy(var_lote,_Symbol,Ask,0,(Ask * _Point),"Encerrar Posição");
         }    
       
     } //| Fim On Tick

Esse é código completo, 

não entendo tanto de programação dos Experts Advisors.. 

No backtest ele funciona perfeitamente, só duplica mesmo quando estou no ambiente real. e como mencionei, não duplica em todas as entradas. 

 
iamfelipesena #:

Esse é código completo, 

não entendo tanto de programação dos Experts Advisors.. 

No backtest ele funciona perfeitamente, só duplica mesmo quando estou no ambiente real. e como mencionei, não duplica em todas as entradas. 

Bem-vindo ao inferno que é programar em MQL5.

Segregue a checagem no OnTrade() ou no OnTrdeTransaction()..

POSITION_TYPE
pode falhar. OnTick() é muito veloz...
 
Flavio Jarabeck #:

Bem-vindo ao inferno que é programar em MQL5.

Segregue a checagem no OnTrade() ou no OnTrdeTransaction()..

pode falhar. OnTick() é muito veloz...

Desculpa minha ignorancia, rsrs'

Não sei bem estruturar dessa forma, Mas não será que antes de ler o OnTrade() ele iria sair executando varias ordens no OnTick() até entender que está posicionado? 

Pensei em talvez colocar um Sleep(1000) logo após a execução da ordem, talvez faça ele parar um pouco antes de ler novamente e assim dar um tempo para ele validar a checagem. acha que vale o teste também? 

 
iamfelipemateus #:

Desculpa minha ignorancia, rsrs'

Não sei bem estruturar dessa forma, Mas não será que antes de ler o OnTrade() ele iria sair executando varias ordens no OnTick() até entender que está posicionado? 

Pensei em talvez colocar um Sleep(1000) logo após a execução da ordem, talvez faça ele parar um pouco antes de ler novamente e assim dar um tempo para ele validar a checagem. acha que vale o teste também? 

Como o Flavio, OnTick() pode executar quando a posição ainda não foi completamente criada ou a ordem (inicial) ainda não foi criada e isso faz voce ter mais posições do que gostaria. O Sleep resolve? Minha opinião que não por ser arbitrario, mas pode diminuir a ocorrencia. Entretanto, tu vai perder analise.

 
Uma das formas de se contornar isso é, criar um sistema de semáforo, quando um evento ocorrer em OnTick deve esperar a liberação ate que seja confirmado em OnTradeTransaction, é a forma mais simples ao meu ver. 
 

Parece que o Sleep(1000) já resolveu, foram 2 dias sem duplicar, mas vou tentar o OnTradeTransaction também. (: 

Documentação sobre MQL5: Elementos Básicos da Linguagem / Funções / Funções de Manipulação de Evento
Documentação sobre MQL5: Elementos Básicos da Linguagem / Funções / Funções de Manipulação de Evento
  • www.mql5.com
Funções de Manipulação de Evento - Funções - Elementos Básicos da Linguagem - Referência MQL5 - Referência sobre algorítimo/automatização de negociação na linguagem para MetaTrader 5
 
Felipe Sena #:

Parece que o Sleep(1000) já resolveu, foram 2 dias sem duplicar, mas vou tentar o OnTradeTransaction também. (: 

Acho que nao entendeu, o OnTradeTransaction eh pra fazer uma forma de sleep onde tu nao trava o programa numa chamada dizendo "demore aqui tantos milesegundos". Se tu fosse fazer um Sleep dentro de um indicador por exemplo, toda tua interface iria travar. No EA, isso eh minimizado ja que nao compartilha a execucao com a interface. Mas eh igualmente visto como ruim ja que pode gerar perda de analise de ticks.
 
Felipe Sena #:

Esse é código completo, 

não entendo tanto de programação dos Experts Advisors.. 

No backtest ele funciona perfeitamente, só duplica mesmo quando estou no ambiente real. e como mencionei, não duplica em todas as entradas. 

E se vc colocasse o IF antes do trade.buy e trade.sell e tranferindo o valor true para comprado ou vendido tipo:

if(sinaldecompra && !comprado ){  // se deu sinal de compra e não estou comprado
   if ( trade.buy(...)) {                       // efetua o trade de compra e caso o trade.buy seja executado com sucesso (true) então

     comprado=true;                           //  comprado recebe true..  Se o evento ontick passar de novo dentro dessa rotina ele vai encontrar o sinal de comprado como true ignorando o resto  

 }

}

 //------------------------------------------

Faça os testes pois se não me falha a memoria meu robo (ainda em fase de testes) fazia algo parecido e depois que implementei uma logica desse tipo não percebi duplicidade.

Acho que o evento Ontick é tão rápido que se vc não der uma tapa no bicho ele vai fazendo cagada rsrsrs

Tente fazer uso também das estruturas MqlTradeRequest e MqlTradeResult em vez da Ctrade. Acredito que possa ser útil também nesse sentido apesar de ainda não tê-lo explorado com afinco


Att

Josue

 

Recomendo a implementação do Jonathan... É inclusive como eu uso no meu engine... Não dá pra ter certeza de nada em contas reais. SEMPRE assuma o pior... Do contrário algum dia você vai zerar sua conta...

É por isso que é tão complexo desenvolver verdadeiros robôs em MQL5. Não dá pra fazer um robô com 100 linhas de código...

;)

Razão: