Custom indicator working but freezing a lot, can you guys help please?

 

Dear all, I created the code for the indicator below, whose objective is to show a theoretical value for the minidollar (WINFUT, which is the USDBRL symbol) depending on the variation of the minidollar (WDOFUT, brazilian main index symbol). The rationale is: if WDOFUT is falling 0.5% I reverse the sign of this fall and consider that WINFUT should be rising 0.5%.

It works correctly, but it makes the graph slow. Could anyone take a look and see if they can find the problem that is making it difficult (slowness in the graph)? 

Additional details: the OnCalculate is called more than 4 thousand times per minute. I think this might be the problem, it is overwhelming for metatrader. But I dont need that high frequency. Is it possible to plot the indicator with less frequency? Lets say, 10 times per minute... it would be nice to plot the indicator using OnTimer instead of OnCalculate but I am not sure if mt5 allows it, anyone knows?

input int janela=10;

input double multiplicador = -1;
datetime StartTime=D'2024.06.18 09:01:00';
double PrecoPartidaDoMini=0;
double PrecoPartidaWDO=0;

input int tetoDePlot=400;
int contaOnCalculate=0;
enum modoEnum 
  {
      
   precoVSjanela=0,        
   precoVSpartida=1,  
   
  };
//--- input parameters
input modoEnum modoDrop=precoVSjanela;
//+------------------------------------------------------------------+
//|                                                 Ind_Cesta_v3.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot Label1
#property indicator_label1  "Label1"
//#property indicator_type1   DRAW_ARROW
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrOrange
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- indicator buffers
double         Label1Buffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,Label1Buffer,INDICATOR_DATA);
   
   ArraySetAsSeries(Label1Buffer,true);
   
   tf=_Period;
   papelNaTela=_Symbol;
   
   //ArrayResize(Label1Buffer,tetoDePlot);

PrecoPartidaDoMini=precoEmFuncaoDoTempo("WIN$", StartTime, 0);
PrecoPartidaWDO=precoEmFuncaoDoTempo("WDO$", StartTime, 0);      

//PrecoPartidaDoMini=iOpen("WIN$",PERIOD_D1,0);  
//PrecoPartidaWDO=iOpen("WDO$",PERIOD_D1,0);     
   
//Print("iTime(WIN$,PERIOD_D1,0)",iTime("WIN$",PERIOD_D1,0));
//Print("iTime(WIN$,PERIOD_D1,1)",iTime("WIN$",PERIOD_D1,1));
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
double aux=0;

ENUM_TIMEFRAMES tf=_Period;
string papelNaTela=_Symbol;


int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   contaOnCalculate++;
   //bool cPapel = papelNaTela == "WIN$" || papelNaTela == "WINQ24";
   //if(tf != PERIOD_M1 || !cPapel )
   //   return -1;
bool condicao=segundo(TimeCurrent()==10) || segundo(TimeCurrent()==20) || segundo(TimeCurrent()==30) || segundo(TimeCurrent()==40) || segundo(TimeCurrent()==50) || segundo(TimeCurrent()==59);
//   
//   if(!condicao) 
//     {
//      return tetoDePlot-1;
//     }
      
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(open,true);
   
   //if(condicao)
   //for(int i=MathMin(tetoDePlot,tetoDePlot-prev_calculated);i>=0;i--)
   for(int i=0;i<MathMin(tetoDePlot,tetoDePlot-prev_calculated);i++)
   //for(int i=0;i<1000;i++)
   {
   
      aux=0;
      //bool c1=hora(iTime("WINQ24",PERIOD_M1,i))>9;
      //bool c2=(hora(iTime("WINQ24",PERIOD_M1,i))==10 && minuto(iTime("WINQ24",PERIOD_M1,i))>janela)||hora(iTime("WINQ24",PERIOD_M1,i))!=10;
      //bool cFinal1=hora(iTime("WINQ24",PERIOD_M1,i))<17;//(hora(iTime("WINQ24",PERIOD_M1,i))==16) && minuto(iTime("WINQ24",PERIOD_M1,i))>49)||
      //bool cFinal2=hora(iTime("WINQ24",PERIOD_M1,i))==16 && minuto(iTime("WINQ24",PERIOD_M1,i))>49;
      //bool cDia=dia(iTime("WINQ24",PERIOD_M1,i))==dia(iTime("WINQ24",PERIOD_M1,0));
      ////bool c4=c1 && c2 && cFinal1 && !cFinal2;
      //bool c4=true;
      //Label1Buffer[i]=iLow(_Symbol,_Period,iLowest(_Symbol,_Period,MODE_LOW,20,i+5));     
      //Label1Buffer[i]=close[i];     
      //Label1Buffer[i]=close[i];     
      
      //aux=-100*(precoEmFuncaoDoTempo("WDO$", iTime("WINQ24",PERIOD_M1,i),0)/precoEmFuncaoDoTempo("WDO$", iTime("WINQ24",PERIOD_M1,i),janela)-1);
      
      PrecoPartidaWDO=PrecoOpenDia("WDO$",iTime("WIN$",_Period,i));   
      PrecoPartidaDoMini=PrecoOpenDia("WIN$",iTime("WIN$",_Period,i));   
      
      
      if(modoDrop==0)
         aux=100*(precoEmFuncaoDoTempo("WDO$", iTime("WINQ24",_Period,i),0)/precoEmFuncaoDoTempo("WDO$", iTime("WINQ24",_Period,i),janela)-1);
      
      
      if(modoDrop==1)
         aux=100*(precoEmFuncaoDoTempo("WDO$", iTime("WINQ24",_Period,i),0)/PrecoPartidaWDO-1);             
      
      
      //if(c4)
      //   Label1Buffer[i]=aux*close[i+janela]/100+close[i+janela];
      
      if(modoDrop==0)
         Label1Buffer[i]=multiplicador*(aux/1)*close[i+janela]/100+close[i+janela];
      
      if(modoDrop==1)
         Label1Buffer[i]=multiplicador*(aux/1)*PrecoPartidaDoMini/100+PrecoPartidaDoMini;
      
      //if(!c4)
      //   Label1Buffer[i]=0;      
      
      
      
   }//for i
   
   if(isNewBarMinuto())
   {
      Print("contaOncalculateLinhaWDO: ",contaOnCalculate);
      contaOnCalculate=0;
   }    
   
//Print("somaTotalPesos",somaTotalPesos);
   
//   if(isNewBarMinuto())
//   {
//      Print("rates_total: ",rates_total);
//      Print("prev_calculated: ",prev_calculated);
//      Print("Label1Buffer[0]: ",Label1Buffer[0]);
//      Print("precoEmFuncaoDoTempo[ITUB4,200]: ",precoEmFuncaoDoTempo("ITUB4", iTime("WINQ24",PERIOD_M1,200),15));
//      
//   }
//--- return value of prev_calculated for next call
   return(tetoDePlot-1);
  }
//+------------------------------------------------------------------+
bool isNewBarMinuto()
  {
//--- memorize the time of opening of the last bar in the static variable
   static datetime last_time=0;
//--- current time
   datetime lastbar_time=SeriesInfoInteger(Symbol(),PERIOD_M1,SERIES_LASTBAR_DATE);

//--- if it is the first call of the function
   if(last_time==0)
     {
      //--- set the time and exit
      last_time=lastbar_time;
      return(false);
     }

//--- if the time differs
   if(last_time!=lastbar_time)
     {
      //--- memorize the time and return true
      last_time=lastbar_time;
      return(true);
     }
//--- if we passed to this line, then the bar is not new; return false
   return(false);
  }
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
double variacao(string papel, int posicao)
{
double resp=0;

if(iClose(papel,PERIOD_M1,posicao+janela)>0)
  {
   resp=(iClose(papel,PERIOD_M1,posicao)/iClose(papel,PERIOD_M1,posicao+janela)-1)*100;
  }

return resp;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
double precoEmFuncaoDoTempo(string papel, datetime tempo, int delta)
{
//double resp=0;
//
//if(iClose(papel,PERIOD_M1,posicao+janela)>0)
//  {
//   resp=(iClose(papel,PERIOD_M1,posicao)/iClose(papel,PERIOD_M1,posicao+janela)-1)*100;
//  }

//iTime("WINM24",PERIOD_M1,i)
//datetime when;//=D'2024.05.14 15:00';
//when = StringToTime(tempo15h);
int  iWhenM1 = iBarShift(papel, PERIOD_M1, tempo);

//Print("iWhenM1 :",iWhenM1);
double close = iClose(papel, PERIOD_M1, iWhenM1+delta);

return close;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int segundo(datetime time1){
MqlDateTime time1string;
TimeToStruct(time1,time1string);
return time1string.sec;
}  
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int dia(datetime time1){
MqlDateTime time1string;
TimeToStruct(time1,time1string);
return time1string.day;
}  
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int hora(datetime time1){
MqlDateTime time1string;
TimeToStruct(time1,time1string);
return time1string.hour;
}  
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int minuto(datetime time1){
MqlDateTime time1string;
TimeToStruct(time1,time1string);
return time1string.min;
}  
//---------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int mes(datetime time1){
MqlDateTime time1string;
TimeToStruct(time1,time1string);
return time1string.mon;
}  
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
int ano(datetime time1){
MqlDateTime time1string;
TimeToStruct(time1,time1string);
return time1string.year;
}  
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
double deltaPrecoPctBvsA(double A, double B)
{
double resp=0;

if(B>0)
   resp=B/A-1;

resp=resp*100;

return resp;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
double deltaPrecoPctJanela(string papel, int i)
{
double novo = precoEmFuncaoDoTempo(papel, iTime("WINQ24",PERIOD_M1,i),0);
double antigo = precoEmFuncaoDoTempo(papel, iTime("WINQ24",PERIOD_M1,i),janela);

double resp = deltaPrecoPctBvsA(antigo,novo);

return resp;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
double PrecoOpenDia(string symbol, datetime tempo)
{

string mesString=IntegerToString(mes(tempo)); 
string diaString=IntegerToString(dia(tempo)); 
if(mes(iTime(_Symbol,PERIOD_D1,0))<10)
   mesString="0"+IntegerToString(mes(tempo)); 

if(dia(iTime(_Symbol,PERIOD_D1,0))<10)
   diaString="0"+IntegerToString(dia(tempo));
   
string tempoOpenDia;//=ano(TimeCurrent())+"."+mes(TimeCurrent())+"."+dia(TimeCurrent())+"."+_Symbol+"1"+".Compra."+".TXT";  
tempoOpenDia=ano(TimeCurrent())+"."+mesString+"."+diaString;
//------++----------------------++-----------
//string tempo15h=ano(TimeCurrent())+ mes(TimeCurrent()) +dia(TimeCurrent())+" 15";
datetime when;//=D'2024.05.14 15:00'; 
when = StringToTime(tempoOpenDia);
int  iWhenM1 = iBarShift(symbol, PERIOD_D1, when);
//Print("iWhenM1 :",iWhenM1);
double Open = iOpen(symbol, PERIOD_D1, iWhenM1);

return Open;
}
 
Good morning
If as you say, you don't need to do the calculations all the time

Limit to new bars only

 if ( prev_calculated < rates_total)
A lot of my code in codebases starts in oncalculate like this

for example the one I added this morning

Free download of the 'MovingAverages.mqh Part II by Wiliam210' indicator by 'William210' for MetaTrader 5 in the MQL5 Code Base, 2024.06.22

Another, more complex solution is to set a timer of the duration you want.
MovingAverages.mqh Part II by Wiliam210
MovingAverages.mqh Part II by Wiliam210
  • www.mql5.com
How to use Metaquotes native smoothing functions in MovingAverages.mqh SimpleMAOnBuffer(), ExponentialMAOnBuffer(), SmoothedMAOnBuffer(), and 2 LinearWeightedMAOnBuffer()
 
Gerard Willia G J B M Dinh Sy #: Limit to new bars only
 if ( prev_calculated < rates_total)

You can't know when a candle closes. Only when a new tick arrives that starts a new bar is the old bar closed, and that tick could arrive almost at the end of a bar's duration.

For a new bar test, Bars is unreliable (a refresh/reconnect can change number of bars on chart), volume is unreliable (miss ticks), Price is unreliable (duplicate prices and The == operand. - MQL4 programming forum.) Always use time.
          MT4: New candle - MQL4 programming forum #3 (2014)
          MT5: Accessing variables - MQL4 programming forum #3 (2022)

I disagree with making a new bar function, because it can only be called once per tick (second call returns false). A variable can be tested multiple times.
          Running EA once at the start of each bar - MQL4 programming forum (2011)

 


Champagne !!!!
 
Gerard Willia G J B M Dinh Sy #:


Champagne !!!!

Thank you guys. I will try the suggested approaches. I already made a solution for "cold analysis", which is, to plot the data I calculated in the chart when the markets are closed ( I did a function within a EA to plot objects OBJ_TREND for each candle) It is not a definitive solution but at least I can visually teste if the the calculations are useful. I start to hate the mql5 indicator way of event handlings... If my analysis turns out to be useful I will still need a way to plot it on a live chart during market hours...