//+------------------------------------------------------------------+
//|                                    Dynamic zone DSS Bressert.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers 7
#property indicator_color1  DeepSkyBlue
#property indicator_color2  LimeGreen
#property indicator_color3  LimeGreen
#property indicator_color4  Red
#property indicator_color5  Red
#property indicator_color6  DimGray
#property indicator_color7  DimGray
#property indicator_style3  STYLE_DOT
#property indicator_style4  STYLE_DOT
#property indicator_style6  STYLE_DOT
#property indicator_style7  STYLE_DASHDOT
#property indicator_width1  2
#property indicator_width2  2
#property indicator_minimum 0
#property indicator_maximum 100

//
//
//
//
//

#import "dynamicZone.dll"
   double dzBuy(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i );
   double dzSell(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i );
#import

//
//
//
//
//

extern string TimeFrame               = "Current time frame";
extern int    StochasticLength        = 55;
extern int    SmoothEMA               = 15;
extern int    DzLookBackBars          = 70;
extern double DzStartBuyProbability1  = 0.10;
extern double DzStartBuyProbability2  = 0.25;
extern double DzStartSellProbability1 = 0.10;
extern double DzStartSellProbability2 = 0.25;
extern int    ZigZagHighLowPeriod     = 30;
extern bool   ZigZagVisible           = true;
extern bool   Interpolate             = true;

extern bool   alertsOn                = false;
extern bool   alertsOnZeroLineCross   = true;
extern bool   alertsOnUpLevel1Cross   = true;
extern bool   alertsOnUpLevel2Cross   = true;
extern bool   alertsOnDownLevel1Cross = true;
extern bool   alertsOnDownLevel2Cross = true;
extern bool   alertsOnCurrent         = false;
extern bool   alertsMessage           = true;
extern bool   alertsSound             = false;
extern bool   alertsEmail             = false;

extern bool   arrowsVisible           = true;
extern string arrowsIdentifier        = "DzDssArrows";
extern color  arrowsUpColor           = DeepSkyBlue;
extern color  arrowsDnColor           = Red;
extern bool   arrowsOnZeroLineCross   = true;
extern bool   arrowsOnUpLevel1Cross   = true;
extern bool   arrowsOnUpLevel2Cross   = true;
extern bool   arrowsOnDownLevel1Cross = true;
extern bool   arrowsOnDownLevel2Cross = true;

//
//
//
//
//

double dssBuffer[];
double bl1Buffer[];
double bl2Buffer[];
double sl1Buffer[];
double sl2Buffer[];
double zliBuffer[];
double zigZag[];

//
//
//
//
//

string indicatorFileName;
bool   returnBars;
bool   calculateValue;
int    timeFrame;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   SetIndexBuffer(0,dssBuffer);
   SetIndexBuffer(1,bl1Buffer);
   SetIndexBuffer(2,bl2Buffer);
   SetIndexBuffer(3,sl2Buffer);
   SetIndexBuffer(4,sl1Buffer);
   SetIndexBuffer(5,zliBuffer);
   SetIndexBuffer(6,zigZag); SetIndexStyle(6,DRAW_SECTION); SetIndexEmptyValue(6,0);
      StochasticLength = MathMax(1,StochasticLength);
      SmoothEMA        = MathMax(0,SmoothEMA);

      //
      //
      //
      //
      //
      
      indicatorFileName = WindowExpertName();
      calculateValue    = TimeFrame=="calculateValue"; if (calculateValue) { return(0); }
      returnBars        = TimeFrame=="returnBars";     if (returnBars)     { return(0); }
      timeFrame         = stringToTimeFrame(TimeFrame);

   IndicatorShortName(timeFrameToString(timeFrame)+" Dynamic zone DSS Bressert ("+StochasticLength+","+SmoothEMA+")");
   return(0);
}

//
//
//
//
//

int deinit()
{
   string lookFor       = arrowsIdentifier+":";
   int    lookForLength = StringLen(lookFor);
      for (int i=ObjectsTotal()-1; i>=0; i--)
      {
         string objectName = ObjectName(i);
            if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
      }
   return(0);
}




//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double work[][8];
#define _st1    0
#define _ss1    1
#define _pHigh  2
#define _pLow   3
#define _zzLow  4
#define _zzHigh 5
#define _chLow  6
#define _chHigh 7

double trends[][5];
#define _tup1 0
#define _tup2 1
#define _tmi  2
#define _tdn1 3
#define _tdn2 4

//
//
//
//
//

int start()
{
   int limit,i,k,n,r,counted_bars = IndicatorCounted();

   if(counted_bars < 0) return(-1);
   if(counted_bars > 0) counted_bars--;
           limit = MathMin(Bars-counted_bars,Bars-1);
           if (returnBars) { dssBuffer[0] = MathMin(limit+1,Bars-1); return(0); }


   //
   //
   //
   //
   //
   
   if (calculateValue || timeFrame == Period())
   {
      if (ArrayRange(work,0)!=Bars) { ArrayResize(work,Bars); ArrayResize(trends,Bars); }

      //
      //
      //
      //
      //
      
      if (ZigZagVisible)
         for (int lastZag=limit+1; lastZag<Bars-1; lastZag++) if (work[Bars-lastZag-1][_zzLow] != 0 || work[Bars-lastZag-1][_zzHigh] != 0) break;
      
      //
      //
      //
      //
      //
      
      double alpha1 = 2.0 / (1.0+SmoothEMA);
    	for(i = limit, r=Bars-i-1; i>=0; i--,r++)
      {
         double close    = iMA(NULL,0,1,0,MODE_SMA,PRICE_CLOSE,i);
         work[r][_pHigh] = iMA(NULL,0,1,0,MODE_SMA,PRICE_HIGH ,i);
         work[r][_pLow]  = iMA(NULL,0,1,0,MODE_SMA,PRICE_LOW  ,i);

         //
         //
         //
         //
         //
      
            double min = work[r][_pLow];
            double max = work[r][_pHigh];
            for (k=1; k<StochasticLength && (r-k)>=0; k++)
            {
               min = MathMin(min,work[r-k][_pLow]);
               max = MathMax(max,work[r-k][_pHigh]);
            }
      
            work[r][_st1] = 0; if (min!=max) work[r][_st1] = 100*(close-min)/(max-min);
               if (r<1)
               {
                  work[r][_ss1] = work[r][_st1];
                  dssBuffer[i]  = work[r][_st1];
                  continue;
               }            
            work[r][_ss1] = work[r-1][_ss1]+alpha1*(work[r][_st1]-work[r-1][_ss1]);

         //
         //
         //
         //
         //
      
            min = work[r][_ss1];
            max = work[r][_ss1];
            for (k=1; k<StochasticLength && (r-k)>=0; k++)
            {
               min = MathMin(min,work[r-k][_ss1]);
               max = MathMax(max,work[r-k][_ss1]);
            }
            double stoch = 0; if (min!=max) stoch = 100*(work[r][_ss1]-min)/(max-min);
            
            //
            //
            //
            //
            //
            
            dssBuffer[i] = dssBuffer[i+1]+alpha1*(stoch -dssBuffer[i+1]);
               if (DzStartBuyProbability1 >0) bl1Buffer[i] = dzBuy (dssBuffer, DzStartBuyProbability1,  DzLookBackBars, Bars, i);
               if (DzStartBuyProbability2 >0) bl2Buffer[i] = dzBuy (dssBuffer, DzStartBuyProbability2,  DzLookBackBars, Bars, i);
               if (DzStartSellProbability1>0) sl1Buffer[i] = dzSell(dssBuffer, DzStartSellProbability1, DzLookBackBars, Bars, i);
               if (DzStartSellProbability2>0) sl2Buffer[i] = dzSell(dssBuffer, DzStartSellProbability2, DzLookBackBars, Bars, i);
                                              zliBuffer[i] = dzSell(dssBuffer, 0.5                    , DzLookBackBars, Bars, i);
            setTrends(i,r);
            manageArrow(i,r);
   
         //
         //
         //
         //
         //

         if (!ZigZagVisible) continue;
   
            //
            //
            //
            //
            //
            
            work[r][_zzLow]  = 0;
            work[r][_zzHigh] = 0;
            work[r][_chLow]  = dssBuffer[i];
            work[r][_chHigh] = dssBuffer[i];
               for (k=1; k<ZigZagHighLowPeriod && (i+k)<Bars; k++)
               {
                  work[r][_chLow]  = MathMin(work[r][_chLow] ,dssBuffer[i+k]);
                  work[r][_chHigh] = MathMax(work[r][_chHigh],dssBuffer[i+k]);
               }
         
               //
               //
               //
               //
               //
               
               if (work[r][_chLow] < work[r-1][_chLow])
               {
                  if (zigZag[lastZag] == work[Bars-lastZag-1][_chLow])
                      zigZag[lastZag] = 0;
                      zigZag[i]       =  work[r][_chLow];
                      work[r][_zzLow] =  work[r][_chLow];
                              lastZag = i;
                              continue;
               }
               if (work[r][_chHigh] > work[r-1][_chHigh])
               {
                  if (zigZag[lastZag] == work[Bars-lastZag-1][_chHigh])
                      zigZag[lastZag]  = 0;
                      zigZag[i]        = work[r][_chHigh];
                      work[r][_zzHigh] = work[r][_chHigh];
                               lastZag = i;
                               continue;
               }
               if (zigZag[i] != 0)
               {
                  zigZag[i] = 0;
                  for (lastZag=i+1; lastZag<Bars; lastZag++)
                  {
                     if (work[Bars-lastZag-1][_zzLow]  != 0) { zigZag[lastZag] = work[Bars-lastZag-1][_zzLow];  break; }
                     if (work[Bars-lastZag-1][_zzHigh] != 0) { zigZag[lastZag] = work[Bars-lastZag-1][_zzHigh]; break; }
                  }
               }
      }
      manageAlerts();
      return(0);           
   }      

   //
   //
   //
   //
   //
   
   limit = MathMax(limit,MathMin(Bars,iCustom(NULL,timeFrame,indicatorFileName,"returnBars",0,0)*timeFrame/Period()));
   if (ArrayRange(trends,0)!=Bars) ArrayResize(trends,Bars);
   if (ZigZagVisible)
      while (limit<Bars-1) { if (zigZag[limit]!= 0) break; limit++; }
      
   //
   //
   //
   //
         
   for (i=limit, r=Bars-i-1;i>=0; i--,r++)
   {
      int y = iBarShift(NULL,timeFrame,Time[i]);
         dssBuffer[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",StochasticLength,SmoothEMA,DzLookBackBars,DzStartBuyProbability1,DzStartBuyProbability2,DzStartSellProbability1,DzStartSellProbability2,ZigZagHighLowPeriod,ZigZagVisible,0,y);
         bl1Buffer[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",StochasticLength,SmoothEMA,DzLookBackBars,DzStartBuyProbability1,DzStartBuyProbability2,DzStartSellProbability1,DzStartSellProbability2,ZigZagHighLowPeriod,ZigZagVisible,1,y);
         bl2Buffer[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",StochasticLength,SmoothEMA,DzLookBackBars,DzStartBuyProbability1,DzStartBuyProbability2,DzStartSellProbability1,DzStartSellProbability2,ZigZagHighLowPeriod,ZigZagVisible,2,y);
         sl2Buffer[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",StochasticLength,SmoothEMA,DzLookBackBars,DzStartBuyProbability1,DzStartBuyProbability2,DzStartSellProbability1,DzStartSellProbability2,ZigZagHighLowPeriod,ZigZagVisible,3,y);
         sl1Buffer[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",StochasticLength,SmoothEMA,DzLookBackBars,DzStartBuyProbability1,DzStartBuyProbability2,DzStartSellProbability1,DzStartSellProbability2,ZigZagHighLowPeriod,ZigZagVisible,4,y);
         zliBuffer[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",StochasticLength,SmoothEMA,DzLookBackBars,DzStartBuyProbability1,DzStartBuyProbability2,DzStartSellProbability1,DzStartSellProbability2,ZigZagHighLowPeriod,ZigZagVisible,5,y);
         zigZag[i]    = 0;
            setTrends(i,r);
            manageArrow(i,r);
        
         if (ZigZagVisible)
         if (y!=iBarShift(NULL,timeFrame,Time[i-1]))
               zigZag[i] = iCustom(NULL,timeFrame,indicatorFileName,"calculateValue",StochasticLength,SmoothEMA,DzLookBackBars,DzStartBuyProbability1,DzStartBuyProbability2,DzStartSellProbability1,DzStartSellProbability2,ZigZagHighLowPeriod,ZigZagVisible,6,y);

         //
         //
         //
         //
         //
                  
         if (!Interpolate || y==iBarShift(NULL,timeFrame,Time[i-1])) continue;

         //
         //
         //
         //
         //

         datetime time = iTime(NULL,timeFrame,y);
            for(n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
            for(k = 1; k < n; k++)
            {
               dssBuffer[i+k] = dssBuffer[i] + (dssBuffer[i+n]-dssBuffer[i])*k/n;
               bl1Buffer[i+k] = bl1Buffer[i] + (bl1Buffer[i+n]-bl1Buffer[i])*k/n;
               bl2Buffer[i+k] = bl2Buffer[i] + (bl2Buffer[i+n]-bl2Buffer[i])*k/n;
               sl2Buffer[i+k] = sl2Buffer[i] + (sl2Buffer[i+n]-sl2Buffer[i])*k/n;
               sl1Buffer[i+k] = sl1Buffer[i] + (sl1Buffer[i+n]-sl1Buffer[i])*k/n;
               zliBuffer[i+k] = zliBuffer[i] + (zliBuffer[i+n]-zliBuffer[i])*k/n;
            }
   }
   manageAlerts();

   //
   //
   //
   //
   //
   
   return(0);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

void setTrends(int i, int r)
{
   trends[r][_tmi]  = trends[r-1][_tmi];
   trends[r][_tup1] = trends[r-1][_tup1];
   trends[r][_tup2] = trends[r-1][_tup2];
   trends[r][_tdn1] = trends[r-1][_tdn1];
   trends[r][_tdn2] = trends[r-1][_tdn2];
      if (dssBuffer[i]>zliBuffer[i]) trends[r][_tmi]  =  1;
      if (dssBuffer[i]<zliBuffer[i]) trends[r][_tmi]  = -1;
      if (dssBuffer[i]>bl1Buffer[i]) trends[r][_tdn2] =  1;
      if (dssBuffer[i]<bl1Buffer[i]) trends[r][_tdn2] = -1;
      if (dssBuffer[i]>bl2Buffer[i]) trends[r][_tdn1] =  1;
      if (dssBuffer[i]<bl2Buffer[i]) trends[r][_tdn1] = -1;
      if (dssBuffer[i]>sl1Buffer[i]) trends[r][_tup2] =  1;
      if (dssBuffer[i]<sl1Buffer[i]) trends[r][_tup2] = -1;
      if (dssBuffer[i]>sl2Buffer[i]) trends[r][_tup1] =  1;
      if (dssBuffer[i]<sl2Buffer[i]) trends[r][_tup1] = -1;
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

void manageAlerts()
{
   if (!calculateValue && alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1; whichBar = iBarShift(NULL,0,iTime(NULL,timeFrame,whichBar)); 
                             whichBar = Bars-whichBar-1;

      //
      //
      //
      //
      //
            
      static datetime time1 = 0;
      static string   mess1 = "";
      if (alertsOnUpLevel1Cross && trends[whichBar][_tup1] != trends[whichBar-1][_tup1])
      {
         if (trends[whichBar][_tup1] ==  1) doAlert(time1,mess1,whichBar,"crossed upper line 1 up");
         if (trends[whichBar][_tup1] == -1) doAlert(time1,mess1,whichBar,"crossed upper line 1 down");
      }
      static datetime time2 = 0;
      static string   mess2 = "";
      if (alertsOnUpLevel2Cross && trends[whichBar][_tup2] != trends[whichBar-1][_tup2])
      {
         if (trends[whichBar][_tup2] ==  1) doAlert(time2,mess2,whichBar,"crossed upper line 2 up");
         if (trends[whichBar][_tup2] == -1) doAlert(time2,mess2,whichBar,"crossed upper line 2 down");
      }
      static datetime time3 = 0;
      static string   mess3 = "";
      if (alertsOnDownLevel1Cross && trends[whichBar][_tdn1] != trends[whichBar-1][_tdn1])
      {
         if (trends[whichBar][_tdn1] ==  1) doAlert(time3,mess3,whichBar,"crossed lower line 1 up");
         if (trends[whichBar][_tdn1] == -1) doAlert(time3,mess3,whichBar,"crossed lower line 1 down");
      }
      static datetime time4 = 0;
      static string   mess4 = "";
      if (alertsOnDownLevel2Cross && trends[whichBar][_tdn2] != trends[whichBar-1][_tdn2])
      {
         if (trends[whichBar][_tdn2] ==  1) doAlert(time4,mess4,whichBar,"crossed lower line 2 up");
         if (trends[whichBar][_tdn2] == -1) doAlert(time4,mess4,whichBar,"crossed lower line 2 down");
      }
      static datetime time5 = 0;
      static string   mess5 = "";
      if (alertsOnZeroLineCross && trends[whichBar][_tmi] != trends[whichBar-1][_tmi])
      {
         if (trends[whichBar][_tmi] ==  1) doAlert(time5,mess5,whichBar,"crossed zero line up");
         if (trends[whichBar][_tmi] == -1) doAlert(time5,mess5,whichBar,"crossed zero line down");
      }
   }
}

//
//
//
//
//

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()," ",timeFrameToString(timeFrame)," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," DZ dss Bressert ",doWhat);
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol()," DZ dss Bressert "),message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void manageArrow(int i, int r)
{
   if (!calculateValue && arrowsVisible)
   {
      deleteArrow(Time[i]);
      if (arrowsOnUpLevel1Cross && trends[r][_tup1]!=trends[r-1][_tup1])
      {
         if (trends[r][_tup1] == 1) drawArrow(i,arrowsUpColor,241,false);
         if (trends[r][_tup1] ==-1) drawArrow(i,arrowsDnColor,242,true);
      }
      if (arrowsOnUpLevel2Cross && trends[r][_tup2]!=trends[r-1][_tup2])
      {
         if (trends[r][_tup2] == 1) drawArrow(i,arrowsUpColor,241,false);
         if (trends[r][_tup2] ==-1) drawArrow(i,arrowsDnColor,242,true);
      }
      if (arrowsOnDownLevel1Cross && trends[r][_tdn1]!=trends[r-1][_tdn1])
      {
         if (trends[r][_tdn1] == 1) drawArrow(i,arrowsUpColor,241,false);
         if (trends[r][_tdn1] ==-1) drawArrow(i,arrowsDnColor,242,true);
      }
      if (arrowsOnDownLevel2Cross && trends[r][_tdn2]!=trends[r-1][_tdn2])
      {
         if (trends[r][_tdn2] == 1) drawArrow(i,arrowsUpColor,241,false);
         if (trends[r][_tdn2] ==-1) drawArrow(i,arrowsDnColor,242,true);
      }
      if (arrowsOnZeroLineCross && trends[r][_tmi]!=trends[r-1][_tmi])
      {
         if (trends[r][_tmi] == 1) drawArrow(i,arrowsUpColor,241,false);
         if (trends[r][_tmi] ==-1) drawArrow(i,arrowsDnColor,242,true);
      }
   }
}               

//
//
//
//
//

void drawArrow(int i,color theColor,int theCode,bool up)
{
   string name = arrowsIdentifier+":"+Time[i];
   double gap  = 3.0*iATR(NULL,0,20,i)/4.0;   
   
      //
      //
      //
      //
      //
      
      ObjectCreate(name,OBJ_ARROW,0,Time[i],0);
         ObjectSet(name,OBJPROP_ARROWCODE,theCode);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         if (up)
               ObjectSet(name,OBJPROP_PRICE1,High[i]+gap);
         else  ObjectSet(name,OBJPROP_PRICE1,Low[i] -gap);
}

//
//
//
//
//

void deleteArrow(datetime time)
{
   string lookFor = arrowsIdentifier+":"+time; ObjectDelete(lookFor);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

//
//
//
//
//

int stringToTimeFrame(string tfs)
{
   tfs = stringUpperCase(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--)
         if (tfs==sTfTable[i] || tfs==""+iTfTable[i]) return(MathMax(iTfTable[i],Period()));
                                                      return(Period());
}
string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

//
//
//
//
//

string stringUpperCase(string str)
{
   string   s = str;

   for (int length=StringLen(str)-1; length>=0; length--)
   {
      int char = StringGetChar(s, length);
         if((char > 96 && char < 123) || (char > 223 && char < 256))
                     s = StringSetChar(s, length, char - 32);
         else if(char > -33 && char < 0)
                     s = StringSetChar(s, length, char + 224);
   }
   return(s);
}