How to get iADXOnArray or iADX on custom array?

 

Good day everyone. I am trying to calculate the ADX value for an entire array. Is there a way I can substitute in my custom array into the iADX that comes with MT4? If not, I am already attempting to build an iADXOnArray function that I would like to be as accurate as if I had used iADX. I would appreciate any help or clarification. This is what I have so far:

edited on 6.3.19

//+------------------------------------------------------------------+

//| iADXOnArray                                                      |

//+------------------------------------------------------------------+

/*

 Calculate ADX on array.

 Data Length has to 15 or more to calculate DX.

 -1 will be the result if array has insufficient data.

*/

double iADXOnArray(double& aHigh[], double& aLow[], double& aClose[], int length){

   double pdm=-1,mdm=-1,tr=-1,pdm_sum=-1,mdm_sum=-1,tr_sum=-1,plusDI=0,minusDI=0,DIdiff=0,DIsum=0;

   double price_high,price_low,DX=-1;

   int i=0,j=0,min=15;

   int ADXPeriod=length;

   //double ADXBuffer[];

   double ADXresult=-1;

   


   double DXarr[];

      if(length >= 15)

      {

       ArrayResize(DXarr, length-min);

      }  

   

//----

i=1;

     while(i<length && length>1)

     {

      price_low=aLow[i];

      price_high=aHigh[i];

      //----

      pdm=price_high-aHigh[i-1];

      mdm=aLow[i-1]-price_low;

      if(pdm<0) pdm=0;  // +DM

      if(mdm<0) mdm=0;  // -DM

      if(pdm==mdm) { pdm=0; mdm=0; }

      else if(pdm<mdm) pdm=0;

           else if(mdm<pdm) mdm=0;

  

      double num1=MathAbs(price_high-price_low);

      double num2=MathAbs(price_high-aClose[i-1]);

      double num3=MathAbs(aClose[i-1]-price_low);

      tr=MathMax(num1,num2);

      tr=MathMax(tr,num3);

      Print("\n +DM = "+DoubleToStr(pdm));

      //Print("\n -DM = "+DoubleToStr(mdm));

      

      pdm_sum = pdm_sum + pdm;

      mdm_sum = mdm_sum + mdm;

      tr_sum= tr_sum + tr;

      


      plusDI = (pdm_sum/tr_sum)*100;

      minusDI = (mdm_sum/tr_sum)*100;

      DIdiff = plusDI - minusDI;

      DIdiff = MathAbs(DIdiff);

      DIsum = plusDI + minusDI;

      DX = (DIdiff/DIsum)*100;

         if(i>=15)

         {

          DXarr[j] = DX;

          j++;

         }


      

      i++;

     }



//---- ADX is exponential moving average on DX

     if(length >= 15)

     {

      ADXPeriod = (length-min);

      ADXresult = iMAOnArray(DXarr,(length-min),ADXPeriod,0,MODE_EMA,0); 

     }

     else

     {

      ADXresult = -1;

     }

//----

   return(ADXresult);

}

//+------------------------------------------------------------------+

//| End of iADXOnArray                                               |

//+------------------------------------------------------------------+


Is this the right approach?


 

Here is my example usage:

double ahigh[]={30.20,30.28,30.45,29.35,29.35,29.29,28.83,28.73,28.67,28.85,28.64,27.68,27.21,26.87,27.41,26.94};

double alow[]={29.41,29.32,29.96,28.74,28.56,28.41,28.08,27.43,27.66,27.83,27.40,27.09,26.18,26.13,26.63,26.13};
double aclose[]={29.87,30.24,30.10,28.90,28.92,28.48,28.56,27.56,28.47,28.28,27.49,27.23,26.35,26.33,27.03,26.22};

 double adx = iADXOnArray(ahigh,alow,aclose,16);

 Print("\n adx = "+DoubleToStr(adx));



I am getting an ADX value of 105.92. But ADX is supposed to be between 0 and 100, inclusive.

 

I think I have hit something:


//+------------------------------------------------------------------+

//| iADXOnArray                                                      |

//+------------------------------------------------------------------+

/*

 Calculate ADX on array.

 Data Length has to 15 or more to calculate DX.

 -1 will be the result if array has insufficient data.

*/

double iADXOnArray(double& aHigh[], double& aLow[], double& aClose[]){

   double pdm=0,mdm=0,tr=0,pdm_sum=0,mdm_sum=0,tr_sum=0,plusDI=0,minusDI=0,DIdiff=0,DIsum=0;

   double price_high,price_low,DX=0;

   double previous_pdm_sum=0,previous_mdm_sum=0,previous_tr_sum=0;

   int i=0,j=0,k=1,min=14;

   int length=ArrayRange(aClose,0);

   int ADXPeriod=length,dxlength=0,old_dxlength=0,adxlength=0,old_adxlength=0;

   double ADXresult=-1;

   double DXarr[],ADXarr[];

   i=1;

     while(i<length && length>1)

     {

      price_low=aLow[i];

      price_high=aHigh[i];

      

      //If High(i) - High(i-1) > 0  dm_plus(i) = High[(i) - High(i-1), otherwise dm_plus(i) = 0.    

      pdm=price_high-aHigh[i-1];

         if(pdm <= 0)pdm=0;

      

      

      //If Low(i-1) - Low(i) > 0  dm_minus(i) = Low(i-1) - Low(i), otherwise dm_minus(i) = 0.

      mdm=aLow[i-1]-price_low;

         if(mdm <= 0)mdm=0;  


         if(pdm==mdm) { pdm=0; mdm=0; }

         else if(pdm<mdm) pdm=0;

         else if(mdm<pdm) mdm=0;

  

      double num1=MathAbs(price_high-price_low);

      double num2=MathAbs(price_high-aClose[i-1]);

      double num3=MathAbs(aClose[i-1]-price_low);

      tr=MathMax(num1,num2);

      tr=MathMax(tr,num3);

         

         if(i<=min)

         {

          pdm_sum = pdm_sum + pdm;

          mdm_sum = mdm_sum + mdm;

          tr_sum= tr_sum + tr;

         }

         else if(i>min)

         {

          pdm_sum = (previous_pdm_sum - (previous_pdm_sum/14)) + pdm;

          

          mdm_sum = (previous_mdm_sum - (previous_mdm_sum/14)) + mdm;

           

          tr_sum  = (previous_tr_sum - (previous_tr_sum/14)) + tr;

         } 

      

      plusDI = (pdm_sum/tr_sum)*100;

      minusDI = (mdm_sum/tr_sum)*100;

      DIdiff = plusDI - minusDI;

      DIdiff = MathAbs(DIdiff);

      DIsum = plusDI + minusDI;

      DX = (DIdiff/DIsum)*100;

         if(i>=min)

         {        

          old_dxlength = ArrayRange(DXarr,0);

          dxlength= old_dxlength+1;

          ArrayResize(DXarr, dxlength);           

          DXarr[old_dxlength] = DX;                     

          previous_pdm_sum = pdm_sum;          

          previous_mdm_sum = mdm_sum;                 

          previous_tr_sum = tr_sum;                             

         }


//---- ADX is simple/exponential moving average on DX

         if(dxlength == min)

         {

          ADXPeriod = (length-min);

          old_adxlength = ArrayRange(ADXarr,0);

          adxlength = old_adxlength + 1;

          ArrayResize(ADXarr, adxlength); 

          ADXarr[0] = iMAOnArray(DXarr,0,dxlength,0,MODE_EMA,0);  

         }

         else if(dxlength > min)

         {

          //ADXt= ( ( ADXt-1 * ( n - 1) ) + DXt ) / n 

          old_adxlength = ArrayRange(ADXarr,0);

          adxlength = old_adxlength + 1;

          ArrayResize(ADXarr, adxlength);           

          ADXarr[old_adxlength] = ( ( (ADXarr[old_adxlength-1] * 13) + DX) / 14 );

         }          

      i++;

     }


//----use ADX array size

     if(adxlength > 0)

     {

      ADXresult = ADXarr[adxlength - 1];

     }  

     else

     {

      ADXresult = -1;

     }

//----

   return(ADXresult);

}

//+------------------------------------------------------------------+

//| End of iADXOnArray                                               |

//+------------------------------------------------------------------+


Now, I have read somewhere that the first ADX value is the simple average of DX  over 14 periods.  Is it Ok, if I use the exponential average of DX for the first ADX value: "ADXarr[0] = iMAOnArray(DXarr,0,dxlength,0,MODE_EMA,0);" instead of "ADXarr[0] = iMAOnArray(DXarr,0,dxlength,0,MODE_SMA,0);"  ?  

Reason: