//+------------------------------------------------------------------+
//|                                                  Value chart.mq4 |
//|                                                                  |
//| Helweg/Stendahl value charts                                     |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers 7
#property indicator_color3 DeepSkyBlue
#property indicator_color4 DeepSkyBlue
#property indicator_color5 DimGray
#property indicator_color6 PaleVioletRed
#property indicator_color7 PaleVioletRed
#property indicator_style5 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

//
//
//
//
//

extern string objectsUniqueID         = "Value charts c";
extern string forSymbol               = "";
extern int    numberOfBars            = 10;
extern color  colorBarDown            = Red;
extern color  colorBarUp              = Green;
extern color  colorBarNeutral         = DimGray;
extern color  colorWickUp             = DimGray;
extern color  colorWickDown           = DimGray;
extern color  colorWickNeutral        = DimGray;
extern int    widthWick               = 1;
extern int    widthBody               = 3;
extern int    DzLookBackBars          = 70;
extern double DzStartBuyProbability1  = 0.05;
extern double DzStartBuyProbability2  = 0.25;
extern double DzStartSellProbability1 = 0.05;
extern double DzStartSellProbability2 = 0.25;
extern bool   invertChart             = false;            
extern bool   zoneValuesShowTags      = false;
extern color  zoneValuesColorUpper    = DeepSkyBlue;
extern color  zoneValuesColorMiddle   = DimGray;
extern color  zoneValuesColorLower    = PaleVioletRed;

//
//
//
//
//

extern bool   alertsOn          = false;
extern bool   alertsOnCurrent   = false;
extern bool   alertsMessage     = true;
extern bool   alertsSound       = false;
extern bool   alertsEmail       = false;
extern bool   arrowsVisible     = false;
extern string arrowsIdentifier  = "dzValueCharArrows";
extern color  arrowsUpColor     = DeepSkyBlue;
extern color  arrowsDnColor     = Red;

//
//
//
//
//

string name;
int    window;
double hiBuffer[];
double loBuffer[];
double prBuffer[];
double saBuffer[];
double sbBuffer[];
double baBuffer[];
double bbBuffer[];
double miBuffer[];
bool   returnBars;
string indicatorFileName;
string useSymbol;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(8);
      SetIndexBuffer(0,hiBuffer); SetIndexStyle(0,DRAW_NONE);
      SetIndexBuffer(1,loBuffer); SetIndexStyle(1,DRAW_NONE);
      SetIndexBuffer(2,saBuffer); SetIndexDrawBegin(2,DzLookBackBars+1);
      SetIndexBuffer(3,sbBuffer); SetIndexDrawBegin(3,DzLookBackBars+1);
      SetIndexBuffer(4,miBuffer); SetIndexDrawBegin(4,DzLookBackBars+1);
      SetIndexBuffer(5,baBuffer); SetIndexDrawBegin(5,DzLookBackBars+1);
      SetIndexBuffer(6,bbBuffer); SetIndexDrawBegin(6,DzLookBackBars+1);
      SetIndexBuffer(7,prBuffer);
         DzStartBuyProbability1  = MathMax(DzStartBuyProbability1 ,0.001);
         DzStartBuyProbability2  = MathMax(DzStartBuyProbability2 ,0.001);
         DzStartSellProbability1 = MathMax(DzStartSellProbability1,0.001);
         DzStartSellProbability2 = MathMax(DzStartSellProbability2,0.001);

   //
   //
   //
   //
   //

   if (forSymbol=="") forSymbol=Symbol();
      indicatorFileName = WindowExpertName();
      returnBars        = (objectsUniqueID== "returnBars"); if (returnBars) return(0);
      numberOfBars      = MathMax(numberOfBars,5);
      name              = forSymbol+" "+objectsUniqueID+" "+numberOfBars;
         IndicatorShortName(name);
   return (0);
}

//
//
//
//
//

int deinit()
{
   string cName = objectsUniqueID+":";
   int    cLen  = StringLen(cName);
   for (int i = ObjectsTotal() - 1; i >= 0; i--)
   {
      string oName = ObjectName(i); if (StringSubstr(oName, 0, cLen) == cName) ObjectDelete(oName);
   }
   return (0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double vaBuffer[];
double trend[];

//
//
//
//
//

int start()
{
   useSymbol = forSymbol;
   double dummy = iClose(forSymbol,0,0);
      if (dummy==0) useSymbol = Symbol();

   //
   //
   //
   //
   //
   
   int counted_bars=IndicatorCounted();
   int i,r,k,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit  = MathMin(Bars-counted_bars,Bars-2);
         if (returnBars) { hiBuffer[0]=limit; return(0); }
         if (useSymbol != Symbol()) limit = MathMin(Bars-1,MathMax(limit,iCustom(useSymbol,0,indicatorFileName,"returnBars",0,0)));
         window = WindowFind(name);
            if (ArraySize(vaBuffer) != Bars) { ArrayResize(vaBuffer,Bars); ArrayResize(trend,Bars); }

   //
   //
   //
   //
   //

      int    nVarP = MathRound(numberOfBars/5.0);
      double nVar0,nVarA,nVarB,nVarC,nVarD,nVarE;
      double nVarR1,nVarR2,nVarR3,nVarR4,nVarR5;
      double nLRange;
      for (i=limit,r=Bars-i-1; i>=0; i--,r++)
      {
         //
         //
         //
         //
         //
         
         int y = iBarShift(useSymbol,0,Time[i]);
         if (numberOfBars<7)
         {
               if (MathAbs(iClose(useSymbol,0,y)-iClose(useSymbol,0,y+1)) >= (iHigh(useSymbol,0,y)-iLow(useSymbol,0,y)))
                     nVarA = MathAbs(iClose(useSymbol,0,y)-iClose(useSymbol,0,y+1));
               else  nVarA = (iHigh(useSymbol,0,y)-iLow(useSymbol,0,y));
               vaBuffer[r] = nVarA;
               
               //
               //
               //
               //
               //
               
               double average=0;
               for (k=0; k<5; k++) average += vaBuffer[r-k];
                                   average /= 5;
               nLRange = average*0.2;
         }
         else
         {            
            nVarA = iHighesti(nVarP,y)-iLowesti(nVarP,y);
                        if  (nVarA == 0 && nVarP == 1)
                             nVarR1 = MathAbs(iClose(useSymbol,0,y)-iClose(useSymbol,0,y+nVarP));
                        else nVarR1 = nVarA;                      
                     
            nVarB = iHighesti(nVarP,y+nVarP+1)-iLowesti(nVarP,y+nVarP);
                        if (nVarB == 0 && nVarP == 1)
                             nVarR2 = MathAbs(iClose(useSymbol,0,y+nVarP)-iClose(useSymbol,0,y+nVarP*2));
                        else nVarR2 = nVarB;

            nVarC = iHighesti(nVarP,y+nVarP*2)-iLowesti(nVarP,y+nVarP*2);
                        if (nVarC == 0 && nVarP == 1)
                             nVarR3 = MathAbs(iClose(useSymbol,0,y+nVarP*2)-iClose(useSymbol,0,y+nVarP*3));
                        else nVarR3 = nVarC;

            nVarD = iHighesti(nVarP,y+nVarP*3)-iLowesti(nVarP,y+nVarP*3);
                        if (nVarD == 0 && nVarP == 1)
                             nVarR4 = MathAbs(iClose(useSymbol,0,y+nVarP*3)-iClose(useSymbol,0,y+nVarP*4));
                        else nVarR4 = nVarD;

            nVarE = iHighesti(nVarP,y+nVarP*4)-iLowesti(nVarP,y+nVarP*4);
                        if (nVarE == 0 && nVarP == 1)
                             nVarR5 = MathAbs(iClose(useSymbol,0,y+nVarP*4)-iClose(useSymbol,0,y+nVarP*5));
                        else nVarR5 = nVarE;

            nLRange = ((nVarR1+nVarR2+nVarR3+nVarR4+nVarR5)/5.0)*0.2;
         }   	         

         //
         //
         //
         //
         //
               	         
	         if ( nLRange <= 0 ) continue;
            double invertMultiplier=1; if (invertChart) invertMultiplier=-1;
            double hlAverage = 0;
               for (k=0; k<numberOfBars; k++) hlAverage += (iHigh(useSymbol,0,y+k)+iLow(useSymbol,0,y+k))/2.0;
                                              hlAverage /= numberOfBars;
            
               double nOpen  = invertMultiplier*(iOpen(useSymbol,0,y)  - hlAverage) / nLRange;
               double nHigh  = invertMultiplier*(iHigh(useSymbol,0,y)  - hlAverage) / nLRange; hiBuffer[i] = nHigh;
	            double nLow   = invertMultiplier*(iLow(useSymbol,0,y)   - hlAverage) / nLRange; loBuffer[i] = nLow;
	            double nClose = invertMultiplier*(iClose(useSymbol,0,y) - hlAverage) / nLRange;	

            //
            //
            //
            //
            //	         

            color  theBarColor  = colorBarNeutral;
            color  theWickColor = colorWickNeutral;
               if (nClose<nOpen) { theBarColor = colorBarDown; theWickColor = colorWickDown; }
               if (nClose>nOpen) { theBarColor = colorBarUp;   theWickColor = colorWickUp;   }
               
               drawBar(Time[i],nHigh,nLow,nOpen,nClose,theBarColor,theWickColor);
               prBuffer[i] = (nHigh+nLow)/2.0;
               if (invertChart)
               {
                  saBuffer[i] = dzSellP(loBuffer,DzStartSellProbability1 ,DzLookBackBars,Bars,i,0.0001);
                  sbBuffer[i] = dzSellP(loBuffer,DzStartSellProbability2 ,DzLookBackBars,Bars,i,0.0001);
                  baBuffer[i] = dzBuyP (hiBuffer,DzStartBuyProbability1  ,DzLookBackBars,Bars,i,0.0001);
                  bbBuffer[i] = dzBuyP (hiBuffer,DzStartBuyProbability2  ,DzLookBackBars,Bars,i,0.0001);
               }
               else
               {
                  saBuffer[i] = dzSellP(hiBuffer,DzStartSellProbability1 ,DzLookBackBars,Bars,i,0.0001);
                  sbBuffer[i] = dzSellP(hiBuffer,DzStartSellProbability2 ,DzLookBackBars,Bars,i,0.0001);
                  baBuffer[i] = dzBuyP (loBuffer,DzStartBuyProbability1  ,DzLookBackBars,Bars,i,0.0001);
                  bbBuffer[i] = dzBuyP (loBuffer,DzStartBuyProbability2  ,DzLookBackBars,Bars,i,0.0001);
               }                  
               miBuffer[i] = dzBuyP(prBuffer,0.5,DzLookBackBars,Bars,i,0.0001);
               
               //
               //
               //
               //
               //
               
               trend[r] = trend[r-1];
               if (invertChart)
               {
                  if (nLow >saBuffer[i]) trend[r] =  1;
                  if (nHigh<baBuffer[i]) trend[r] = -1;
               }
               else
               {
                  if (nHigh>saBuffer[i]) trend[r] =  1;
                  if (nLow <baBuffer[i]) trend[r] = -1;
               }                  
               manageArrow(useSymbol,i);
      }
      manageAlerts();
      
   //
   //
   //
   //
   //
   
   if (zoneValuesShowTags)
   {
      showTag(0,saBuffer[0],zoneValuesColorUpper);
      showTag(1,sbBuffer[0],zoneValuesColorUpper);
      showTag(2,miBuffer[0],zoneValuesColorMiddle);
      showTag(3,baBuffer[0],zoneValuesColorLower);
      showTag(4,bbBuffer[0],zoneValuesColorLower);
   }
   return(0);
}



//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double iHighesti(int period, int i)
{
   if (i>=Bars) return(0);
   double max  = iHigh(useSymbol,0,i);
         for (int k=1;(i+k)<Bars && k<period; k++) max = MathMax(iHigh(useSymbol,0,i+k),max);
   return(max);
}
double iLowesti(int period, int i)
{
   if (i>=Bars) return(0);
   double min  = iLow(useSymbol,0,i);
         for (int k=1;(i+k)<Bars && k<period; k++) min = MathMin(min,iLow(useSymbol,0,i+k));
   return(min);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void showTag(string add, double value, color tagColor)
{
   string oName;
          oName = objectsUniqueID+":"+add;
            if (ObjectFind(oName) < 0) ObjectCreate(oName,OBJ_ARROW,window,Time[0],0);
                 ObjectSet(oName, OBJPROP_PRICE1, value);
                 ObjectSet(oName, OBJPROP_COLOR,tagColor);
                 ObjectSet(oName, OBJPROP_ARROWCODE,SYMBOL_RIGHTPRICE);
}

//
//
//
//
//

void drawBar(int bTime, double prHigh, double prLow, double prOpen, double prClose, color barColor, color wickColor)
{
   string oName;
          oName = objectsUniqueID+":"+bTime+"w";
            if (ObjectFind(oName) < 0) ObjectCreate(oName,OBJ_TREND,window,bTime,0,bTime,0);
                 ObjectSet(oName, OBJPROP_PRICE1, prHigh);
                 ObjectSet(oName, OBJPROP_PRICE2, prLow);
                 ObjectSet(oName, OBJPROP_COLOR, wickColor);
                 ObjectSet(oName, OBJPROP_WIDTH, widthWick);
                 ObjectSet(oName, OBJPROP_RAY, false);
                 ObjectSet(oName, OBJPROP_BACK, true);
           
         oName = objectsUniqueID+":"+bTime+"b";
            if (ObjectFind(oName) < 0)ObjectCreate(oName,OBJ_TREND,window,bTime,0,bTime,0);
                 ObjectSet(oName, OBJPROP_PRICE1, prOpen);
                 ObjectSet(oName, OBJPROP_PRICE2, prClose);
                 ObjectSet(oName, OBJPROP_COLOR, barColor);
                 ObjectSet(oName, OBJPROP_WIDTH, widthBody);
                 ObjectSet(oName, OBJPROP_RAY, false);
                 ObjectSet(oName, OBJPROP_BACK, true);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

void manageAlerts()
{
   if (alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1; whichBar = Bars-whichBar-1;
      if (trend[whichBar]!=trend[whichBar-1])
      {
         if (trend[whichBar] ==  1) doAlert(whichBar,"high broke up");
         if (trend[whichBar] == -1) doAlert(whichBar,"low broke down");
      }         
   }
}

//
//
//
//
//

void doAlert(int forBar, string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;

   if (previousAlert != doWhat || previousTime != Time[forBar])
   {
       previousAlert  = doWhat;
       previousTime   = Time[forBar];

       //
       //
       //
       //
       //

       message =  StringConcatenate(Symbol()," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," DZ value chart signal ",doWhat);
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol(),"dz value chart"),message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void manageArrow(string useSymbol, int i)
{
   if (arrowsVisible &&  Symbol()==useSymbol)
   {
      deleteArrow(Time[i]);
      if (trend[Bars-i-1]!=trend[Bars-i-2])
      {
         if (trend[Bars-i-1] ==  1) drawArrow(i,arrowsUpColor,241,false);
         if (trend[Bars-i-1] == -1) drawArrow(i,arrowsDnColor,242,true);
      }         
   }
}               

//
//
//
//
//

void drawArrow(int i,color theColor,int theCode,bool up)
{
   string name = objectsUniqueID+":arrow:"+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 = objectsUniqueID+":arrow:"+time; ObjectDelete(lookFor);
}