#ifndef TF_INDICATORS_ROBUST_STATISTICS_MQH
#define TF_INDICATORS_ROBUST_STATISTICS_MQH

double TF_Clamp(const double value,const double lower,const double upper)
  {
   if(value<lower) return(lower);
   if(value>upper) return(upper);
   return(value);
  }

double TF_Median(const double &source[])
  {
   int count=ArraySize(source);
   if(count<=0) return(EMPTY_VALUE);
   double copy[];
   ArrayResize(copy,count);
   for(int i=0;i<count;i++) copy[i]=source[i];
   ArraySort(copy);
   if((count&1)==1) return(copy[count/2]);
   return(0.5*(copy[count/2-1]+copy[count/2]));
  }

double TF_MAD(const double &source[],const double floor_value=1.0e-10)
  {
   int count=ArraySize(source);
   if(count<=0) return(floor_value);
   double median=TF_Median(source);
   double deviations[];
   ArrayResize(deviations,count);
   for(int i=0;i<count;i++) deviations[i]=MathAbs(source[i]-median);
   return(MathMax(1.4826*TF_Median(deviations),floor_value));
  }

double TF_Median3(const double a,const double b,const double c)
  {
   if(a>b)
     {
      if(b>c) return(b);
      return(a>c ? c : a);
     }
   if(a>c) return(a);
   return(b>c ? c : b);
  }

double TF_SampleStdDev(const double &values[])
  {
   int count=ArraySize(values);
   if(count<2) return(0.0);
   double mean=0.0;
   for(int i=0;i<count;i++) mean+=values[i];
   mean/=count;
   double sum=0.0;
   for(int i=0;i<count;i++)
     {
      double d=values[i]-mean;
      sum+=d*d;
     }
   return(MathSqrt(sum/(count-1)));
  }

double TF_WinsorizeRobust(const double value,const double &population[],const double multiples=3.0)
  {
   double center=TF_Median(population);
   double scale=TF_MAD(population,1.0e-9);
   return(TF_Clamp(value,center-multiples*scale,center+multiples*scale));
  }

#endif
