//------------------------------------------------------------------
#property copyright ""
#property link      ""
//------------------------------------------------------------------
#property indicator_chart_window
#property indicator_buffers 9
#property indicator_color1  clrLimeGreen
#property indicator_color2  clrOrange
#property indicator_color3  clrLimeGreen
#property indicator_color4  clrOrange
#property indicator_color5  clrOrange
#property indicator_color6  clrLimeGreen
#property indicator_color7  clrOrange
#property indicator_color8  clrLimeGreen
#property indicator_color9  clrOrange
#property indicator_style8  STYLE_DOT
#property indicator_style9  STYLE_DOT

//
//
//
//
//

#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

//
//
//
//
//

#define _disLin 1
#define _disBar 2
#define _disDot 4

enum enDisplay
{
   en_lin = _disLin,                  // Display line
   en_his = _disBar,                  // Display colored bars
   en_all = _disLin+_disBar,          // Display colored lines and bars
   en_lid = _disLin+_disDot,          // Display lines with dots
   en_hid = _disBar+_disDot,          // Display colored bars with dots
   en_ald = _disLin+_disBar+_disDot,  // Display colored lines and bars with dots
   en_dot = _disDot,                  // Display dots
};

extern ENUM_TIMEFRAMES TimeFrame        = PERIOD_CURRENT; // Time frame
extern int            PdfMaLength       = 10;      // Pdfma Length
extern double         Sensitivity       = 5;       // Sensivity Factor
extern double         StepSize          = 20;      // Constant Step Size
extern double         Variance          = 1;       // Pdfma variance
extern double         Mean              = 0.0;     // Pdfma mean
extern bool           HighLow           = false;   // High/Low Mode Switch (more sensitive)
extern int            DzLookBackBars    = 35;
extern double         DzBuyProbability  = 0.1;
extern double         DzSellProbability = 0.1;
input enDisplay       DisplayType       = en_lin;    // Display type
input int             LinesWidth        = 3;         // Lines width (when lines are included in display)
input int             BarsWidth         = 1;         // Bars width (when bars are included in display)
input bool            alertsOn          = false;     // Turn alerts on?
input bool            alertsOnCurrent   = true;      // Alerts on current (still opened) bar?
extern bool           alertsOnSlope     = true;
extern bool           alertsOnLevels    = true;
input bool            alertsMessage     = true;      // Alerts should show pop-up message?
input bool            alertsSound       = false;     // Alerts should play alert sound?
input bool            alertsNotify      = false;     // Alerts should send push notification?
input bool            alertsEmail       = false;     // Alerts should send email?
extern string         soundFile         = "alert2.wav";
input int             ArrowsWidth       = 2;
input int             ArrowCodeUp       = 159;       // Arrow code up
input int             ArrowCodeDn       = 159;       // Arrow code down
input double          ArrowGapUp        = 0.5;       // Gap for arrow up        
input double          ArrowGapDn        = 0.5;       // Gap for arrow down
input bool            ArrowOnFirst      = true;      // Arrow on first bars
input int             Shift             = 0;         // Average shift
input bool            Interpolate       = true;           // Interpolate in multi time frame mode on/off?

double histou[],histod[],LineBuffer[],DnBuffera[],DnBufferb[],arrowu[],arrowd[],up[],dn[],smin[],smax[],trend[],trendu[],trendd[],_coeffs[],count[];
string indicatorFileName;
#define _mtfCall(_buff,_y) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,PdfMaLength,Sensitivity,StepSize,Variance,Mean,HighLow,DzLookBackBars,DzBuyProbability,DzSellProbability,DisplayType,LinesWidth,BarsWidth,alertsOn,alertsOnCurrent,alertsOnSlope,alertsOnLevels,alertsMessage,alertsSound,alertsNotify,alertsEmail,soundFile,ArrowsWidth,ArrowCodeUp,ArrowCodeDn,ArrowGapUp,ArrowGapDn,ArrowOnFirst,0,_buff,_y)

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

#define maxx 3.5
int init()
{
   IndicatorBuffers(15);
   int lstyle = DRAW_LINE;      if ((DisplayType&_disLin)==0) lstyle = DRAW_NONE;
   int hstyle = DRAW_HISTOGRAM; if ((DisplayType&_disBar)==0) hstyle = DRAW_NONE;
   int astyle = DRAW_ARROW;     if ((DisplayType&_disDot)==0) astyle = DRAW_NONE;
   SetIndexBuffer(0,histou);     SetIndexStyle(0,hstyle,EMPTY,BarsWidth);
   SetIndexBuffer(1,histod);     SetIndexStyle(1,hstyle,EMPTY,BarsWidth);
   SetIndexBuffer(2,LineBuffer); SetIndexStyle(2,lstyle,EMPTY,LinesWidth); SetIndexLabel(2,"StepMA("+PdfMaLength+","+Sensitivity+","+StepSize+")");
   SetIndexBuffer(3,DnBuffera);  SetIndexStyle(3,lstyle,EMPTY,LinesWidth);
   SetIndexBuffer(4,DnBufferb);  SetIndexStyle(4,lstyle,EMPTY,LinesWidth);
   SetIndexBuffer(5,arrowu);     SetIndexStyle(5,astyle,EMPTY,ArrowsWidth); SetIndexArrow(5,ArrowCodeUp);
   SetIndexBuffer(6,arrowd);     SetIndexStyle(6,astyle,EMPTY,ArrowsWidth); SetIndexArrow(6,ArrowCodeDn);
   SetIndexBuffer(7,up);         SetIndexStyle(7,DRAW_LINE);
   SetIndexBuffer(8,dn);         SetIndexStyle(8,DRAW_LINE);
   SetIndexBuffer(9,smin);
   SetIndexBuffer(10,smax);
   SetIndexBuffer(11,trend);
   SetIndexBuffer(12,trendu);
   SetIndexBuffer(13,trendd);
   SetIndexBuffer(14,count);
 
      PdfMaLength = MathMax(PdfMaLength,2);
      ArrayResize(_coeffs,PdfMaLength);   
         double step = maxx/(PdfMaLength-1); for(int i=0; i<PdfMaLength; i++) _coeffs[i] = pdf(i*step,Variance,Mean*maxx);
         
   indicatorFileName = WindowExpertName();
   TimeFrame         = fmax(TimeFrame,_Period);
   
   for (i=0; i<7; i++) SetIndexShift(i,Shift*TimeFrame/Period());
   IndicatorShortName(timeFrameToString(TimeFrame)+" StepMA("+PdfMaLength+","+Sensitivity+","+StepSize+")");
return(0);
}
int deinit() { return(0); }     

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int start()
{
   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 (TimeFrame != _Period)
         {
            limit = (int)fmax(limit,fmin(Bars-1,_mtfCall(14,0)*TimeFrame/_Period));
            if (trend[limit]==-1) CleanPoint(limit,DnBuffera,DnBufferb);
            for (i=limit;i>=0 && !_StopFlag; i--)
            {
                int y = iBarShift(NULL,TimeFrame,Time[i]);
                int x = y;
                if (ArrowOnFirst)
                      {  if (i<Bars-1) x = iBarShift(NULL,TimeFrame,Time[i+1]);               }
                else  {  if (i>0)      x = iBarShift(NULL,TimeFrame,Time[i-1]); else x = -1;  }
                     LineBuffer[i] = _mtfCall(2,y);
                     DnBuffera[i]  = _mtfCall(3,y);
                     DnBufferb[i]  = _mtfCall(4,y);
                     up[i]         = _mtfCall(7,y);
                     dn[i]         = _mtfCall(8,y);
   	               arrowu[i]     = EMPTY_VALUE;
                     arrowd[i]     = EMPTY_VALUE;
                     histou[i]     = EMPTY_VALUE;
                     histod[i]     = EMPTY_VALUE;
                     trend[i]      = _mtfCall(11,y);
                     if (x!=y)
                     {
                       arrowu[i] = _mtfCall(5,y);
                       arrowd[i] = _mtfCall(6,y);
                     }
                     if (trend[i]==-1) { histou[i] = Low[i]; histod[i] = High[i]; }
                     if (trend[i]== 1) { histod[i] = Low[i]; histou[i] = High[i]; }
                     
                     //
                     //
                     //
                     //
                     //
                     
                      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(LineBuffer);
                             _interpolate(up);
                             _interpolate(dn);
                         }            
            }
            for (i=limit; i >= 0; i--) if (trend[i]==-1) PlotPoint(i,DnBuffera,DnBufferb,LineBuffer);
       return(0);
      }

      //
      //
      //
      //
      //
        
      if (trend[limit]==-1) CleanPoint(limit,DnBuffera,DnBufferb);
      for(i=limit; i>=0; i--)
      {
         double thigh;
         double tlow;
            if (HighLow)
	               { thigh=iPdfma(Low[i ] ,PdfMaLength,_coeffs,i,0); tlow =iPdfma(High[i] ,PdfMaLength,_coeffs,i,1); } 	
	         else  { thigh=iPdfma(Close[i],PdfMaLength,_coeffs,i,0); tlow =iPdfma(Close[i],PdfMaLength,_coeffs,i,1); }

   	   LineBuffer[i] = iStepMa(Sensitivity,StepSize,Point,thigh,tlow,Close[i],i);
   	   DnBuffera[i]  = EMPTY_VALUE;
   	   DnBufferb[i]  = EMPTY_VALUE;
   	   arrowu[i]     = EMPTY_VALUE;
         arrowd[i]     = EMPTY_VALUE;
         histou[i]     = EMPTY_VALUE;
         histod[i]     = EMPTY_VALUE;
   	   up[i]         = dzSellP(LineBuffer,DzSellProbability,DzLookBackBars,Bars,i,0.00001);
         dn[i]         = dzBuyP (LineBuffer,DzBuyProbability ,DzLookBackBars,Bars,i,0.00001);
         trendu[i]     = trendu[i+1];
         trendd[i]     = trendd[i+1];
               if (LineBuffer[i] > up[i]) trendu[i] = 1;
               if (LineBuffer[i] < up[i]) trendu[i] =-1;  
               if (LineBuffer[i] > dn[i]) trendd[i] = 1;
               if (LineBuffer[i] < dn[i]) trendd[i] =-1;  
   	   if (trend[i]==-1) PlotPoint(i,DnBuffera,DnBufferb,LineBuffer);
   	   if (trend[i]==-1) { histou[i] = Low[i]; histod[i] = High[i]; }
         if (trend[i]== 1) { histod[i] = Low[i]; histou[i] = High[i]; }        
         if (i<Bars-1 && trend[i]!=trend[i+1])
         {
            if (trend[i] ==  1) arrowu[i] = fmin(LineBuffer[i],Low[i] )-iATR(NULL,0,15,i)*ArrowGapUp;
            if (trend[i] == -1) arrowd[i] = fmax(LineBuffer[i],High[i])+iATR(NULL,0,15,i)*ArrowGapDn;
         }          
   }
   
   //
   //
   //
   //
   //
   
   if (alertsOn)
   {
      if (alertsOnCurrent)
            int whichBar = 0;
      else      whichBar = 1;
      static datetime time1 = 0;
      static string   mess1 = "";
      if (alertsOnSlope && trend[whichBar] != trend[whichBar+1])
      {
         if (trend[whichBar] ==  1) doAlert(time1,mess1,whichBar,"trend changed to up");
         if (trend[whichBar] == -1) doAlert(time1,mess1,whichBar,"trend changed to down");       
      }         
      static datetime time2 = 0;
      static string   mess2 = "";
      if (alertsOnLevels && trendu[whichBar] != trendu[whichBar+1])
      {
         if (trendu[whichBar] ==  1 ) doAlert(time2,mess2,whichBar,"crossed upper level up");
         if (trendu[whichBar] == -1 ) doAlert(time2,mess2,whichBar,"crossed upper level down");
      }         
      static datetime time3 = 0;
      static string   mess3 = "";
      if (alertsOnLevels && trendd[whichBar] != trendd[whichBar+1])
      {
         if (trendd[whichBar] ==  1 ) doAlert(time3,mess3,whichBar,"crossed lower level up");
         if (trendd[whichBar] == -1 ) doAlert(time3,mess3,whichBar,"crossed lower level down");
      }         
   }   
	return(0);	
}

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
//
//
//
//

double workStep[][3];
#define _smin   0
#define _smax   1
#define _trend  2

double iStepMa(double sensitivity, double stepSize, double stepMulti, double phigh, double plow, double pprice, int r)
{
   if (ArrayRange(workStep,0)!=Bars) ArrayResize(workStep,Bars);
   if (sensitivity == 0) sensitivity = 0.0001; r = Bars-r-1;
   if (stepSize    == 0) stepSize    = 0.0001;
      double result; 
	   double size = sensitivity*stepSize;

      //
      //
      //
      //
      //
      
      if (r==0)
      {
         workStep[r][_smax]  = phigh+2.0*size*stepMulti;
         workStep[r][_smin]  = plow -2.0*size*stepMulti;
         workStep[r][_trend] = 1;
         return(pprice);
      }

      //
      //
      //
      //
      //
      
      workStep[r][_smax]  = phigh+2.0*size*stepMulti;
      workStep[r][_smin]  = plow -2.0*size*stepMulti;
      workStep[r][_trend] = workStep[r-1][_trend];
            if (pprice>workStep[r-1][_smax]) workStep[r][_trend] =  1;
            if (pprice<workStep[r-1][_smin]) workStep[r][_trend] = -1;
            if (workStep[r][_trend] ==  1) { if (workStep[r][_smin] < workStep[r-1][_smin]) workStep[r][_smin]=workStep[r-1][_smin]; result = workStep[r][_smin]+size*stepMulti; }
            if (workStep[r][_trend] == -1) { if (workStep[r][_smax] > workStep[r-1][_smax]) workStep[r][_smax]=workStep[r-1][_smax]; result = workStep[r][_smax]-size*stepMulti; }
      trend[Bars-r-1] = workStep[r][_trend]; 

   return(result); 
} 

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
//
//
//
//

void doAlert(datetime& previousTime, string& previousAlert, int forBar, string doWhat)
{
   string message;
   
   if (previousAlert != doWhat || previousTime != Time[forBar]) {
       previousAlert  = doWhat;
       previousTime   = Time[forBar];

       //
       //
       //
       //
       //

       message =  StringConcatenate(Symbol()," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," Dynamic zone step ma ",doWhat);
          if (alertsMessage) Alert(message);
          if (alertsNotify)  SendNotification(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol()," Dynamic zone step ma "),message);
          if (alertsSound)   PlaySound(soundFile);
   }
}

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
//
//    normal probability density function
//
//

#define Pi 3.141592653589793238462643

double pdf(double x, double variance=1.0, double mean=0) { return((1.0/MathSqrt(2*Pi*MathPow(variance,2))*MathExp(-MathPow(x-mean,2)/(2*MathPow(variance,2))))); }
double workPdfma[][2];
double iPdfma(double price, double period, double& coeffs[], int r, int instanceNo=0)
{
   if (ArraySize(workPdfma)!= Bars) ArrayResize(workPdfma,Bars); r = Bars-r-1;
   
   //
   //
   //
   //
   //
   
   workPdfma[r][instanceNo] = price;
      double sumw = coeffs[0];
      double sum  = coeffs[0]*price;

      for(int k=1; k<period && (r-k)>=0; k++)
      {
         double weight = coeffs[k];
                sumw  += weight;
                sum   += weight*workPdfma[r-k][instanceNo];  
      }             
      return(sum/sumw);
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

void CleanPoint(int i,double& first[],double& second[])
{
   if (i>=Bars-3) return;
   if ((second[i]  != EMPTY_VALUE) && (second[i+1] != EMPTY_VALUE))
        second[i+1] = EMPTY_VALUE;
   else
      if ((first[i] != EMPTY_VALUE) && (first[i+1] != EMPTY_VALUE) && (first[i+2] == EMPTY_VALUE))
          first[i+1] = EMPTY_VALUE;
}

void PlotPoint(int i,double& first[],double& second[],double& from[])
{
   if (i>=Bars-2) return;
   if (first[i+1] == EMPTY_VALUE)
      if (first[i+2] == EMPTY_VALUE) 
            { first[i]  = from[i];  first[i+1]  = from[i+1]; second[i] = EMPTY_VALUE; }
      else  { second[i] =  from[i]; second[i+1] = from[i+1]; first[i]  = EMPTY_VALUE; }
   else     { first[i]  = from[i];                           second[i] = EMPTY_VALUE; }
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

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("");
}
