[Dúvida] Como realizar apenas uma operação a cada candle

Christian Alves  

Bom dia, boa tarde ou boa noite senhoras e senhores! Espero que todos estejam bem!


Venho por meio deste tópico questiona-los a respeito de mais uma de minhas dúvidas! Acabei de fazer outra publicação no fórum em que citava um de meus filhotes no qual utilizo a estrutura MQLTick  para identificar se o preço atual (.last) do candle 0 (ao vivo) está fechando dentro da banda de Bollinger para tentar prever um possível setup de fechou fora/fechou dentro.


Assim sendo, minha estrutura de abrir/fechar posições fica dentro de OnTick para que eu possa obter o valor do tick.last e verificar se o candle 1 fecha fora, e o candle 0 está fechando dentro.

if(rates[1].close < lowBand[1] && tick.last > lowBand[0]) //caso seja uma compra

ou

if(rates[1].close > upBand[1] && tick.last < upBand[0]) //caso seja uma venda


Por conta do take profit deste robô ser um alvo não tão longo, é possível que ele encerre a operação no mesmo candle de entrada. Quando isso ocorre, ele acaba por identificar que não existe nenhuma posição em aberta e caso encontre todas as variáveis desejadas para que a entrada ocorra, acaba por realizar uma segunda entrada no mesmo candle em que foi feita a outra entrada citada anteriormente. Vocês podem verificar isso acontecendo na foto abaixo, especificamente no log do histórico no horário de 9:54 e 9:55, no qual ele encerra a operação e automaticamente no mesmo segundo já a abre novamente.



Antes eu utilizava a seguinte estrutura de código que segue abaixo para que não fossem realizas múltiplas operações no mesmo candle até que uma nova vela se formasse.

//========ESTRUTURA PARA IDENTIFICAR NOVOS CANDLES E NÃO FAZER DUPLAS OPERAÇÕES===============  
  
   candleAtual = rates[0].time;
        if(candleAtual != candleNovo)
                {
                candleNovo = rates[0].time;
                }

        else{
                return;
              }


Desde que comecei a realizar as entradas no candle 0 tive que realizar algumas mudanças. Quando esta estrutura que identifica novos candles estava presente nas linhas de código do robô, caso a mesma se encontrasse a cima da estrutura de código de compra e da venda (como cito no exemplo abaixo), percebi que isso acabava por barrar a possibilidade do uso do tick.last, não realizando nenhuma operação caso assim estivesse programado.

candleAtual = rates[0].time;
        if(candleAtual != candleNovo)
        {
        candleNovo = rates[0].time;
        }

  else{
          return;
        }

if(rates[1].close < lowBand[1] && tick.last > lowBand[0]) //caso seja uma compra

ou

if(rates[1].close > upBand[1] && tick.last < upBand[0]) //caso seja uma venda


Não sei se seria possível através dessa mesma estrutura de identificação de formação de novos candles fazer com que apenas uma operação por setup seja possível, estou totalmente aberto a sugestões e críticas! Agradeço desde já a atenção e a eventual possibilidade de caso alguém possa me auxiliar com minha dúvida!


Obrigado pela atenção e pelo carinho, grande abraço.

Christian Alves

Vinicius Pereira De Oliveira  

Olá, Christian, boa tarde!!


No tópico abaixo, o @NandoBueno apresentou questão semelhante e eu registrei uma sugestão. Aparentemente não funcionou para ele (não entendi direito o porquê), mas se você quiser dar uma olhada pra ver se lhe traz alguma ideia: ...

 

Fórum de negociação, sistemas de negociação automatizados e testes de estratégias de negociação

Como garantir que o EA não fará mais de uma operação no mesmo Candle operando no M1

Vinicius de Oliveira, 2022.09.28 22:58


Boa tarde!!


Pra esse caso em que o sinal pode ocorrer a qualquer momento (e não apenas na abertura de nova barra), uma forma bem simples de saber se já foi aberta posição na barra atual seria armazenando iTime(0) sempre que uma posição for aberta, e verificando essa informação antes de abrir nova posição...

//--- Global
   datetime open_time = 0;

   . . .

//--- Open position
   if(open_time != iTime(_Symbol, PERIOD_CURRENT, 0))
     {
      if(!m_trade.Buy(Lot, _Symbol, ASK, SL, TP, COMMENT))
        {
         Print(m_trade.ResultRetcode(), " ", m_trade.ResultRetcodeDescription());
         return;
        }
      open_time = iTime(_Symbol, PERIOD_CURRENT, 0);
     }


Acho que essa solução deve funcionar se o EA não for encerrado e reiniciado durante a execução da mesma barra... Para um maior controle (independente de encerramento/reinício do EA), verifique o horário de abertura da última posição no histórico de operações (por exemplo).


. . .



EDIT.1: Apenas reforçando a informação de que a variável open_time deve ser declarada no escopo global.

Eduardo Oliveira  

O que nosso amigo Vinicius colocou funcionará e precisa ter os seguintes objetivos em mente:

1 Caso abra uma ordem precisa salvar o horario de abertura da vela, Vinicius chamou de open_time;

2 Se essa ordem continuar aberta mesmo apos uma vela nova, então salvar o horario de abertura desta vela nova no open_time novamente

3 No momento de abrir uma nova ordem, o horario da vela atual deverá ser diferente da variavel open_time

4 voltar para o 1º passo 


Na sua estrutura acima faltou nos if's de compra e venda as comparações deste open_time, por isso que o seu EA faz compra/venda e nao respeita a mesma vela


Espero que ajude

Vinicius Pereira De Oliveira  
Eduardo Oliveira #:

O que nosso amigo Vinicius colocou funcionará e precisa ter os seguintes objetivos em mente:

1 Caso abra uma ordem precisa salvar o horario de abertura da vela, Vinicius chamou de open_time;

2 Se essa ordem continuar aberta mesmo apos uma vela nova, então salvar o horario de abertura desta vela nova no open_time novamente

3 No momento de abrir uma nova ordem, o horario da vela atual deverá ser diferente da variavel open_time

4 voltar para o 1º passo 


Na sua estrutura acima faltou nos if's de compra e venda as comparações deste open_time, por isso que o seu EA faz compra/venda e nao respeita a mesma vela


Espero que ajude


👍 Boa, Eduardo!! Eu também acho que o passo-a-passo é esse mesmo...

Christian Alves  
Eduardo Oliveira #:

O que nosso amigo Vinicius colocou funcionará e precisa ter os seguintes objetivos em mente:

1 Caso abra uma ordem precisa salvar o horario de abertura da vela, Vinicius chamou de open_time;

2 Se essa ordem continuar aberta mesmo apos uma vela nova, então salvar o horario de abertura desta vela nova no open_time novamente

3 No momento de abrir uma nova ordem, o horario da vela atual deverá ser diferente da variavel open_time

4 voltar para o 1º passo 


Na sua estrutura acima faltou nos if's de compra e venda as comparações deste open_time, por isso que o seu EA faz compra/venda e nao respeita a mesma vela


Espero que ajude

Vinicius de Oliveira #:

Olá, Christian, boa tarde!!

No tópico abaixo, o @NandoBueno apresentou questão semelhante e eu registrei uma sugestão. Aparentemente não funcionou para ele (não entendi direito o porquê), mas se você quiser dar uma olhada pra ver se lhe traz alguma ideia: ...



EDIT.1: Apenas reforçando a informação de que a variável open_time deve ser declarada no escopo global.


Bom dia senhores! Espero que estejam bem.


Gostaria de agradece-los por me auxiliarem, através da ideia de sua ideia Vinicius, e também do passo a passo do Eduardo, foi possível alcançar o objetivo desejado por esta pessoa que vos fala! Fiz algumas alterações para se adequar dentro da minha estrutura de código, segue abaixo como ficou o resultado final:


//======GLOBAL=======

datetime open_time_venda = 0;
datetime open_time_compra = 0;

//=====ONTICK=========

if(rates[1].close < lowBand[1] && tick.last > lowBand[0]){ //caso seja uma compra

        if(open_time_compra != iTime(_Symbol, PERIOD_CURRENT, 0)){
      
                Trade.Buy(Contratos, Symbol(), 0.00, 0.000, 0.000, NULL);
      
                open_time_compra = iTime(_Symbol, PERIOD_CURRENT, 0);
      
                Print("O open_time dentro do trade é: ", open_time_compra);
      
                addTakeStop(Stop_Loss, Take_Profit);
 
               }
      }
}
if(rates[1].close > upBand[1] && tick.last < upBand[0]){ //caso seja uma venda

         if(open_time_venda = iTime(_Symbol, PERIOD_CURRENT, 0)){

                Trade.Sell(Contratos, Symbol(), 0.00, 0.000, 0.000, NULL);
   
                open_time_venda = iTime(_Symbol, PERIOD_CURRENT, 0);
    
                 Print("O open_time dentro do trade é: ", open_time_venda);
    
                 addTakeStop(Stop_Loss, Take_Profit);
                
                }
        }
}
Vinicius Pereira De Oliveira  
Christian Alves #Bom dia senhores! Espero que estejam bem. Gostaria de agradece-los por me auxiliarem, através da ideia de sua ideia Vinicius, e também do passo a passo do Eduardo, foi possível alcançar o objetivo desejado por esta pessoa que vos fala! Fiz algumas alterações para se adequar dentro da minha estrutura de código, segue abaixo como ficou o resultado final:



Bom dia, Christian, prazer poder ajudar!!


Apenas dê uma olhadinha aí nessa parte do seu código original... O trecho que você postou faltou um sinal "!":

if(open_time_venda != iTime(_Symbol, PERIOD_CURRENT, 0))


Abraço!!

Christian Alves  
Vinicius de Oliveira #:


Bom dia, Christian, prazer poder ajudar!!


Apenas dê uma olhadinha aí nessa parte do seu código original... O trecho que você postou faltou um sinal "!":


Abraço!!


Muito obrigado por me atentar Vini, realmente havia esquecido o "!" ahahahaha, grande abraço!


Eduardo Oliveira #:

Boa garoto!!

NUNCA DUVIDEI!!

Abraço!


Obrigado meu irmão, grande abraço!

Edson A Santos  

Oi Christian, já experimentou a isNewbar? Acho que simplifica o código...

//+------------------------------------------------------------------+

void OnTick()

  {

   if(isNewBar())

     {

     }

  }


//+------------------------------------------------------------------+

bool isNewBar()

  {

   static datetime last_time=0;

   datetime lastbar_time=(datetime)SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE);


   if(last_time==0)

     {

      last_time=lastbar_time;

      return(false);

     }


   if(last_time!=lastbar_time)

     {

      last_time=lastbar_time;

      return(true);

     }

   return(false);

  }


//+------------------------------------------------------------------+

Razão: