Programação de Indicadores: Identificando os últimos negócios antes de desenhar a próxima barra!

Aproveitando que tenho compartilhado informações sobre a codificação de robôs no Metatrader5 (ainda em “indicadores“) e algumas dúvidas ou curiosidades estão surgindo, resolvi demonstrar o código que utilizo para identificar os últimos negócios ou nova barra.

A função isNewBar foi definida, inicialmente, para permitir a identificação de uma nova barra – o meu objetivo era abrir os cálculos a cada nova barra.

Parecia simples, bastava comparar “last_time!=lastbar_time” (ou seja, comparar valor atual com o anterior e retornar true quando os valores não forem iguais).

bool isNewBar(const datetime lastbar_time, const int prev_calc) {
   ...
   if (last_time==0 || init_time==0 || last_time!=lastbar_time) {
      last_time=lastbar_time;
      init_time=init_auxtime;
      if (last_time==0) return(false);
      return(true);
   }
   ...
   return(false);
}

O valor de lastbar_time é o horário da barra atual (baseado na abertura, e fornecido pela variável time[i]) – mudará apenas na próxima barra. E last_time é o último horário capturado.

Funciona perfeitamente para a primeira execução do indicador, quando prev_calculated for 0 (com dados históricos). Porém, a lógica não pode ser a mesma quando o indicador estiver analisando os negócios em tempo real.

Suponhamos que você queira trocar a cor do candle quando o preço de abertura for igual ao preço de fechamento (para fechar posição)…

Com os dados históricos (prev_calculated 0), a barra não é processada ticket a ticket. Então, se compararmos open com close assim que a função isNewBar retornar true, teremos a certeza de que open[i] representa o primeiro negócio e close[i] o último (no intervalo de tempo representado pela barra).

Pois é, mas o comportamento não será o mesmo quando prev_calculated for maior que 0 (em tempo real). Neste caso, assim que a próxima barra for desenhada, para o primeiro ticket, teremos open igual a close. Ou seja, a comparação será SEMPRE verdadeira logo que surgir a próxima barra.

Por esta razão, inclui o controle de tempo decorrido (time_match):

   ...
   datetime init_auxtime=TimeCurrent();
   ...
   // 5 minutos
   limit_time=300;
   time_match=(limit_time-(init_auxtime-init_time));
   ...
   if (last_time==0 || init_time==0 || last_time!=lastbar_time) {
      last_time=lastbar_time;
      init_time=init_auxtime;
      if (last_time==0) return(false);
   }

   if (prev_aux==0) return(true);
   else if (time_match<=1) {
      if (time_match<=0) {
         last_time=lastbar_time;
         init_time=init_auxtime;
         return(false);
      }
      return(true);
    }
    ...

Esta é uma das várias pegadinhas deste tipo de programação! 😉

Confiram, logo a seguir, a função completa:

...
int time_punish=0;
...
bool isNewBar(const datetime lastbar_time, const int prev_calc)
  {
//--- memorize the time of opening of the last bar in the static variable
   static datetime last_time=0;
   static datetime init_time=0;
   
   datetime init_auxtime=TimeCurrent();

   int limit_time=0,prev_aux=prev_calc;
   long time_match=0;
   
   limit_time=300;
   time_match=(limit_time-(init_auxtime-init_time));
   if (time_match<0) time_match=0;
   
   string label_name1="Seconds", label_text="Seconds... "+(string) (long)time_match;
   ObjectDelete(0, label_name1);
   ObjectCreate(0, label_name1, OBJ_LABEL, 0, 0, 0);
   //ObjectSetInteger(0,label_name1,OBJPROP_XDISTANCE,960);
   ObjectSetInteger(0,label_name1,OBJPROP_XDISTANCE,ChartGetInteger(0,CHART_WIDTH_IN_PIXELS,0)-100);
   ObjectSetInteger(0,label_name1,OBJPROP_YDISTANCE,30);
   ObjectSetInteger(0,label_name1,OBJPROP_COLOR,YellowGreen);
   ObjectSetString(0,label_name1,OBJPROP_TEXT,label_text);
   
//--- if it is the first call of the function or new bar
   if (last_time!=lastbar_time && trade_open>0) bars_trade++;
   if (last_time==0 || init_time==0 || last_time!=lastbar_time) {
      if (init_auxtime>=init_time+limit_time && init_time>0) prev_aux=0;
      time_punish=1;
      last_time=lastbar_time;
      init_time=init_auxtime;
      if (last_time==0) return(false);
   }

//--- allow after 5 minutes - 1s
   if (time_match>2 && time_match<250) time_punish=0;
   if (prev_aux==0) return(true);
   else if (time_match<=1) {
      if (time_match<=0) {
         last_time=lastbar_time;
         init_time=init_auxtime;
         time_punish=1;
         return(false);
      }
      if (time_punish==0) return(true);
   }
   
//--- if we passed to this line, then the bar is not new; return false
   return(false);
  }

"A primeira definição, com a criação de um objeto do tipo LABEL, exibirá o contador decrescente (time_match) dos segundos decorridos (300s ou 5min)"

O código responsável pelos cálculos fica limitado pela função isNewBar:

if (isNewBar(time[i], last)==true) {
   ...
   // codificação para mudança de cor do candlestick
   if (open[i]==close[i]) buf_color_line[i]=0;
   ...
}


Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *