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