//+------------------------------------------------------------------+
//|Stochastic OBS Squares.mq4                                        |
//+------------------------------------------------------------------+

#property indicator_chart_window
#property indicator_buffers   0

extern int                 Periods = 200;
extern ENUM_TIMEFRAMES     Periodicity = PERIOD_H1;
extern int                 StoK = 8;
extern int                 StoD = 3;
extern int                 StoMA = 5;
extern ENUM_MA_METHOD      StoMethod = MODE_SMA;
extern double              Overbought = 75;
extern double              Oversold = 25;
extern bool                ShowOverbought = true;
extern color               StoOBColor = clrBurlyWood;
extern bool                ShowOversold = true;
extern color               StoOSColor = clrSilver;
extern bool                ShowLabels = true;
extern string              LabelFont = "Arial";
extern int                 LabelSize = 8;
extern color               LabelColor = clrBlack;

int i,j;

datetime RealStoOBTime,RealStoOSTime;

void ObjDel()
{
   for(i = 1000; i >= 0; i--)
   {
      ObjectDelete(0,"StoOB"+Periodicity+"["+i+"]");
      ObjectDelete(0,"StoOBtxt"+Periodicity+"["+i+"]");
      ObjectDelete(0,"StoOS"+Periodicity+"["+i+"]");
      ObjectDelete(0,"StoOStxt"+Periodicity+"["+i+"]");
      
      ObjectDelete(0,"StoRealOB"+Periodicity);
      ObjectDelete(0,"StoRealOBtxt"+Periodicity);
      ObjectDelete(0,"StoRealOS"+Periodicity);
      ObjectDelete(0,"StoRealOStxt"+Periodicity);
   }
}

bool PlotTrend(const long              chart_ID=0,
               string                  name="trendline",
               const int               subwindow=0,
               datetime                time1=0,
               double                  price1=0,
               datetime                time2=0,
               double                  price2=0,             
               const color             clr=clrBlack,
               const ENUM_LINE_STYLE   style=STYLE_SOLID,
               const int               width=2,
               const bool              back=true,
               const bool              selection=false,
               const bool              ray=false,
               const bool              hidden=true)
{
   ResetLastError();
   if(!ObjectCreate(chart_ID,name,OBJ_TREND,subwindow,time1,price1,time2,price2))
   {
      Print(__FUNCTION__,": failed to create line = ",GetLastError());
      return(false);
   }
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
   ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_RAY,ray);
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
   return(true);
}



bool VLineCreate(const long            chart_ID=0,        // chart's ID
                 const string          name="VLine",      // line name
                 const int             sub_window=0,      // subwindow index
                 datetime              time=0,            // line time
                 const color           clr=clrRed,        // line color
                 const ENUM_LINE_STYLE style=STYLE_SOLID, // line style
                 const int             width=1,           // line width
                 const bool            back=false,        // in the background
                 const bool            selection=true,    // highlight to move
                 const bool            hidden=true,       // hidden in the object list
                 const long            z_order=0)         // priority for mouse click
  {
//--- if the line time is not set, draw it via the last bar
   if(!time)
      time=TimeCurrent();
//--- reset the error value
   ResetLastError();
//--- create a vertical line
   if(!ObjectCreate(chart_ID,name,OBJ_VLINE,sub_window,time,0))
     {
      Print(__FUNCTION__,
            ": failed to create a vertical line! Error code = ",GetLastError());
      return(false);
     }
//--- set line color
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set line display style
   ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set line width
   ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the line by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot be
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
   return(true);
  }
  
bool TextCreate(const long              chart_ID=0,               // chart's ID
                const string            name="Text",              // object name
                const int               sub_window=0,             // subwindow index
                datetime                time=0,                   // anchor point time
                double                  price=0,                  // anchor point price
                const string            text="Text",              // the text itself
                const string            font="Arial",             // font
                const int               font_size=10,             // font size
                const color             clr=clrRed,               // color
                const double            angle=0.0,                // text slope
                const ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER, // anchor type
                const bool              back=false,               // in the background
                const bool              selection=false,          // highlight to move
                const bool              hidden=true,              // hidden in the object list
                const long              z_order=0)                // priority for mouse click
  {
//--- set anchor point coordinates if they are not set
//--- reset the error value
   ResetLastError();
//--- create Text object
   if(!ObjectCreate(chart_ID,name,OBJ_TEXT,sub_window,time,price))
     {
      Print(__FUNCTION__,
            ": failed to create \"Text\" object! Error code = ",GetLastError());
      return(false);
     }
//--- set the text
   ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);
//--- set text font
   ObjectSetString(chart_ID,name,OBJPROP_FONT,font);
//--- set font size
   ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size);
//--- set the slope angle of the text
   ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle);
//--- set anchor type
   ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor);
//--- set color
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the object by mouse
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
   return(true);
  }

bool RectangleCreate(const long            chart_ID=0,        // chart's ID
                     const string          name="Rectangle",  // rectangle name
                     const int             sub_window=0,      // subwindow index 
                     datetime              time1=0,           // first point time
                     double                price1=0,          // first point price
                     datetime              time2=0,           // second point time
                     double                price2=0,          // second point price
                     const color           clr=clrRed,        // rectangle color
                     const ENUM_LINE_STYLE style=STYLE_SOLID, // style of rectangle lines
                     const int             width=1,           // width of rectangle lines
                     const bool            fill=true,        // filling rectangle with color
                     const bool            back=true,        // in the background
                     const bool            selection=false,    // highlight to move
                     const bool            hidden=true,       // hidden in the object list
                     const long            z_order=0)         // priority for mouse click
  {
//--- set anchor points' coordinates if they are not set
//--- reset the error value
   ResetLastError();
//--- create a rectangle by the given coordinates
   if(!ObjectCreate(chart_ID,name,OBJ_RECTANGLE,sub_window,time1,price1,time2,price2))
     {
      Print(__FUNCTION__,
            ": failed to create a rectangle! Error code = ",GetLastError());
      return(false);
     }
//--- set rectangle color
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- set the style of rectangle lines
   ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- set width of the rectangle lines
   ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- enable (true) or disable (false) the mode of filling the rectangle
   ObjectSetInteger(chart_ID,name,OBJPROP_FILL,fill);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of highlighting the rectangle for moving
//--- when creating a graphical object using ObjectCreate function, the object cannot be
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
   return(true);
  }
  
double UserStochasticMain(ENUM_TIMEFRAMES tf, int shft)
{
   return(iStochastic(NULL,tf,StoK,StoD,StoMA,StoMethod,0,0,shft));
}

double HighTwoTimes(ENUM_TIMEFRAMES tf, datetime t1, datetime t2)
{
   return(iHigh(NULL,tf,iHighest(NULL,tf,MODE_HIGH,iBarShift(NULL,tf,t1)-iBarShift(NULL,tf,t2),iBarShift(NULL,tf,t2))));
}

double LowTwoTimes(ENUM_TIMEFRAMES tf, datetime t1, datetime t2)
{
   return(iLow(NULL,tf,iLowest(NULL,tf,MODE_LOW,iBarShift(NULL,tf,t1)-iBarShift(NULL,tf,t2),iBarShift(NULL,tf,t2))));   
}

int init()
{
   return(0);
}
   
   
int deinit()
{
   ObjDel();
   Comment("");
   return(0);
}

int start()
{
   ObjDel();

   bool StoOBA = false;   datetime StoOBATime;
   bool StoOBB = false;   datetime StoOBBTime;
   
   datetime StoOBTime[1024][2]; int StoOBNum = 0;
   
   bool StoOSA = false;   datetime StoOSATime;
   bool StoOSB = false;   datetime StoOSBTime;
   
   datetime StoOSTime[1024][2]; int StoOSNum = 0;   

//+------------------------------------------------------------+
//|Update currently overbought stochastics data.               |
//+------------------------------------------------------------+
         
   if(UserStochasticMain(Periodicity,1) >= Overbought)
   {
      i=1;j=2;
      while(i!=0)
      {
         if(UserStochasticMain(Periodicity,j) < Overbought)
         {
            RealStoOBTime = iTime(NULL,Periodicity,j);
            i=0;
         }else{
            j++;
         }
      }
   }else{
      RealStoOBTime = iTime(NULL,Periodicity,0)+Periodicity*60;
   }
   
   if(UserStochasticMain(Periodicity,1) <= Oversold)
   {
      i=1;j=2;
      while(i!=0)
      {
         if(UserStochasticMain(Periodicity,j) > Oversold)
         {
            RealStoOSTime = iTime(NULL,Periodicity,j);
            i=0;
         }else{
            j++;
         }
      }
   }else{
      RealStoOSTime = iTime(NULL,Periodicity,0)+Periodicity*60;
   }
   
//+------------------------------------------------------------+
//|Update historical stochastics data.                         |
//+------------------------------------------------------------+
   
   for(i=Periods; i>=0; i--)
   {
      if(!StoOBA &&
         UserStochasticMain(Periodicity,i+2) <= Overbought &&
         UserStochasticMain(Periodicity,i+1) >  Overbought)
      {
         StoOBA = true; StoOBATime = iTime(NULL,Periodicity,i+2);
      }
      
      if(StoOBA && !StoOBB &&
         UserStochasticMain(Periodicity,i+2) >= Overbought &&
         UserStochasticMain(Periodicity,i+1) <  Overbought)
      {
         StoOBB = true; StoOBBTime = iTime(NULL,Periodicity,i+1);
      }
      
      if(StoOBA && StoOBB)
      {
         StoOBTime[StoOBNum][0] = StoOBATime;
         StoOBTime[StoOBNum][1] = StoOBBTime;
         
         StoOBA = false;
         StoOBB = false;
         
         StoOBNum++;
      }
   }

   for(i=Periods; i>=0; i--)
   {
      if(!StoOSA &&
         UserStochasticMain(Periodicity,i+2) >= Oversold &&
         UserStochasticMain(Periodicity,i+1) <  Oversold)
      {
         StoOSA = true; StoOSATime = iTime(NULL,Periodicity,i+2);
      }
      
      if(StoOSA && !StoOSB &&
         UserStochasticMain(Periodicity,i+2) <= Oversold &&
         UserStochasticMain(Periodicity,i+1) >  Oversold)
      {
         StoOSB = true; StoOSBTime = iTime(NULL,Periodicity,i+1);
      }
      
      if(StoOSA && StoOSB)
      {
         StoOSTime[StoOSNum][0] = StoOSATime;
         StoOSTime[StoOSNum][1] = StoOSBTime;
         
         StoOSA = false;
         StoOSB = false;
         
         StoOSNum++;
      }
   }

//+------------------------------------------------------------+
//|Draw specified rectangles.                                  |
//+------------------------------------------------------------+

   if(ShowOverbought)
   {
      RectangleCreate(0,"StoRealOB"+Periodicity,0,
                      RealStoOBTime,
                      HighTwoTimes(Periodicity,RealStoOBTime,iTime(NULL,Periodicity,0)),
                      iTime(NULL,Periodicity,0)+Periodicity*60,
                      LowTwoTimes(Periodicity,RealStoOBTime,iTime(NULL,Periodicity,0)),
                      StoOBColor);

      if(ShowLabels)
      {   
         TextCreate(0,"StoRealOBtxt"+Periodicity,0,
                    RealStoOBTime,
                    HighTwoTimes(Periodicity,RealStoOBTime,iTime(NULL,Periodicity,0)),
                    "M"+Periodicity, LabelFont,LabelSize,LabelColor,0,ANCHOR_LEFT_UPPER);
      }
      
      for(i = StoOBNum; i >= 0; i--)
      {
         RectangleCreate(0,"StoOB"+Periodicity+"["+i+"]",0,
                         StoOBTime[i][0],
                         HighTwoTimes(Periodicity,StoOBTime[i][0],StoOBTime[i][1]),
                         StoOBTime[i][1],
                         LowTwoTimes(Periodicity,StoOBTime[i][0],StoOBTime[i][1]),
                         StoOBColor);
         if(ShowLabels)
         {                           
            TextCreate(0,"StoOBtxt"+Periodicity+"["+i+"]",0,
                       StoOBTime[i][0],
                       HighTwoTimes(Periodicity,StoOBTime[i][0],StoOBTime[i][1]),
                       "M"+Periodicity, LabelFont,LabelSize,LabelColor,0,ANCHOR_LEFT_UPPER);
         }
      }
   }
     
   if(ShowOversold)
   {
      RectangleCreate(0,"StoRealOS"+Periodicity,0,
                      RealStoOSTime,
                      HighTwoTimes(Periodicity,RealStoOSTime,iTime(NULL,Periodicity,0)),
                      iTime(NULL,Periodicity,0)+Periodicity*60,
                      LowTwoTimes(Periodicity,RealStoOSTime,iTime(NULL,Periodicity,0)),
                      StoOSColor);
      if(ShowLabels)
      {      
         TextCreate(0,"StoRealOStxt"+Periodicity,0,
                    RealStoOSTime,
                    LowTwoTimes(Periodicity,RealStoOSTime,iTime(NULL,Periodicity,0)),
                    "M"+Periodicity, LabelFont,LabelSize,LabelColor,0,ANCHOR_LEFT_LOWER);
      }
      
      for(i = StoOSNum; i >= 0; i--)
      {
         RectangleCreate(0,"StoOS"+Periodicity+"["+i+"]",0,
                         StoOSTime[i][0],
                         HighTwoTimes(Periodicity,StoOSTime[i][0],StoOSTime[i][1]),
                         StoOSTime[i][1],
                         LowTwoTimes(Periodicity,StoOSTime[i][0],StoOSTime[i][1]),
                         StoOSColor);

         if(ShowLabels)
         {            
            TextCreate(0,"StoOStxt"+Periodicity+"["+i+"]",0,
                       StoOSTime[i][0],
                       LowTwoTimes(Periodicity,StoOSTime[i][0],StoOSTime[i][1]),
                       "M"+Periodicity, LabelFont,LabelSize,LabelColor,0,ANCHOR_LEFT_LOWER);
         }                              
      }
   }      
         
   return(0);
}