//+------------------------------------------------------------------+
//|                                                 Accumulation.mq4 |
//|                   Copyright 2005-2014, MetaQuotes Software Corp. |
//|                                              http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright   "2005-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
#property description "Accumulation/Distribution"
#property strict

//--- indicator settings
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1  clrLightSeaGreen
#property indicator_width1  2
#property indicator_color2  clrDodgerBlue
#property indicator_color3  clrSandyBrown
#property indicator_color4  clrDimGray
#property indicator_style4  STYLE_DOT

enum enLevelType
{
   lev_float, // Floating levels
   lev_quan   // Quantile levels
};

#import "dynamicZone.dll"
   double dzBuyP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precision);
   double dzSellP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precision);
#import

extern enLevelType     FlType                 = lev_quan;       // Levels type
extern int             FlPeriod               = 35;             // Levels period
extern double          FlUp                   = 80;             // Upper level %
extern double          FlDown                 = 20;             // Lower level %


//--- buffers
double ExtADbuffer[], buffer1[],buffer2[],buffer3[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit(void)
  {
   IndicatorShortName(" A/D ("+(string)FlPeriod+")");
   
   IndicatorDigits(0);
//--- indicators
   IndicatorBuffers(4);
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtADbuffer);
      SetIndexBuffer(1, buffer1);
   SetIndexBuffer(2, buffer2);
   SetIndexBuffer(3, buffer3);
  }
//+------------------------------------------------------------------+
//| Accumulation/Distribution                                        |
//+------------------------------------------------------------------+
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[])
  {
//--- prevent total recalculation
   int i=rates_total-prev_calculated-1;
//--- current value should be recalculated
   if(i<0)
      i=0;
//---
   while(i>=0)
     {
      ExtADbuffer[i]=(close[i]-low[i])-(high[i]-close[i]);
      if(ExtADbuffer[i]!=0.0)
        {
         double diff=high[i]-low[i];
         if(diff<0.000000001)
            ExtADbuffer[i]=0.0;
         else
           {
            ExtADbuffer[i]/=diff;
            ExtADbuffer[i]*=(double)tick_volume[i];
           }
        }
      if(i<rates_total-1)
         ExtADbuffer[i]+=ExtADbuffer[i+1];
         
            if (FlType==lev_float)
            {
               double min   = ExtADbuffer[ArrayMinimum(ExtADbuffer,FlPeriod,i)];
               double max   = ExtADbuffer[ArrayMaximum(ExtADbuffer,FlPeriod,i)];
               double range = max-min;
                  buffer1[i] = min+FlUp  *range/100.0;
                  buffer2[i] = min+FlDown*range/100.0;
                  buffer3[i] = min+0.5*range;
            }
            else
            {
                  buffer1[i] = iQuantile(ExtADbuffer[i],FlPeriod, FlUp            ,i,Bars);
                  buffer2[i] = iQuantile(ExtADbuffer[i],FlPeriod, FlDown          ,i,Bars);
                  buffer3[i] = iQuantile(ExtADbuffer[i],FlPeriod,(FlUp+FlDown)/2.0,i,Bars);
            }  
      i--;
     }
//---
   return(rates_total);
  }
//+------------------------------------------------------------------+

#define _quantileInstances 1
double _sortQuant[];
double _workQuant[][_quantileInstances];

double iQuantile(double value, int period, double qp, int i, int bars, int instanceNo=0)
{
   if (period<1) return(value);
   if (ArrayRange(_workQuant,0)!=bars) ArrayResize(_workQuant,bars); 
   if (ArraySize(_sortQuant)!=period)  ArrayResize(_sortQuant,period); 
            i=bars-i-1; _workQuant[i][instanceNo]=value;
            int k=0; for (; k<period && (i-k)>=0; k++) _sortQuant[k] = _workQuant[i-k][instanceNo];
                     for (; k<period            ; k++) _sortQuant[k] = 0;
                     ArraySort(_sortQuant);

   //
   //
   //
   //
   //
   
   double index = (period-1.0)*qp/100.00;
   int    ind   = (int)index;
   double delta = index - ind;
   if (ind == NormalizeDouble(index,5))
         return(            _sortQuant[ind]);
   else  return((1.0-delta)*_sortQuant[ind]+delta*_sortQuant[ind+1]);
}   