Indicador Apresentando Lentidão

 

Bom dia a todos!

Espero que estejam bem.

Estou fazendo a adaptação de um indicador (CurrencySlopeStrength) que, para quem não conhece, apresenta um comportamento semelhante ao de outros osciladores, como RSI, Stochastic etc.

No entanto, tenho percebido que o indicador fica pesado quando é anexado a vários gráficos, especialmente na primeira abertura do MT4.

A função OnCalculate está conforme o código abaixo. Há algo que eu possa fazer para otimizar o desempenho desse indicador?

Desde já, agradeço pela atenção e pela colaboração de todos.

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[])
  {
   int lastBar = rates_total - 1;
   if(lastBar < 0)
      return(0);

   // inpMaxBars = 200
   int limit = lastBar;
   if(inpMaxBars > 0)
      limit = MathMin(limit, inpMaxBars - 1);

   int startt;

   if(prev_calculated <= 0 || prev_calculated > rates_total)
     {
      startt = limit;
     }
   else
     {
      int lastDone = prev_calculated - 1;

      startt = MathMin(lastDone, limit);

      if(startt < 1)
         startt = 1;
     }

   for(int i = startt; i >= 0; i--)
     {
      ArrayInitialize(GBLCurrencyValues, 0.0);

      CalculateAllCurrenciesSlope(GBLBaseTF, time[i]);

      FillIndicatorBuffers(i);

      if(i == 1)
         ArrayCopy(GBLCurrencyValuesPrior, GBLCurrencyValues);

      if(i == 0)
         ManageDashboard(window);
     }

   if(GBLShowLevelCross)
     {
      DrawLevelLines(window);
      DrawLineLabels(window, time[0]);
     }
   else
     {
      ObjectDelete(GBLUniquePrefix + "HLine_High");
      ObjectDelete(GBLUniquePrefix + "HLine_Low");
     }

   return(rates_total);
  }
Documentação sobre MQL5: Funções de Manipulação de Evento / Elementos Básicos da Linguagem
Documentação sobre MQL5: Funções de Manipulação de Evento / Elementos Básicos da Linguagem
  • www.mql5.com
A linguagem MQL5 fornece processamento de alguns eventos pré-definidos . Funções para manipulação destes eventos...
 
Jeovane Reges:

Bom dia a todos!

Espero que estejam bem.

Estou fazendo a adaptação de um indicador (CurrencySlopeStrength) que, para quem não conhece, apresenta um comportamento semelhante ao de outros osciladores, como RSI, Stochastic etc.

No entanto, tenho percebido que o indicador fica pesado quando é anexado a vários gráficos, especialmente na primeira abertura do MT4.

A função OnCalculate está conforme o código abaixo. Há algo que eu possa fazer para otimizar o desempenho desse indicador?

Desde já, agradeço pela atenção e pela colaboração de todos.

Pergunta: Por que motivos você está calculando todo o RANGE DE BARRAS PRESENTES NO GRÁFICO ? 🤔😵 Mas mesmo que tenha algum motivo, este seu LAÇO FOR está muito, mas muito mal otimizado. A chamada ArrayInitialize está sendo chamada a cada interação. Por que você precisa zerar todo array a cada interação do LAÇO ? Mas independente disto, o motivo pelo qual ele se apresenta LENTO no momento em que você adiciona ele ao gráfico, se deve ao fato, de que na primeira execução, você está varrendo TODO O HISTÓRICO 😱, independentemente da quantidade de barras presentes nele. E quanto mais barras existir, mais lento o indicador irá ficar na primeira execução. Melhore isto e seu indicador ficará mais rápido no momento em que for adicionado ao gráfico. 🙂👍

 
CODE X #:

Pergunta: Por que motivos você está calculando todo o RANGE DE BARRAS PRESENTES NO GRÁFICO ? 🤔😵 Mas mesmo que tenha algum motivo, este seu LAÇO FOR está muito, mas muito mal otimizado. A chamada ArrayInitialize está sendo chamada a cada interação. Por que você precisa zerar todo array a cada interação do LAÇO ? Mas independente disto, o motivo pelo qual ele se apresenta LENTO no momento em que você adiciona ele ao gráfico, se deve ao fato, de que na primeira execução, você está varrendo TODO O HISTÓRICO 😱, independentemente da quantidade de barras presentes nele. E quanto mais barras existir, mais lento o indicador irá ficar na primeira execução. Melhore isto e seu indicador ficará mais rápido no momento em que for adicionado ao gráfico. 🙂👍

Boa tarde.

Primeiramente, muito obrigado pelo feedback.

Você tem razão sobre a ineficiência do loop apresentado. A minha intenção original, na verdade, era evitar o uso de funções dependentes da interface, como WindowFirstVisibleBar() e WindowBarsPerChart(), para manter os buffers calculados em todo o histórico.

Porém, devido ao peso do cálculo de força das moedas (que varre múltiplos pares) e à lentidão severa na inicialização, fui 'obrigado' a adotar a abordagem de cálculo apenas da janela visível. Foi a solução necessária (que encontrei) para garantir a fluidez do indicador no gráfico.

A minha tentativa inicial de controle de loop via rates_total e prev_calculated mostrou-se instável. Em alguns cenários, especialmentle ao abrir o MT4, onde era necessário forçar o recálculo do indicador (alternando timeframes ou ativos) para corrigir a visualização. Ou seja, ao reiniciar a plataforma, o histórico apresentava distorções visuais (semelhantes a 'lanças' ou spikes), causadas por lacunas nos dados. Diante dessas limitações, optei por uma solução focada no processamento exclusivo dos dados da janela visível.

Caso você conheça uma alternativa mais viável e eficiente, estou a disposição para ouvi-lá.

Segue abaixo como ficou a correção final para limitar o cálculo ao range visível:

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[])
  {
   if(rates_total < 2)
      return 0;

   if(!IsHistoryReady())
      return 0;

   int firstBar  = WindowFirstVisibleBar();
   int barsChart = WindowBarsPerChart();

   int lastBar   = firstBar - barsChart;
   if(lastBar < 0)
      lastBar = 0;

   static int prevFirstBar  = 0;
   static int prevBarsChart = 0;
   static datetime lastTime = 0;

   bool fullRecalculate = (firstBar != prevFirstBar ||
                           barsChart != prevBarsChart ||
                           time[0] != lastTime ||
                           prev_calculated == 0);

   prevFirstBar = firstBar;
   prevBarsChart = barsChart;
   lastTime = time[0];

   int startBar, endBar;

   if(fullRecalculate)
     {
      startBar = firstBar;
      endBar   = lastBar;

      if(inpMaxBars > 0)
        {
         int maxStart = firstBar - inpMaxBars + 1;
         if(maxStart < 0)
            maxStart = 0;

         if(endBar < maxStart)
            endBar = maxStart;
        }

      for(int buffer = rates_total - 1; buffer > startBar; buffer--)
        {
         arrUSD[buffer] = EMPTY_VALUE;
         arrEUR[buffer] = EMPTY_VALUE;
         arrGBP[buffer] = EMPTY_VALUE;
         arrCHF[buffer] = EMPTY_VALUE;
         arrJPY[buffer] = EMPTY_VALUE;
         arrAUD[buffer] = EMPTY_VALUE;
         arrCAD[buffer] = EMPTY_VALUE;
         arrNZD[buffer] = EMPTY_VALUE;
        }
     }
   else
     {
      startBar = 0;
      endBar   = 0;
     }

   for(int bar = startBar; bar >= endBar; bar--)
     {
      ArrayInitialize(GBLCurrencyValues, 0.0);

      CalculateAllCurrenciesSlope(GBLBaseTF, bar);

      FillIndicatorBuffers(bar);

      if(inpWeighOnlyChart)
         DrawChartSymbolBackground(bar, time[bar], windex);

      if(bar == 1)
         ArrayCopy(GBLCurrencyValuesPrior, GBLCurrencyValues);

      if(bar == 0)
         ManageDashboard(windex);
     }

   if(GBLShowLevelCross)
     {
      DrawLevelLines(windex);
      DrawLineLabels(windex, time[0]);
     }
   else
     {
      ObjectDelete(GBLUniquePrefix + "HLine_High");
      ObjectDelete(GBLUniquePrefix + "HLine_Low");
     }

   return(rates_total);
  }

bool IsHistoryReady()
  {
   if(GBLSymbolCount == 0)
      return false;

   for(int i = 0; i < GBLSymbolCount; i++)
     {
      string sym = GBLSymbolNames[i];

      if(!SymbolSelect(sym, true))
         continue;

      int barsAvailable = iBars(sym, GBLBaseTF);

      if(barsAvailable <= 0)
        {
         iClose(sym, GBLBaseTF, 0);
         return false;
        }
     }

   return true;
  }