Advice on custom indicator

 

I have transferred an indicator that is open source from pinescript to MQL5. The indicator works 99% of the time as intended however at times when it has been left for a while, the calculation seems to not be correct until it is refreshed starting the Oninit process over. At that point the values and indicator graphic match with the pinescript version. My knowledge of MQL5 is still low level so I know my code is not perfect but I would be really grateful for any advice/ criticism of my code and how to improve it's function, readability and/or efficiency. Ive attached both the pine and MQL5 versions below. 

// Pinescript version, not complete as the original script has extra code not relevant to the issue (this code is the core calculation)

f_pmarp( float _price, simple int _pmarLen, int _pmarpLen, string _type ) =>

    _pmarp = math.abs ( _price /  ta.vwma( _price, _type, _pmarLen ))

    _pmarpSum = 0

    _len = bar_index < _pmarpLen ? bar_index : _pmarpLen

    for i = 1 to _len by 1
        _pmarpSum += ( _pmarp[i] > _pmarp ? 0 : 1 )
        _pmarpSum

    _return = bar_index >= _pmarLen ? _pmarpSum / _len * 100 : na
        _return
#property description "PMARP by mcalc, credit to Caretaker"
//---- the indicator will be plotted in the main window
#property indicator_separate_window
//---- three buffers will be used for the calculations and plot of the indicator
#property indicator_buffers 4 
//---- only one graphic plot is used 
#property indicator_plots   1
//---- the indicator should be plotted as a line
#property indicator_type1   DRAW_LINE
//---- the color of the indicator's line is red 
#property indicator_color1  Red 

#property indicator_width1  2

// PMARP Long 

input group "PMARP"
input int     pmarpLookback = 350; // Lookback
input int     pmarpLength   = 50;  // Length 

//---- the declaration of the dynamic arrays
//that will be used further as an indicator's buffer
double pmarpArr[]; 
double pmarArr[];
double VWMAArr[];
double pmarpSumArr[];
double VWMAHandle;

void OnInit()
{
//----+
//---- assign the dynamic array pmarpArr with 0th indicator's buffer and other calculations with others
   SetIndexBuffer(0,pmarpArr,INDICATOR_DATA);
   ArraySetAsSeries(pmarpArr,true);
   
   SetIndexBuffer(1,pmarpSumArr,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(pmarpSumArr,true);
   
   SetIndexBuffer(2,pmarArr,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(pmarArr, true);
   
   SetIndexBuffer(3,VWMAArr,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(VWMAArr, true);

//---- set plot begin from the bar with number pmarpLookback
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,pmarpLookback);  

//---- declare handle for custom VWMA indicator 
   VWMAHandle = iCustom(NULL,0,"Market/VWMA Volume Weighted Moving Average",pmarpLength,VOLUME_TICK,PRICE_CLOSE);

}

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[]){
  
 
//----+ 
      //---- check for the presence of bars, sufficient for the calculation
   if (rates_total <= pmarpLookback ) return 0;
   // If stopped dont return anything
   if(IsStopped()) return 0;
   
 
   //---- declaration of local variables 
   int s=0;
   int pmarpSum;
   //Reverse Index close price 
   ArraySetAsSeries(close, true);
   
   //---- CopyBuffer function to pull VWMA values and place in custom array
   CopyBuffer(VWMAHandle,0,0,rates_total,VWMAArr);
   // Main Loop
   for(int i=0;i<rates_total;i++)
     {
      // Calculate all PMAR Values
      pmarArr[i]=MathAbs(close[i]/VWMAArr[i]);
      // Reset pmarpSum each bar
      pmarpSum = 0;
      // cycle through previous lookback bars and add 1 or 0 to sum if previous pmar value <||> current cycles value
      for (s = 0;s <pmarpLookback ;s++){
          pmarpSum += ( pmarArr[s] > pmarArr[i] ? 0 : 1 );
          
      }  
      // Add sum to array for that bar
      pmarpSumArr[i] = pmarpSum;
      // Calculate pmarp and normalise to 2dp
      pmarpArr[i] = NormalizeDouble((pmarpSumArr[i] / pmarpLookback) * 100,2);
             
     }
//----+     
   return(rates_total);
  }
                
//+------------------------------------------------------------------+
 
  1.       pmarArr[i]=MathAbs(close[i]/VWMAArr[i]);
    1. Buffers are automatically size, are as-series, and elements are moved for you, new elements are set to EMPTY_VALUE (or your designated. They can also draw on the chart automatically.

    2. In MT5, you must set the direction.

      To define the indexing direction in the time[], open[], high[], low[], close[], tick_volume[], volume[] and spread[] arrays, call the ArrayGetAsSeries() function. In order not to depend on defaults, call the ArraySetAsSeries() function for the arrays to work with.
                Event Handling / OnCalculate - Reference on algorithmic/automated trading language for MetaTrader 5

  2.    for(int i=0;i<rates_total;i++)
    

    You are recalculating all bars every tick.

    See How to do your lookbacks correctly #9#14 & #19. (2016)

 

Thank you for the advice! I'll read the articles and try to implement the changes. Appreciate it.


William Roeder #:
    1. Buffers are automatically size, are as-series, and elements are moved for you, new elements are set to EMPTY_VALUE (or your designated. They can also draw on the chart automatically.

    2. In MT5, you must set the direction.

  1. You are recalculating all bars every tick.

    See How to do your lookbacks correctly #9#14 & #19. (2016)