//+------------------------------------------------------------------
//|  Swing Reversal Candle V1.0
//|  Original Code by mladen for High-Low-mtf.mq4
//|  Mod by :  BlueRain  - ForexFactory                                                   
//|  For Swing High/Low candle with Reversal pattern
//+------------------------------------------------------------------
#property copyright "mladen"
#property link      "mladenfx@gmail.com"
#property link      "www.forex-station.com"

#property indicator_chart_window
#property indicator_buffers 15

/*
//band
#property indicator_color1  clrNONE
#property indicator_color2  clrNONE
#property indicator_color3  clrNONE

//line
#property indicator_color4  clrNONE  //line
#property indicator_color5  clrNONE //line

#property indicator_color6  clrNONE  
#property indicator_color7  clrPaleVioletRed

//dot buffer 7 & 8
//peakup - 7 on the highest
//peakdn - 8 on the lowest
#property indicator_color8  clrDeepSkyBlue
#property indicator_color9  clrPaleVioletRed

#property indicator_color10 clrNONE
#property indicator_color11 clrNONE
#property indicator_color12 clrNONE
#property indicator_color13 clrNONE

*/

#property indicator_color14 clrGreen
#property indicator_color15 clrRed

/*
#property indicator_style1  STYLE_DOT
#property indicator_style2  STYLE_DOT
#property indicator_style3  STYLE_DOT


#property indicator_width8  2
#property indicator_width9  2
*/

#property strict

extern ENUM_TIMEFRAMES TimeFrame       = PERIOD_CURRENT;  // Time frame
extern int             HighLowPeriod   = 10;              // High low period
extern bool            Interpolate     = true;            // Interpolate in multi time frame mode?

int             ZigZagLineWidth = 0;               // Lines width

enum BoxStyle
{

   FILL,
   OUTLINE
};

extern bool ShowArrow = true;
extern int ArrowSize = 2;
extern int uparrowCode = 159; //up
extern int dnarrowCode = 159; //down
//Arrow color
extern color MarkerColorUp = LimeGreen;
extern color MarkerColorDown = OrangeRed;

extern color BoxLineColor = clrBlue;   
extern int BoxLineWidth = 2;
extern BoxStyle boxstyle = OUTLINE; 



double peakUp[],peakDn[],legUpa[],legUpb[],legDna[],legDnb[],limHi[],limMi[],limLo[],leg[],zigzag[],trend[],count[];

//--- indicator buffers
double         dnBuffer[];
double         upBuffer[];


string indicatorFileName;
int alertshiftbar = 2;  //orderbook will look forward 2 bar max, 


string        BoxIdentifier = "CboxLine";
double atr;
string name;


#define _mtfCall(_buf,_ind) iCustom(NULL,TimeFrame,indicatorFileName,0,HighLowPeriod,_buf,_ind)


int init()
{
   IndicatorBuffers(15);
   
      //limit band line 
      SetIndexBuffer(0,limHi);  //limit line high
      SetIndexBuffer(1,limMi);  //limit line mi
      SetIndexBuffer(2,limLo);  // limit line low
      
      //zigzag line up trend
      SetIndexBuffer(3,legUpa); SetIndexStyle(3,EMPTY,EMPTY,ZigZagLineWidth);
      SetIndexBuffer(4,legUpb); SetIndexStyle(4,EMPTY,EMPTY,ZigZagLineWidth);
   
      //zigzag line down trend
      SetIndexBuffer(5,legDna); SetIndexStyle(5,EMPTY,EMPTY,ZigZagLineWidth);
      SetIndexBuffer(6,legDnb); SetIndexStyle(6,EMPTY,EMPTY,ZigZagLineWidth);
      
      //peak dot
      SetIndexBuffer(7,peakUp); SetIndexStyle(7,DRAW_ARROW); SetIndexArrow(7,159);  //dot
      SetIndexBuffer(8,peakDn); SetIndexStyle(8,DRAW_ARROW); SetIndexArrow(8,159);  //dot
      
      
      SetIndexBuffer(9,leg);
      SetIndexBuffer(10,trend);
      SetIndexBuffer(11,zigzag);
      SetIndexBuffer(12,count);
      
    //---- Candle indicators
    //candle buffer
    SetIndexBuffer(13,upBuffer);    SetIndexStyle(13, DRAW_ARROW,EMPTY,ArrowSize,MarkerColorUp); SetIndexArrow(13,uparrowCode); SetIndexLabel(13, "Up"); 
    SetIndexBuffer(14,dnBuffer);  SetIndexStyle(14, DRAW_ARROW,EMPTY,ArrowSize,MarkerColorDown); SetIndexArrow(14,dnarrowCode); SetIndexLabel(14, "Down"); 
    
    SetIndexEmptyValue(13,EMPTY_VALUE);
    SetIndexEmptyValue(14,EMPTY_VALUE);
      
    IndicatorShortName(WindowExpertName()); 
    
    TimeFrame         = MathMax(TimeFrame,_Period);
   return(0);
}
int deinit()
{
   deleteObjects();
   return(0);
}

//+------------------------------------------------------------------
//|                                                                  
//+------------------------------------------------------------------
//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
      if (counted_bars<0) return(-1);
      if (counted_bars>0) counted_bars--;
          int limit = MathMin(Bars-counted_bars,Bars-1);
          int countz = 0;
          
          
            int k = limit; 
            
            for (; k<Bars && countz<2; k++)
            {
               if (peakUp[k] != EMPTY_VALUE) countz ++;
               if (peakDn[k] != EMPTY_VALUE) countz ++;
            }
            count[0] = k;
            if (TimeFrame != _Period)
            {
               limit = (int)MathMax(limit,MathMin(Bars-1,_mtfCall(12,0)*TimeFrame/Period()));
               if (trend[limit]== 1) CleanPoint(limit,legUpa,legUpb);
               if (trend[limit]==-1) CleanPoint(limit,legDna,legDnb);
               for (int i=limit; i>=0; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,Time[i]);
                  int x = (i<Bars-1) ? iBarShift(NULL,TimeFrame,Time[i+1]) : y;
                  if (Interpolate) x = (i>0) ? iBarShift(NULL,TimeFrame,Time[i-1]) : x;
                  
                     limHi[i]  = _mtfCall( 0,y);
                     limMi[i]  = _mtfCall( 1,y);
                     limLo[i]  = _mtfCall( 2,y);
                     
                     trend[i]  = _mtfCall(10,y);
                     zigzag[i] = _mtfCall(11,y);
                     
                     peakUp[i] = EMPTY_VALUE;
                     peakDn[i] = EMPTY_VALUE;
                     
                     if (x!=y)
                     {
                        peakUp[i] = _mtfCall(7,y);
                        peakDn[i] = _mtfCall(8,y);
                     }
         
                     //
                     //
                     //
                     //
                     //

                        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; 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(limHi); 
                                 _interpolate(limLo); 
                                 _interpolate(limMi); 
                                 if (zigzag[i]!=EMPTY_VALUE) _interpolate(zigzag); 
                           }               
                  }
                  for (int i=limit; i>=0; i--)
                  {
                     legDna[i]  = EMPTY_VALUE; 
                     legDnb[i]  = EMPTY_VALUE; 
                     legUpa[i]  = EMPTY_VALUE; 
                     legUpb[i]  = EMPTY_VALUE; 
                     if (trend[i]== 1) PlotPoint(i,legUpa,legUpb,zigzag);
                     if (trend[i]==-1) PlotPoint(i,legDna,legDnb,zigzag);
                  }
                  return(0);
            }
            
   //
   //
   //
   //
   //
   
      if (trend[limit]== 1) CleanPoint(limit,legUpa,legUpb);
      if (trend[limit]==-1) CleanPoint(limit,legDna,legDnb);
      
      for (int i=limit,n=0; i>=0; i--)
      {
         peakUp[i] = EMPTY_VALUE;
         peakDn[i] = EMPTY_VALUE;
         zigzag[i] = EMPTY_VALUE;
         limHi[i]  = High[ArrayMaximum(High,HighLowPeriod,i)];
         limLo[i]  = Low[ArrayMinimum(Low,HighLowPeriod,i)];
         limMi[i]  = (limHi[i]+limLo[i])/2.0;
         leg[i]    = (i<Bars-1) ? leg[i+1] : 0;
      
         if ((i<Bars-1) && limHi[i]>limHi[i+1]) leg[i] = MathMax( 1,leg[i+1]+1);
         if ((i<Bars-1) && limLo[i]<limLo[i+1]) leg[i] = MathMin(-1,leg[i+1]-1);
         if (leg[i] > 0 && leg[i] != leg[i+1]) { if (leg[i]>1) cleanUppeak(i); peakUp[i] = High[i]; }
         if (leg[i] < 0 && leg[i] != leg[i+1]) { if (leg[i]<1) cleanDnpeak(i); peakDn[i] = Low[i];  }
 
         
         trend[i] = (i<Bars-1) ? trend[i+1] : 0;
         if (peakUp[i] != EMPTY_VALUE || peakDn[i] != EMPTY_VALUE)
         {
            if (peakUp[i] != EMPTY_VALUE)
            {
                  for(n = 1; i+n < Bars-1 && peakUp[i+n]==EMPTY_VALUE; n++) continue; if (peakUp[i+n]<peakUp[i]) trend[i] = 1;
                  for(n = 1; i+n < Bars-1 && peakDn[i+n]==EMPTY_VALUE; n++) continue;
            }
            if (peakDn[i] != EMPTY_VALUE)
            {
                  for(n = 1; i+n < Bars-1 && peakDn[i+n]==EMPTY_VALUE; n++) continue; if (peakDn[i+n]>peakDn[i]) trend[i] = -1;
                  for(n = 1; i+n < Bars-1 && peakUp[i+n]==EMPTY_VALUE; n++) continue;
            }
            
            //
            //
            //
            //
            //
            
            if (trend[i] == 1)
                  if (peakUp[i] != EMPTY_VALUE) 
                        { zigzag[i] = peakUp[i]; zigzag[i+n] = peakDn[i+n]; }
                  else  { zigzag[i] = peakDn[i]; zigzag[i+n] = peakUp[i+n]; }
            else
                  if (peakUp[i] != EMPTY_VALUE) 
                        { zigzag[i] = peakUp[i]; zigzag[i+n] = peakDn[i+n]; }
                  else  { zigzag[i] = peakDn[i]; zigzag[i+n] = peakUp[i+n]; }
            
            //
            //
            //
            //
            //
            
            for(k=1; k<n; k++)
            {
               zigzag[i+k] = zigzag[i] + (zigzag[i+n]-zigzag[i])*k/n;
               trend[i+k]  = trend[i];
            }  	            
            for(k=n-1; k>=0; k--)
            {
               legDna[i+k]  = EMPTY_VALUE; 
               legDnb[i+k]  = EMPTY_VALUE; 
               legUpa[i+k]  = EMPTY_VALUE; 
               legUpb[i+k]  = EMPTY_VALUE; 
                  if (trend[i]== 1) PlotPoint(i+k,legUpa,legUpb,zigzag);
                  if (trend[i]==-1) PlotPoint(i+k,legDna,legDnb,zigzag);
            }                  
         }               
      }
      
    
    //------------------------------------
    //Candle Pattern Handling
    //------------------------------------- 
 
   
     for (int i=limit-1; i>=0;i--){
   
      //sell  - u,u, down long below u low 
      atr = iATR(Symbol(),0,100,0);
      //Highest
      name =  BoxIdentifier+":"+TimeToStr(Time[i]);
      
      
      if (peakUp[i+1] != EMPTY_VALUE && peakDn[i+1] == EMPTY_VALUE)
      {
      
       //up
       if ( High[i+1] > High[i+2] && //highest candle break high
            Close[i] < Low[i+1]  //bear candle - break low
          )  
            { 
                  if (ShowArrow) upBuffer[i+1]=High[i+1] + atr/2;
                  
                       ObjectCreate(name,OBJ_RECTANGLE,0,Time[i+2],0,Time[i],0);
                       ObjectSet(name,OBJPROP_FILL,false);         
                       ObjectSet(name,OBJPROP_COLOR,BoxLineColor);
                       ObjectSet(name,OBJPROP_WIDTH,BoxLineWidth);
                       if (boxstyle == OUTLINE)
                             ObjectSet(name,OBJPROP_BACK,0);
                        
                       int HighPoint = iHighest(Symbol(),0,MODE_HIGH,3,i);
                       int LowPoint =  iLowest(Symbol(),0,MODE_LOW,3,i);
                       ObjectSet(name,OBJPROP_PRICE1,High[HighPoint]);
                       ObjectSet(name,OBJPROP_PRICE2,Low[LowPoint]);
                      
            }
      //buy
      
      }
      
      else 
      if (peakDn[i+1] != EMPTY_VALUE && peakUp[i+1] == EMPTY_VALUE) 
      {
         if (   Low[i+1] < Low[i+2] && //highest candle break high
                Close[i] >  High[i+1]//4th candle close above 3rd candle wick
            )
               
               {
                 if (ShowArrow) dnBuffer[i+1]=Low[i+1] - atr/2;
                  
                    ObjectCreate(name,OBJ_RECTANGLE,0,Time[i+2],0,Time[i],0);
                       ObjectSet(name,OBJPROP_FILL,false);        
                       ObjectSet(name,OBJPROP_COLOR,BoxLineColor);
                       ObjectSet(name,OBJPROP_WIDTH,BoxLineWidth);
                    
                     if (boxstyle == OUTLINE)
                             ObjectSet(name,OBJPROP_BACK,0);
                       
                        
                       int HighPoint = iHighest(Symbol(),0,MODE_HIGH,3,i);
                       int LowPoint =  iLowest(Symbol(),0,MODE_LOW,3,i);
                       ObjectSet(name,OBJPROP_PRICE1,High[HighPoint]);
                       ObjectSet(name,OBJPROP_PRICE2,Low[LowPoint]);
            
                }
      }
   }
   
   
      
      return(0);
}



void deleteObjects()
{
   string lookFor       = BoxIdentifier+":";
   int    lookForLength = StringLen(lookFor);
   for (int i=ObjectsTotal()-1; i>=0; i--)
   {
      string objectName = ObjectName(i);
         if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
   }
}




//+------------------------------------------------------------------+
//|    Util Functions                                                              |
//+------------------------------------------------------------------+
string TF2Str(int period)
  {
   switch(period)
     {
      case PERIOD_M1: return("M1");
      case PERIOD_M5: return("M5");
      case PERIOD_M15: return("M15");
      case PERIOD_M30: return("M30");
      case PERIOD_H1: return("H1");
      case PERIOD_H4: return("H4");
      case PERIOD_D1: return("D1");
      case PERIOD_W1: return("W1");
      case PERIOD_MN1: return("MN");
     }
   return(IntegerToString(Period()));
  }
  


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; }
}



//+------------------------------------------------------------------
//|                                                                  
//+------------------------------------------------------------------
//
//
//
//
//

void cleanUppeak(int i)
{
   for (int k=i+1; k<Bars && peakDn[k]==EMPTY_VALUE; k++) 
         if (peakUp[k] != EMPTY_VALUE) { peakUp[k]=EMPTY_VALUE; break; }
}
void cleanDnpeak(int i)
{
   for (int k=i+1; k<Bars && peakUp[k]==EMPTY_VALUE; k++) 
         if (peakDn[k] != EMPTY_VALUE) { peakDn[k]=EMPTY_VALUE; break; }
}