Percent Rank and Percentile Value

 

Hi people!

I really do not like MathMedian(), and I rather use the following code to calculate percentile values from a percent rank input. However, I have been unable to code an efficient indicator from it. Can anyone make a indicator that works from it?

//+------------------------------------------------------------------+
//|                                                    Quantiles.mqh |
//|                                                    Arthur Albano |
//|                            https://www.facebook.com/arthuralbano |
//+------------------------------------------------------------------+
#property copyright "Arthur Albano"
#property link      "https://www.facebook.com/arthuralbano"
#include <Math\Stat\Math.mqh>
//+------------------------------------------------------------------+
//| Computes the interpolated percentile value of an array[]         |
//| todo: check for Mendenhall & Sicich (C=0)                        |
//+------------------------------------------------------------------+
double MathPercentileValue(double &array[], const double &percent_rank, const int C=0)
  {
//---
    double percentile_value = 0.0;

//---
    int size=ArraySize(array);

//--- check data range
    if(size==0)
        return(QNaN);

//--- check for percent rank [0..1]
    if(percent_rank<0 || percent_rank>1)
        return(QNaN);
        
//--- simple case: one element
    if(size==1)
        return(array[0]);

   double rank;
   rank = (size - 1) * percent_rank;
   
   int left_rank;
   left_rank = (int)MathCeil(rank);
   double left_weight;
   left_weight = (rank + 1 ) - double(left_rank);
   
   int right_rank;
   right_rank = (int)MathFloor(rank);
   double right_weight;
   right_weight = 1 - left_weight;
   
//--- prepare sorted values
   double sorted_values[];
   ArrayResize(sorted_values,size);
   if(ArrayCopy(sorted_values,array,0,0,WHOLE_ARRAY)!=size)
      return(QNaN);
   ArraySort(sorted_values);

   //--- calculation
    percentile_value = sorted_values[left_rank]*left_weight + sorted_values[right_rank]*right_weight;
   
   return(percentile_value);
}
 
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
   double mul=pow(10,_Digits),percent=0.5;
//---
   int start=!prev_calculated?Period-1:prev_calculated-1;
   for(int i=start;i<rates_total;i++)
      CoeffBuffer[i]=(close[i]-close[i-Period+1])/(time[i]-time[i-Period+1])*mul;
//---
   start=!prev_calculated?Period*2-1:prev_calculated-1;
   for(int i=start;i<rates_total;i++)
      //MedianBuffer[i]=MathMedian(i,Period,CoeffBuffer);
      MedianBuffer[i]=MathPercentileValue(i,Period,CoeffBuffer,percent);
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double MathMedian(const int index,const int period,const double &array[])
  {
//--- prepare sorted values
   double sorted_values[];
   if(ArrayCopy(sorted_values,array,0,index-period+1,period)!=period)
      return(0);
   ArraySort(sorted_values);
//--- calculate median for odd and even cases
//--- data_count=odd
   if(period%2==1)
      return(sorted_values[period/2]);
   else
//--- data_count=even
      return(0.5*(sorted_values[(period-1)/2]+sorted_values[(period+1)/2]));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double MathPercentileValue(const int index,const int period,double &array[],const double &percent_rank, const int C=0)
  {
//---
   double percentile_value = 0.0;
//--- check for percent rank [0..1]
   if(percent_rank<0 || percent_rank>1)
      return(0.0);
//--- simple case: one element
   if(period==2)
      return(array[index]);
   double rank;
   rank=(period-1)*percent_rank;
//---
   int left_rank;
   left_rank=(int)MathCeil(rank);
   double left_weight;
   left_weight=(rank+1)-double(left_rank);
//---
   int right_rank;
   right_rank=(int)MathFloor(rank);
   double right_weight;
   right_weight=1-left_weight;
//--- prepare sorted values
   double sorted_values[];
   //ArrayResize(sorted_values,size);
   if(ArrayCopy(sorted_values,array,0,index-period+1,period)!=period)
      return(0.0);
   ArraySort(sorted_values);
//--- calculation
   percentile_value=sorted_values[left_rank]*left_weight+sorted_values[right_rank]*right_weight;
//---
   return(percentile_value);
  }
//+------------------------------------------------------------------+
 
Ernst Van Der Merwe:

I wrote:

    for(int i=0;i<(size-1);i++)
        {
            for(int j=(i+1);j<(size);j++)
                {
                    ArrayResize(CoeffBuffer,k+1);
                    Coefficient = (price[j]-price[i])/(time[j]-time[i]);
                    CoeffBuffer[k] = Coefficient;
                    k++;
                };
        };

This generates coefficients for a combination. This doesn't look the same as:

for(int i=start;i<rates_total;i++)
      CoeffBuffer[i]=(close[i]-close[i-Period+1])/(time[i]-time[i-Period+1])*mul;
Is it the same?
 

The following code calculates a combinatory of linear coefficients and give the percentile value based on its percent rank:

//+------------------------------------------------------------------+
//| Quantile Regression Coefficient                                  |
//+------------------------------------------------------------------+
double MathQuantRegCoeff(double &x_array[], double &y_array[], const double &percent_rank)
    {
    if(ArraySize(x_array)!=ArraySize(y_array))
        return(QNaN);
    int size = ArraySize(x_array);
    if(size<2)
        return(QNaN);
    double QuantRegCoeff = 0.0;
    double CoeffBuffer[];
    
    int k=0;
    double Coefficient=0;
    
    // Combinatory of coefficients
    for(int i=0;i<(size-1);i++)
        {
            for(int j=(i+1);j<(size);j++)
                {
                    ArrayResize(CoeffBuffer,k+1);
                    Coefficient = (y_array[j]-y_array[i])/(x_array[j]-x_array[i]);
                    CoeffBuffer[k] = Coefficient;
                    k++;
                };
        };
    QuantRegCoeff = MathPercentileValue(CoeffBuffer, percent_rank);
    return(QuantRegCoeff);
    }
Reason: