//+------------------------------------------------------------------+
//|                                           Bosson_GapAnalyzer.mq4 |
//|                                     Copyright 2014, Curtis Bosson 
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Sciurus"
#property link      "http://www.mql5.com"
#property version   "1.2"
#property strict
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
#property indicator_width1 2
#property indicator_color2 Black
#property indicator_color3 Black
#property indicator_color4 Yellow
#property indicator_width4 1
#property indicator_color5 Yellow
#property indicator_width5 1
#property indicator_color6 Green
#property indicator_width6 1
#property indicator_color7 Green
#property indicator_width7 1

extern int h_left = 50;
extern int h_right = 50;
extern double minPipWidthBack = 0;
extern double maxPipWidthBack = 100;
extern double minPipWidthForward = 0;
extern double maxPipWidthForward = 100;
extern int barsLookback = 1000;
extern color PTZboxcolor = Salmon;
extern color TZboxcolor = Blue;
extern bool showChannel = false;
extern int channelWidth = 35;

//double barType[];
//double transient[];

double top[],bottom[],center[],upArrowY[],upArrowG[],downArrowY[],downArrowG[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

IndicatorBuffers(8);
SetIndexBuffer(0,center);//SetIndexArrow(0,159);SetIndexStyle(0,DRAW_ARROW);
SetIndexBuffer(1,bottom);//SetIndexArrow(1,159);SetIndexStyle(1,DRAW_ARROW);
SetIndexBuffer(2,top);//SetIndexArrow(2,159);SetIndexStyle(2,DRAW_ARROW);
SetIndexBuffer(3,upArrowY);SetIndexArrow(3,233);SetIndexStyle(3,DRAW_ARROW);
SetIndexBuffer(4,downArrowY);SetIndexArrow(4,234);SetIndexStyle(4,DRAW_ARROW);
SetIndexBuffer(5,upArrowG);SetIndexArrow(5,233);SetIndexStyle(5,DRAW_ARROW);
SetIndexBuffer(6,downArrowG);SetIndexArrow(6,234);SetIndexStyle(6,DRAW_ARROW);



//IndicatorBuffers (2);
//SetIndexBuffer(0,barType, INDICATOR_DATA);
//SetIndexLabel(0,"recurrent");
//SetIndexBuffer(1,transient, INDICATOR_DATA);
//SetIndexLabel(1,"transient");
// barType: blank == nothing going on, 1==initial push on upside, 2==subsequent push to upside, 3==initial push to downside, 4==subsequent push to downside
// transient: blank == not transient, 1 == transient on upside, 2 == transient on downside, 3== forming transient
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//--- 
 
clearRectangles(); 
double cumulativeDevelopedPrice = 0;
double cumulativeDevelopingPrice = 0;
   
int backwards;
if (barsLookback < (Bars-h_left)){
   backwards = barsLookback;
   }
else {
   backwards = Bars-h_left-1;
   }
     
for (int i = backwards-1; i > -1; i--){
   
if (1==1){

   double currentHigh = High[i];
   double currentLow = Low[i];
   
   for (int p=1; p<=h_left; p++){
      double backHigh = High[i+p];
      double backLow = Low[i+p];
      if (currentHigh <= backHigh){
         currentHigh = backLow;
      }
   }
   for (int q=1;q<=h_left;q++){
      double backLow = Low[i+q];
      double  backHigh = High[i+q];
      if (currentLow <= backHigh){
         currentLow = backHigh;
      }  
   }
   if (currentHigh > currentLow && (currentHigh-currentLow)/Point()>10*minPipWidthBack && (currentHigh-currentLow)/Point()<10*maxPipWidthBack){ 
      
//      int r;
//      for (int p=i+1; p<=i+h_left; p++){
//         int z = barType[p];
//         if (z!=1 && z!=2 && r!=1 && r!=2){
//            r=1;
//            barType[i]=1;
//         }
//         if (z==1){
//            r = 2;
//            barType[i]=2;
//         }
//      }     
      drawRectangle("up", "back", i,currentHigh,currentLow, h_left, PTZboxcolor);
      
      cumulativeDevelopingPrice = checkForUpperForwardZone(cumulativeDevelopingPrice, i,currentLow,currentHigh);        
      cumulativeDevelopingPrice = checkForLowerForwardZone(cumulativeDevelopingPrice, i,currentLow,currentHigh);
      if(i>h_left){ 
         cumulativeDevelopedPrice = cumulativeDevelopedPrice + (currentHigh-currentLow);  
      }       
   }
   }   
} // end of upper zones

for (int i=backwards-1; i>-1; i--){
   double currentHigh = High[i];
   double currentLow = Low[i];
   
if (1==1){
   for (int p=1; p<=h_left; p++){
      double backHigh = High[i+p];
      double backLow = Low[i+p];
      if (currentLow >= backLow){
         currentLow = backHigh;
      }
   }
   for (int q=1;q<=h_left;q++){
      double backLow = Low[i+q];
      double  backHigh = High[i+q];
      if (currentHigh >= backLow){
         currentHigh = backLow;
      }  
   }
   
   if (currentHigh > currentLow && (currentHigh-currentLow)/Point()>10*minPipWidthBack && (currentHigh-currentLow)/Point()<10*maxPipWidthBack){ 
//            int r;
//      for (int p=i+1; p<=i+h_left; p++){
//         int z = barType[p];
//         if (z!=3 && z!=4 && r!=3 && r!=4){
//            r=3;
//            barType[i]=3;
//         }
//         if (z==3){
//            r = 4;
//            barType[i]=4;
//         }
//      }
      drawRectangle("down", "back",i,currentHigh,currentLow, h_left, PTZboxcolor);

      cumulativeDevelopingPrice = checkForLowerForwardZone(cumulativeDevelopingPrice, i,currentLow,currentHigh);
      cumulativeDevelopingPrice = checkForUpperForwardZone(cumulativeDevelopingPrice, i,currentLow,currentHigh);
      if (i>h_left){
         cumulativeDevelopedPrice = cumulativeDevelopedPrice + (currentHigh - currentLow);
      }
   }
   }
}


   double percent = NormalizeDouble((cumulativeDevelopingPrice/cumulativeDevelopedPrice),3);
   writeLabel("1", "Probability transient using pip counts: " + percent, 850, 10);
   
//   double backCount = countRectangles("ba");
   double forwardCount = countRectangles("fo");
//   double ratio = NormalizeDouble((forwardCount/backCount),3);
//   writeLabel("2","Probability transient using bar counts: " + ratio, 850, 30);
   
   double pips = pipsInRectangle("fo");
   double meanPips = NormalizeDouble((pips/forwardCount)*10000, 2);
//   writeLabel("3","Mean transient zone height (Pips): " + meanPips, 850, 30);
   
   double SE = (calculateSE((meanPips/10000),forwardCount))*10000;
   double confid = NormalizeDouble(1.96* SE,2);
//   writeLabel("4","1.96 * SE: " + confid, 850, 30);
   
   writeLabel("5", "Upper 95% confidence interval for transient zone height: " + (meanPips+confid),850,30);
   
   
   
   if (showChannel==true){
      drawChannel(channelWidth);
   }
   
//--- return value of prev_calculated for next call
   return(rates_total);
   
  }
  
  

  
  
//+------------------------------------------------------------------+

void drawRectangle (string g, string j, int i, double currentHigh, double currentLow, int h_left, color clr){

   ObjectCreate("rectangle"+j+i+g, OBJ_RECTANGLE, 0, Time[i],currentHigh,Time[i+h_left], currentLow);
   ObjectSet("rectangle"+j+i+g,OBJPROP_COLOR, clr);
   ObjectSet("rectange"+j+i+g, OBJPROP_STYLE, STYLE_SOLID);
   ObjectSet("rectangle"+j+i+g, OBJPROP_BACK, true);
   ObjectSet("rectangle"+j+i+g, OBJPROP_FILL, true); 
}

double checkForUpperForwardZone(double cumulativePrice, int i, double currentLow, double currentHigh){
  
  int zing;
  if (i>=h_right+1){
      zing = h_right;
  }
  else {
      zing = i;
  }
   
  if (currentHigh > currentLow){
   for (int p=1; p<zing+1; p++){
      double forwardHigh = High[i-p];
      double forwardLow = Low[i-p];
      if (currentHigh <= forwardHigh){
         currentHigh = forwardLow;
      }
   }
   for (int q=1; q<zing+1; q++){
      double forwardLow = Low[i-q];
      double  forwardHigh = High[i-q];
      if (currentLow <= forwardHigh){
         currentLow = forwardHigh;
      }  
   }

   if (currentHigh > currentLow && (currentHigh-currentLow)/Point()>10*minPipWidthForward && (currentHigh-currentLow)/Point()<10*maxPipWidthForward){ 
//      if (zing==i){transient[i]=3;} if(zing==h_left){transient[i]=1;}
      drawRectangle("up","forward", i,currentHigh,currentLow, zing*-1, TZboxcolor);
      if(i>h_right){
         cumulativePrice = cumulativePrice + (currentHigh-currentLow);
      }
      if (i==zing){
         writeMessage((h_right-i) + " bars to go",i,currentLow);
      }
      }
   }  
   
   return (cumulativePrice);

}

double checkForLowerForwardZone(double currentPrice, int i, double currentLow, double currentHigh){
  
  int zing;
  if (i>=h_right+1){
      zing = h_right;
  }
  else {
      zing = i;    
  } 
  if (currentHigh > currentLow){
   for (int p=1; p<zing+1; p++){
      double forwardHigh = High[i-p];
      double forwardLow = Low[i-p];
      if (currentHigh >= forwardLow){
         currentHigh = forwardLow;
      }
   }
   for (int q=1; q<zing+1; q++){
      double forwardLow = Low[i-q];
      double  forwardHigh = High[i-q];
      if (currentLow >= forwardLow){
      }  
   }

   if (currentHigh > currentLow && (currentHigh-currentLow)/Point()>10*minPipWidthForward && (currentHigh-currentLow)/Point()<10*maxPipWidthForward){     
      
//      if (zing==i){transient[i]=3;} if(zing==h_left){transient[i]=2;}
      drawRectangle("low","forward", i,currentHigh,currentLow, zing*-1, TZboxcolor);
      if (i>h_right){
         currentPrice = currentPrice + (currentHigh-currentLow);
      }
      if (i==zing){
         writeMessage((h_right-i) +" bars to go",i,currentLow);
      }
      }       
   }  
   return (currentPrice);
}

void writeMessage(string message, int i, double currentLow){
   ObjectCreate (0,"message"+i, OBJ_TEXT, 0, Time[0], currentLow);
   ObjectSetString(0,"message"+i, OBJPROP_TEXT, message);
}

void writeLabel(string name, string message, int x, int y){
   ObjectCreate(0,"probability"+name, OBJ_LABEL,0, 0, 0);
   ObjectSetString(0, "probability"+name, OBJPROP_TEXT, message);
   ObjectSetInteger(0, "probability"+name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, "probability"+name, OBJPROP_YDISTANCE, y);
}

int deinit(){
  
   clearRectangles();
   return(0);
}

void clearRectangles(){
//----
   int i, ot=ObjectsTotal()-1;
   string id;
//----
   for(i=ot;i>=0;i--)
    {id=ObjectName(i);
    if(StringSubstr(id,0,5)=="recta" || StringSubstr(id,0,5)=="messa" || StringSubstr(id,0,5)=="proba"){
      {ObjectDelete(id);
      }
      }
    }
  }
  
 double countRectangles (string name){
      int i, ot=ObjectsTotal()-1;
      string id;
      double count;
      for(i=ot;i>=0;i--){
         id=ObjectName(i);
         if(StringSubstr(id,9,2)==name){
            count++;
         }
      }
      return(count);
 }
 
 double pipsInRectangle(string name){
      int i, ot=ObjectsTotal()-1;
      string id;
      double pips;
      for(i=ot;i>0;i--){
         id=ObjectName(i);
         if(StringSubstr(id,9,2)==name){
            pips = pips+ (ObjectGetDouble(0,id,OBJPROP_PRICE1) - ObjectGetDouble(0,id,OBJPROP_PRICE2));
         }
      }
      return(pips);
 }
 
 
 double calculateSE(double mean, double count){
   double cumDiff, SD, SE;
   int i, ot=ObjectsTotal()-1;
   string id;
   for(i=ot;i>0;i--){
      id=ObjectName(i);
      if(StringSubstr(id,9,2)=="fo"){
         double diff = mean-(ObjectGetDouble(0,id,OBJPROP_PRICE1)-ObjectGetDouble(0,id,OBJPROP_PRICE2));
         cumDiff = cumDiff+ MathAbs(diff); 

      }
   }

   SD= MathSqrt(MathPow(cumDiff,2)/count);
   SE=SD/(MathSqrt(count));
   return (SE);
 
 }
 
 void drawChannel(int width){
 
//   center[Bars-2] = Close[Bars-1];
//   top[Bars-2]=Close[Bars-1]+Point()*10*channelWidth;
//   bottom[Bars-2]=Close[Bars-1]-Point()*10*channelWidth;

   
   for (int i=Bars-2;i>0;i--){
   
   
       if (Close[i]>top[i]){
         top[i-1] = Close[i];
         center[i-1] = Close[i]-Point()*10*channelWidth;
         bottom[i-1] = Close[i]-2*Point()*10*channelWidth;
       } 
       else if (Close[i]<bottom[i]){
         bottom[i-1] = Close[i];
         center[i-1] = Close[i]+Point()*10*channelWidth;
         top[i-1] = Close[i]+2* Point()*10*channelWidth;
       }
       else {
         center[i-1]=center[i];
         top[i-1]=top[i];
         bottom[i-1]=bottom[i];
       }
       
       if (Open[i]<center[i]&&Close[i]<center[i]){
         upArrowG[i]=center[i];
       }
       if(Open[i]<center[i] && Close[i]>center[i]){
//         upArrowY[i]=center[i];
       }
       
       if (Open[i]>center[i]&& Close[i]>center[i]){
         downArrowY[i]=center[i];
       }
       if(Open[i]>center[i] && Close[i]<center[i]){
//         downArrowY[i]=center[i];
       }
      
   }
 }
  