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