//+------------------------------------------------------------------+
//|                                          dynamic zone price zone |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1  clrLimeGreen
#property indicator_color2  clrRed
#property indicator_color3  clrDimGray
#property indicator_width1  2
#property indicator_width2  2
#property indicator_style3  STYLE_DOT
#property strict

//
//
//
//
//

extern ENUM_TIMEFRAMES    TimeFrame              = PERIOD_CURRENT;   // Time frame
extern ENUM_APPLIED_PRICE DzPrice                = PRICE_CLOSE;      // Price to use
extern int                DzSmooth               = 1;                // Price pre smoothing period
extern ENUM_MA_METHOD     DzSmoothMode           = MODE_SMA;         // Price pre smoothing method
extern int                DzLookBackBars         = 35;               // Dynamic zone look back
extern double             DzStartBuyProbability  = 0.02;             // Dynamic zone buy probability
extern double             DzStartSellProbability = 0.02;             // Dynamic zone sell probability
extern bool               Interpolate            = true;             // Interpolate true/false

double bli[],sli[],cen[],prc[],count[];
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,DzPrice,DzSmooth,DzSmoothMode,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,_buff,_ind)

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int OnInit()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,bli); SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(1,sli); SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(2,cen); SetIndexStyle(2,DRAW_LINE);
   SetIndexBuffer(3,prc);
   SetIndexBuffer(4,count);
   
   //
   //
   //
   //
   //
   
   string PriceType;
      switch(DzPrice)
      {
         case PRICE_CLOSE:    PriceType = "Close";    break;  // 0
         case PRICE_OPEN:     PriceType = "Open";     break;  // 1
         case PRICE_HIGH:     PriceType = "High";     break;  // 2
         case PRICE_LOW:      PriceType = "Low";      break;  // 3
         case PRICE_MEDIAN:   PriceType = "Median";   break;  // 4
         case PRICE_TYPICAL:  PriceType = "Typical";  break;  // 5
         case PRICE_WEIGHTED: PriceType = "Weighted"; break;  // 6
      }    
      indicatorFileName = WindowExpertName();
      TimeFrame         = fmax(TimeFrame,_Period);   

   //
   //
   //
   //
   //
   
   IndicatorShortName (timeFrameToString(TimeFrame)+" Dynamic zone price zone ("+(string)DzSmooth+","+PriceType+","+(string)DzLookBackBars+","+DoubleToStr(DzStartBuyProbability,3)+","+DoubleToStr(DzStartSellProbability,3)+")");
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) { }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   double normalizer;
   int i,counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = fmin(Bars-counted_bars,Bars-1); count[0] = limit;
         if (Digits == 4 || Digits == 5)
               normalizer = 100;
         else  normalizer = 1;  
            if (TimeFrame!=_Period)
            {
               limit = (int)fmax(limit,fmin(Bars-1,_mtfCall(4,0)*TimeFrame/_Period));
               for (i=limit;i>=0 && !_StopFlag; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,Time[i]);
                     bli[i] = _mtfCall(0,y);
                     sli[i] = _mtfCall(1,y);
                     cen[i] = _mtfCall(2,y);
                     
                     //
                     //
                     //
                     //
                     //
                     
                     if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
                     #define _interpolate(buff) buff[i+k] = buff[i]+(buff[i+n]-buff[i])*k/n
                     int n,k; datetime time = iTime(NULL,TimeFrame,y);
                        for(n = 1; (i+n)<Bars && Time[i+n] >= time; n++) continue;	
                        for(k = 1; k<n && (i+n)<Bars && (i+k)<Bars; k++) 
                        {
                            _interpolate(bli); 
                            _interpolate(sli);
                            _interpolate(cen);   
                         }                                        
            }
   return(0);
   }             
         
   //
   //
   //
   //
   //
   //

   for(i=limit; i >= 0; i--)
   {
      prc[i] = iMA(NULL,0,DzSmooth,0,DzSmoothMode,DzPrice,i)*normalizer;
      bli[i] = dzBuy (i, prc, DzStartBuyProbability,  DzLookBackBars)/normalizer;
      sli[i] = dzSell(i, prc, DzStartSellProbability, DzLookBackBars)/normalizer;
      cen[i] = dzSell(i, prc, 0.5,                    DzLookBackBars)/normalizer;
   }
return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double dzBuy(int i, double& array[], double initValue, int lookBackBars)
{
   double left  = -10000;
   double right =  10000;
   
   if ((Bars-i)<lookBackBars) return(EMPTY_VALUE);
   
   //
   //
   //
   //
   //

   double eps      = 0.001;
   double yval     = (left+right)/2.0;
	double delta    = yval-left;
	int    maxSteps = 0;
	
		while (delta>0.005 && maxSteps<50)
		{
			maxSteps++;
   	      double tcount = 0;
			   for (int k=0; k<lookBackBars;k++) if (array[i+k]<yval) tcount++;
	
				double prob = tcount/lookBackBars;
               if (prob<(initValue-eps))
               {
                  left = yval;
                  yval = (yval+right)/2.0;
               }
               else
               {
                  right = yval;
                  yval  = (yval+left)/2.0;
               }
               delta=yval-left;
      }               
      return(yval);   
}

//
//
//
//
//

double dzSell(int i, double& array[], double initValue, int lookBackBars)
{
   double left  = -10000;
   double right =  10000;
   
   if ((Bars-i)<lookBackBars) return(EMPTY_VALUE);
   
   //
   //
   //
   //
   //

   double eps      = 0.001;
   double yval     = (left+right)/2.0;
	double delta    = yval-left;
	int    maxSteps = 0;
	
		while (delta>0.005 && maxSteps<50)
		{
			maxSteps++;
   	      double tcount = 0;
			   for (int k=0; k<lookBackBars;k++) if (array[i+k]>yval) tcount++;
	
				double prob = tcount/lookBackBars;
               if (prob<(initValue-eps))
               {
                  right = yval;
                  yval  = (yval+left)/2.0;
               }
               else
               {
                  left = yval;
                  yval = (yval+right)/2.0;
               }
               delta=yval-left;
      }               
      return(yval);   
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}
