How can I optimize this code? It runs very slowly during the first initialization of the indicators.

 
How can I optimize this code? It runs very slowly during the first initialization of the indicators. The final calculations of  ergoCCIBuf  and  triggerBuf  depend on the preceding buffers.
#property indicator_separate_window
#property indicator_buffers 8
#property indicator_plots   2

#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1 clrDeepSkyBlue
#property indicator_color2 clrYellow
#property indicator_width1 1
#property indicator_width2 1
#property indicator_style1 STYLE_SOLID
#property indicator_style2 STYLE_SOLID

#define ITS IntegerToString


input int PQ = 10;
input int PR = 10;
input int PS = 5;
input int PT = 3;
input int Dist = 5;

double ergoCCIBuf[];
double triggerBuf[];
double closeBuf[];
double emaBuf1[];
double emaBuf2[];
double closeAbsBuf[];
double emaBuf3[];
double emaBuf4[];
datetime warnTime;
string longOrShortStr;
string longOrShortStrFlag;
string indicatorName;


void OnInit() {

  SetIndexBuffer(0, ergoCCIBuf, INDICATOR_DATA);
  SetIndexBuffer(1, triggerBuf, INDICATOR_DATA);

  SetIndexBuffer(2, closeBuf, INDICATOR_CALCULATIONS);
  SetIndexBuffer(3, emaBuf1, INDICATOR_CALCULATIONS);
  SetIndexBuffer(4, emaBuf2, INDICATOR_CALCULATIONS);
  SetIndexBuffer(5, closeAbsBuf, INDICATOR_CALCULATIONS);
  SetIndexBuffer(6, emaBuf3, INDICATOR_CALCULATIONS);
  SetIndexBuffer(7, emaBuf4, INDICATOR_CALCULATIONS);

  ArraySetAsSeries(ergoCCIBuf, true);
  ArraySetAsSeries(triggerBuf, true);
  ArraySetAsSeries(closeBuf, true);
  ArraySetAsSeries(emaBuf1, true);
  ArraySetAsSeries(emaBuf2, true);
  ArraySetAsSeries(closeAbsBuf, true);
  ArraySetAsSeries(emaBuf3, true);
  ArraySetAsSeries(emaBuf4, true);

  PlotIndexSetString(0, PLOT_LABEL, "Ergo CCI");
  PlotIndexSetString(1, PLOT_LABEL, "Trigger");
  IndicatorSetInteger(INDICATOR_DIGITS, _Digits - 4);

  indicatorName = "Sniper Trigger(" + ITS(PQ) + ", " + ITS(PR) + ", " + ITS(PS) + ", " + ITS(PT) + ")";
  return;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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 start, counted_bars = prev_calculated;
  if (rates_total < PT) return (-1);
  start = rates_total - PQ - 1;
  if (counted_bars >= PQ) start = rates_total - (counted_bars - 1);

  ArraySetAsSeries(close, true);
  ArraySetAsSeries(time, true);
 
  for (int i = start; i >= 0; i--) {
    closeBuf[i] = close[i] - close[i + 1];
    closeAbsBuf[i] = MathAbs(closeBuf[i]);
    emaBuf1[i] = iMAOnArray(closeBuf, 0, PQ, 0, MODE_EMA, i);
    emaBuf2[i] = iMAOnArray(emaBuf1, 0, PR, 0, MODE_EMA, i);
    emaBuf3[i] = iMAOnArray(closeAbsBuf, 0, PQ, 0, MODE_EMA, i);
    emaBuf4[i] = iMAOnArray(emaBuf3, 0, PR, 0, MODE_EMA, i);
    ergoCCIBuf[i] = 500.0 * iMAOnArray(emaBuf2, 0, PS, 0, MODE_EMA, i) / iMAOnArray(emaBuf4, 0, PS, 0, MODE_EMA, i);
    triggerBuf[i] = iMAOnArray(ergoCCIBuf, 0, PT, 0, MODE_EMA, i);
  }
 

  return rates_total;
}
 
//+------------------------------------------------------------------+
double iMAOnArray(double &__array[], int __total, int __period, int __ma_shift, int __ma_method, int __shift) {
  double __Buffer[], __Array[];

  if (__total == 0)
    __total = ArraySize(__array);

  if (__total > 0 && __total <= __period)
    return (0);

  if (__shift > __total - __period - __ma_shift)
    return (0);

  switch (__ma_method) {
  case MODE_SMA : {
    __total = ArrayCopy(__Array, __array, 0, __shift + __ma_shift, __period);

    if (ArrayResize(__Buffer, __total) < 0)
      return (0);

    double __Sum = 0;
    int __Position = __total - 1;

    for (int __Index = 1; __Index < __period; __Index++, __Position--)
      __Sum += __Array[__Position];

    while (__Position >= 0) {
      __Sum += __Array[__Position];
      __Buffer[__Position] = __Sum / __period;
      __Sum -= __Array[__Position + __period - 1];
      __Position--;
    }

    return (__Buffer[0]);
  }
  case MODE_EMA : {
    if (ArrayResize(__Buffer, __total) < 0)
      return (0);

    double __pr = 2.0 / (__period + 1);
    int __Position = __total - 2;

    while (__Position >= 0) {
      if (__Position == __total - 2)
        __Buffer[__Position + 1] = __array[__Position + 1];

      __Buffer[__Position] = __array[__Position] * __pr + __Buffer[__Position + 1] * (1 - __pr);
      __Position--;
    }

    return (__Buffer[__shift + __ma_shift]);
  }
  case MODE_SMMA : {
    if (ArrayResize(__Buffer, __total) < 0)
      return (0);

    double __Sum = 0;
    int __Position = __total - __period;

    while (__Position >= 0) {
      if (__Position == __total - __period) {
        for (int __Index = 0, __Element = __Position; __Index < __period; __Index++, __Element++) {
          __Sum += __array[__Element];
          __Buffer[__Element] = 0;
        }
      } else
        __Sum = __Buffer[__Position + 1] * (__period - 1) + __array[__Position];

      __Buffer[__Position] = __Sum / __period;
      __Position--;
    }

    return (__Buffer[__shift + __ma_shift]);
  }
  case MODE_LWMA : {
    if (ArrayResize(__Buffer, __total) < 0)
      return (0);

    double __Sum = 0.0, __LinearSum = 0.0;
    double __Price;

    int __Index, __Weight = 0, __Position = __total - 1;

    for(__Index = 1; __Index <= __period; __Index++, __Position--) {
      __Price = __array[__Position];
      __Sum += __Price * __Index;
      __LinearSum += __Price;
      __Weight += __Index;
    }

    __Position++;
    __Index = __Position + __period;

    while (__Position >= 0) {
      __Buffer[__Position] = __Sum / __Weight;

      if (__Position == 0)
        break;

      __Position--;
      __Index--;
      __Price = __array[__Position];
      __Sum = __Sum - __LinearSum + __Price * __period;
      __LinearSum -= __array[__Index];
      __LinearSum += __Price;
    }

    return (__Buffer[__shift + __ma_shift]);
  }

  default:
    return (0);
  }

  return (0);
}
//+------------------------------------------------------------------+
 
hini:
How can I optimize this code? It runs very slowly during the first initialization of the indicators. The final calculations of  ergoCCIBuf  and  triggerBuf  depend on the preceding buffers.
The problem is the design of your iMAOnArray.

The EMA algorithm itself is very efficient, but your implementation isn't utilizing it.

In short:
EMA loop requires an initialization value. On first run that is an SMA value. From there on it is the last EMA value that was calculated.

SMMA and LWMA are just variants of the EMA.

Suggested solution:
Since the EMA algorithm requires a state that depends on the series it is calculated on, I would implement it as an object/class/struct.

Same goes for SMA, use a ring buffer to efficiently calculate the SMA.
 
Dominik Egert #:
The problem is the design of your iMAOnArray.

The EMA algorithm itself is very efficient, but your implementation isn't utilizing it.

In short:
EMA loop requires an initialization value. On first run that is an SMA value. From there on it is the last EMA value that was calculated.

SMMA and LWMA are just variants of the EMA.

Suggested solution:
Since the EMA algorithm requires a state that depends on the series it is calculated on, I would implement it as an object/class/struct.

Same goes for SMA, use a ring buffer to efficiently calculate the SMA.
Thank you for your reply. I have resolved this issue. The problem indeed lies in the iMAOnArray function, which caused a lot of redundant calculations. Now I have changed to use the official library function ExponentialMAOnBuffer, which only needs to calculate once. The loading speed of the indicator has returned to normal.
  for (int i = start; i >= 0; i--) {
    closeBuf[i] = close[i] - close[i + 1];
    closeAbsBuf[i] = MathAbs(closeBuf[i]);
  }
  ExponentialMAOnBuffer(rates_total, prev_calculated, 0, PQ, closeBuf, emaBuf1);
  ExponentialMAOnBuffer(rates_total, prev_calculated, 0, PR, emaBuf1, emaBuf2);
  ExponentialMAOnBuffer(rates_total, prev_calculated, 0, PQ, closeAbsBuf, emaBuf3);
  ExponentialMAOnBuffer(rates_total, prev_calculated, 0, PR, emaBuf3, emaBuf4);
  ExponentialMAOnBuffer(rates_total, prev_calculated, 0, PS, emaBuf2, emaBuf5);
  ExponentialMAOnBuffer(rates_total, prev_calculated, 0, PS, emaBuf4, emaBuf6);
  for (int i = start; i >= 0; i--) {
    ergoCCIBuf[i] = 500.0 * emaBuf5[i] / emaBuf6[i];
  }
  ExponentialMAOnBuffer(rates_total, prev_calculated, 0, PT, ergoCCIBuf, emaBuf7);
  for (int i = start; i >= 0; i--) {
    triggerBuf[i] = emaBuf7[i];
  }