//+------------------------------------------------------------------
//|                                              BR 4 Bar Fractal Pattern   |
//+------------------------------------------------------------------
#property copyright "BlueRain"



#property indicator_chart_window
#property indicator_buffers 2

#property strict

//1,2 - Buy/Sell arrow signal
#property indicator_color1 clrBlue
#property indicator_color2 clrRed



//ENGULFING
#property indicator_width1 2
#property indicator_width2 2


extern bool  Include_5Bar_Pattern = true;
extern bool  Show_TP_Line = true;
extern double TP = 100;
extern color BuyTextColor = clrBlue;
extern color SellTextColor = clrRed;
extern color BuyLineColor = clrBlue;
extern color SellLineColor = clrRed;

extern bool  Show_Box = true;
extern color Box_Color = clrYellow;
extern bool  Show_Rail_Box = true;
extern color RailBox_Color = clrRed;



extern string _AlertSetting  = "--Alert Setting --";
extern bool   alertsOn            = false;
extern bool   alertsOnCurrentBar     = false;
extern bool   alertsMessage       = true;
extern bool   alertsNotification  = false;
extern bool   alertsSound         = true;
extern bool   alertsEmail         = false;

datetime PrevTime;              
string ShortName="BR4BF_Indi"; 
double OHLC_D1[][6];  





double pips;


  //+------------------------------------------------------------------+
//| Figure type                                                      |
//+------------------------------------------------------------------+
  
enum DIRECTION
{
  UP,
  DOWN
}; 

 

string indicatorFileName;


//--- indicator buffers
double         Sell4BFArrowBuffer[]; 
double         Buy4BFArrowBuffer[];

string LabelID = "BR4Fractal_"; 

 int shift,shift1,shift2,shift3;
double O, O1, O2, C, C1, C2, L, L1, L2, H, H1, H2;

   
double atr;
datetime HT,LT;   

int MaxBarLimit = 1000;
double timeX = 0;


#define LONG 1
#define SHORT -1



int init()
{
      IndicatorBuffers(4);
      
    
      
      //3BF
      SetIndexBuffer(0,Sell4BFArrowBuffer); 
      SetIndexBuffer(1,Buy4BFArrowBuffer);
      SetIndexStyle(0, DRAW_ARROW,EMPTY,1,clrRed);  //sell
      SetIndexStyle(1, DRAW_ARROW,EMPTY,1,clrBlue);
      SetIndexEmptyValue(0,EMPTY_VALUE);
      SetIndexEmptyValue(1,EMPTY_VALUE);
      SetIndexArrow(0,116);
      SetIndexArrow(1,116);
      
      pips = GetPipMultiplier(Symbol());
 
   
      switch(Period())                 // Calculating coefficient for..
     {
      // .. different timeframes
      case     1:
         LT=PERIOD_M5;
         HT=PERIOD_M15;
         break;// Timeframe M1
      case     5:
         LT=PERIOD_M1;
         HT=PERIOD_M15;
         break;// Timeframe M5
      case    15:
         LT=PERIOD_M5;
         HT=PERIOD_M30;
         break;// Timeframe M15
      case    30:
         LT=PERIOD_M15;
         HT=PERIOD_H1;
         break;// Timeframe M30
      case    60:
         LT=PERIOD_M30;
         HT=PERIOD_H4;
         break;// Timeframe H1
      case   240:
         LT=PERIOD_H1;
         HT=PERIOD_D1;
         break;// Timeframe H4
      case  1440:
         LT=PERIOD_H4;
         HT=PERIOD_W1;
         break;// Timeframe D1
      case 10080:
         LT=PERIOD_D1;
         HT=PERIOD_MN1;
         break;// Timeframe W1
      case 43200:
         LT=PERIOD_W1;
         HT=PERIOD_D1;
         break;// Timeframe MN
     }
         
     if(Period()==1   )timeX=60;if(Period()==5    )timeX=300;if(Period()==15   )timeX=900;
     if(Period()==30  )timeX=1800;if(Period()==60   )timeX=3600;if(Period()==240  )timeX=14400;
     if(Period()==1440)timeX=86400;if(Period()==10080)timeX=604800;if(Period()==43200)timeX=2592000;
  
     IndicatorShortName(ShortName);
 
     //indicatorFileName = WindowExpertName();
         
   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=Bars-20;
      if(counted_bars>=20) limit=Bars-counted_bars-1;
      
      //We want to limit to 150
      int BarMax = MathMin(limit,200);
      string name;
      
    
      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      //3 Candle Fractal handline section
      //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       for (int i=BarMax ;i>=0; i--)
       {
            atr = iATR(Symbol(),0,100,i);
       
                  
            //Sell ---------------------------------------
            if (  (is3FractalPatternConfirmed(SHORT,i)== true )   )
                {
                  
                       Sell4BFArrowBuffer[i] = High[i] + atr/2;
                      // WritePatternNameToCandle(i,"Sell","HIGH"); 
                                            
                       name = LabelID + " Sell_line_"+ IntegerToString(i);
                       DrawLine(name, Time[i+1], Time[i+1] + timeX*10, Low[i+1], Low[i+1],SellLineColor);         
                      
                      if (   Show_TP_Line && TP > 0 )
                       {
                       
                           DrawLine(LabelID + " Sell_TP_line"+ IntegerToString(i), Time[i+1],Time[i+1] + timeX*10,Low[i+1] -  TP*pips,Low[i+1] -  TP*pips,BuyLineColor);
                        
                      }
                      
                   if (Show_Box)
                   {
                     name = StringConcatenate(LabelID, ":Box", "Short" , IntegerToString(i)); 
                     
                     int highest = iHighest(Symbol(),PERIOD_CURRENT,MODE_HIGH,4,i+1);
                     int lowest = iLowest(Symbol(),PERIOD_CURRENT,MODE_LOW,4,i+1);
                     
                     Print("Short High is " + highest);
                     
                      Draw_Area(LabelID + ":Box_Short" + IntegerToString(i),Time[i+4],High[highest],Time[i+1],Low[lowest],Box_Color);
                    // RectangleCreate(0,name,0,Time[i+4],High[i+4],Time[i+1],Low[i+1],Box_Color,0,1,false,false,false,true,0);
                                
                   }
                   
                       
                   if (Show_Rail_Box)
                   {
                     name = StringConcatenate(LabelID, ":RailBox", "Short" , IntegerToString(i)); 
                     
                     int highest = iHighest(Symbol(),PERIOD_CURRENT,MODE_HIGH,2,i+2);
                     int lowest = iLowest(Symbol(),PERIOD_CURRENT,MODE_LOW,2,i+2);
                     
                     Print("Short High is " + highest);
                     
                      Draw_Area(LabelID + ":RailBox_Short" + IntegerToString(i),Time[i+3],High[highest],Time[i+2],Low[lowest],RailBox_Color);
                    // RectangleCreate(0,name,0,Time[i+4],High[i+4],Time[i+1],Low[i+1],Box_Color,0,1,false,false,false,true,0);
                                
                   }
                   
                          
                    
                       
                  }    
           
              //Buy --------------------------------------------------------
              if (   is3FractalPatternConfirmed(LONG,i) == true    )
                 {
                       Buy4BFArrowBuffer[i] = Low[i] - atr/2;
                     //  WritePatternNameToCandle(i,"Buy","LOW"); 
                       
                       name = LabelID + " Buy_line_"+ IntegerToString(i);
                       DrawLine(name, Time[i+1],Time[i+1] + timeX*10, High[i+1], High[i+1],BuyLineColor);   
                       
                       if (   Show_TP_Line && TP > 0)
                       {
                       
                           DrawLine(LabelID + " Buy_TP_line"+ IntegerToString(i), Time[i+1],Time[i+1] + timeX*10,High[i+1] +  TP*pips,High[i+1] + TP*pips,BuyLineColor);
                           
                          
         
                      }
                      
                       if (Show_Box)
                         {
                           name = StringConcatenate(LabelID, ":Box", "Long", IntegerToString(i)); 
                           
                           int highest = iHighest(NULL,0,MODE_HIGH,4,i+1);
                           int lowest = iLowest(NULL,0,MODE_LOW, 4,i+1);
                           
                         //  RectangleCreate(0,name,0,Time[i+4],highest,Time[i+1],lowest,Box_Color,0,1,false,false,false,true,0);
                         //  RectangleCreate(0,name,0,Time[i+4],High[i+4],Time[i+1],Low[i+1],Box_Color,0,1,false,false,false,true,0);
                         //RectangleCreate(0,name,0,Time[i+4],lowest,Time[i+1],highest,Box_Color,0,1,false,false,false,true,0);
                           Draw_Area(LabelID + ":Box_Long" + IntegerToString(i),Time[i+4],High[highest],Time[i+1],Low[lowest],Box_Color);           
                         }
                         
                        
                       if (Show_Rail_Box)
                         {
                           name = StringConcatenate(LabelID, ":RailBox", "Long", IntegerToString(i)); 
                           
                           int highest = iHighest(NULL,0,MODE_HIGH,2,i+2);
                           int lowest = iLowest(NULL,0,MODE_LOW, 2,i+2);
                           
                         //  RectangleCreate(0,name,0,Time[i+4],highest,Time[i+1],lowest,Box_Color,0,1,false,false,false,true,0);
                         //  RectangleCreate(0,name,0,Time[i+4],High[i+4],Time[i+1],Low[i+1],Box_Color,0,1,false,false,false,true,0);
                         //RectangleCreate(0,name,0,Time[i+4],lowest,Time[i+1],highest,Box_Color,0,1,false,false,false,true,0);
                           Draw_Area(LabelID + ":RailBox_Long" + IntegerToString(i),Time[i+3],High[highest],Time[i+2],Low[lowest],RailBox_Color);           
                         }
                         
                   
                                
                  }
                  
                  
              
         }
          

       WindowRedraw();
  
       manageAlerts();        
      
      return(0);
}



  
void deleteObjects()
{
   string lookFor       = LabelID;
   int    lookForLength = StringLen(lookFor);
   for (int i=ObjectsTotal()-1; i>=0; i--)
   {
      string objectName = ObjectName(i);
         if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
   }
}




  
  
void DrawLine(string name, datetime Time1, datetime Time2, double pointA, double pointB,color linecolor=clrRed)
{


 if ( ObjectFind(name)) ObjectDelete(name);
 
 ObjectCreate(name,OBJ_TREND,0,Time1,0,Time2,0);
                      
 ObjectSet(name,OBJPROP_COLOR,linecolor);
  ObjectSet(name,OBJPROP_WIDTH,2);
                  ObjectSet(name,OBJPROP_RAY,false);
                  
                   ObjectSet(name,OBJPROP_PRICE1,pointA);
                   ObjectSet(name,OBJPROP_PRICE2,pointB);
                   
                   
}
 

void DrawLine(string name, datetime Time1, datetime Time2, double Price1, double Price2,color lcolor, int lwidth,ENUM_LINE_STYLE linestyle)
{
  
          ObjectDelete(name);
            
          ObjectCreate(name,OBJ_TREND,0,Time1,0,Time2,0);
                      
          ObjectSet(name,OBJPROP_COLOR,lcolor);
          
          if (linestyle == STYLE_SOLID)
           ObjectSet(name,OBJPROP_WIDTH,lwidth);
          
          ObjectSet(name,OBJPROP_STYLE,linestyle);
         
          ObjectSet(name,OBJPROP_RAY,false);
              
          ObjectSet(name,OBJPROP_PRICE1,Price1);
          ObjectSet(name,OBJPROP_PRICE2,Price2);
                   

}  


void WritePatternNameToCandle(int i,string text, string position)
{

  
  double _atr=iATR(Symbol(),PERIOD_CURRENT,30,i);
  string name = StringConcatenate(LabelID, ":CandlePattern", TimeToStr(Time[i]), IntegerToString(i)); 
  
  if (position == "HIGH")
             {
                       ObjectCreate(name + text, OBJ_TEXT, 0, Time[i], High[i] + _atr);
                        ObjectSetText(name + text, text, 9, "Times New Roman", SellTextColor);
             }
                         
  else if (position == "LOW")
              {
                   ObjectCreate(name + text, OBJ_TEXT, 0, Time[i], Low[i] - _atr);
                   ObjectSetText(name + text, text, 9, "Times New Roman", BuyTextColor);    
              }     

                                              
               

}


void manageAlerts()
{
string msg;
int whichBar;

   if (alertsOn)
   {
      if (alertsOnCurrentBar)
               whichBar = 0;
      else     whichBar = 1; 
     
         if (Sell4BFArrowBuffer[whichBar]  != EMPTY_VALUE)
         {   msg =   StringConcatenate(Symbol(),", ",timeFrameToString(_Period)," BR 4Bar Fractal "," SELL "," @ ",TimeToStr(TimeLocal(),TIME_SECONDS));
             doAlert(whichBar,msg);
          }
          
         if (Buy4BFArrowBuffer[whichBar] != EMPTY_VALUE) 
         {
            msg =   StringConcatenate(Symbol(),", ",timeFrameToString(_Period)," BR 4Bar Fractal "," BUY "," @ ",TimeToStr(TimeLocal(),TIME_SECONDS));
           doAlert(whichBar,msg);
         }
   }
}

//
//
//
//
//

void doAlert(int forBar, string doWhat)
{

static string   previousAlert="nothing";
static datetime previousTime = TimeCurrent();

   
   if (previousAlert != doWhat && previousTime != Time[forBar]) {
       previousAlert  = doWhat;
       previousTime   = Time[forBar];

 
    if (alertsMessage)      Alert(doWhat);
          if (alertsEmail)        SendMail(StringConcatenate(Symbol()," BR Scalper "),doWhat);
          if (alertsNotification) SendNotification(doWhat);
          if (alertsSound)        PlaySound("alert2.wav");
   }
}


string sTfTable[] = {"M1","M5","M10","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,10,15,30,60,240,1440,10080,43200};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}



bool is3FractalPatternConfirmed(int Direction,int i)
{


 if (Direction == SHORT)
  {
      if ( Include_5Bar_Pattern == false)
      {
            if (  Open[i+4] < Close[i+4] &&  //up - 4
                  Open[i+3] < Close[i+3] &&  //up  - 3
                  
                  Close[i+3] > Close[i+4]  && //higher high
                  Open[i+3] > Open[i+4]  &&  //Higher Low
                  
                    
                  Open[i+2] > Close[i+2] &&  //down  2
                  Open[i+1] > Close[i+1] &&  //down  1
                 // Open[i]  >  Close[i] && //down 0
                  
                  
                  Open[i+2] > Open[i+1] && //lower open
                  Close[i+2]> Close[i+1] //&& //lower open
                  
                //  Low[i+1] > Low[i]   // candle 0 low breaks candle 2
              
             ) 
             {
           
                   
             return(true);
             }
       }
       else
       {
       
           if (  Open[i+4] < Close[i+4] &&  //up - 4
                  Open[i+3] < Close[i+3] &&  //up  - 3
                  
                  Close[i+3] > Close[i+4]  && //higher high
                  Open[i+3] > Open[i+4]  &&  //Higher Low
                  
                    
                  Open[i+2] > Close[i+2] &&  //down  2
                  Open[i+1] > Close[i+1] &&  //down  1
                  Open[i]  >  Close[i] && //down 0
                  
                  
                  Open[i+2] > Open[i+1] && //lower open
                  Close[i+2]> Close[i+1] && //lower open
                  
                  Low[i+1] > Low[i]   // candle 0 low breaks candle 2
              
             ) 
             {
           
           
                   
             return(true);
             }
        }
       
  }
  
  
  if (Direction == LONG)
  {
     if ( Include_5Bar_Pattern == false )
     {
            if (  Open[i+4] > Close[i+4] &&  //down
                  Open[i+3] > Close[i+3] &&  //down
                  
                  Close[i+3] < Close[i+4]  && //lower low
                  Open[i+3] < Open[i+4]  &&  //lower open 
                  
                            
                  Open[i+2] < Close[i+2] &&  //up
                  Open[i+1] < Close[i+1] &&  //up
                //  Open[i]  <  Close[i] && //down 0
                   
                  Open[i+2] < Open[i+1] && //lower open
                  Close[i+2] < Close[i+1] //&& //lower open
                 
                //  High[i+1] < High[i]   // candle 1 low breaks candle 2
              
             ) 
             {
           
         
                   
                   
             return(true);
             }
     }
     else
     {
     
           if (  Open[i+4] > Close[i+4] &&  //down
                  Open[i+3] > Close[i+3] &&  //down
                  
                  Close[i+3] < Close[i+4]  && //lower low
                  Open[i+3] < Open[i+4]  &&  //lower open 
                  
                            
                  Open[i+2] < Close[i+2] &&  //up
                  Open[i+1] < Close[i+1] &&  //up
                  Open[i]  <  Close[i] && //down 0
                   
                  Open[i+2] < Open[i+1] && //lower open
                  Close[i+2] < Close[i+1] && //lower open
                 
                  High[i+1] < High[i]   // candle 1 low breaks candle 2
              
             ) 
             {
           
   
                   
             return(true);
             }
     
     
     
     
     
     }
  }
  
  
  
  
  return false;
     
       
  

}




//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double getPoint(string symbol)
  {
   return MarketInfo(symbol,MODE_POINT);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double getModifier(string symbolName)
  {
   int digits=(int) MarketInfo(symbolName,MODE_DIGITS);
   double modifier=1;
   
   if(digits==3 || digits==5)
   
      modifier=10.0;
   
   return modifier;
  }

//Function to normalize the digits
double CalculateNormalizedDigits(string symbolName)
  {

   double digits = MarketInfo(symbolName,MODE_DIGITS);

   if( digits <=3)
     {
      return(0.01);
     }
   else
      if( digits >=4)
        {
         return(0.0001);
        }
      else
         return(0);
  }



  string TF2Str(int nperiod)
  {
   switch(nperiod)
     {
      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");
     }
     
    if ( Period() == PERIOD_M1) return("M1");
    if ( Period() == PERIOD_M5) return("M5");
    if ( Period() == PERIOD_M15) return("M15");
    if ( Period() == PERIOD_M30) return("M30");
    if ( Period() == PERIOD_H1) return("H1");
    if ( Period() == PERIOD_H4) return("H4");
    if ( Period() == PERIOD_D1) return("D1");
    if ( Period() == PERIOD_W1) return("W1");
    if ( Period() == PERIOD_MN1) return("MN1");


   return("Unknown");
  }
  
  double GetPipMultiplier(string symbol)
{
   double multi;
   
   // adjust for 4- and 5- digits brokers
   double mdigits = MarketInfo(Symbol(),MODE_DIGITS);
   double mpoints = MarketInfo(Symbol(),MODE_POINT);
   
   //multiplier to points to get pip point
   if( mdigits == 2 || mdigits == 4 ){ mpoints *= 1; }
   if( mdigits == 3 || mdigits == 5 ){ mpoints *= 10; }
   if( mdigits == 6 ){ mpoints *= 100; }
   if (mdigits == 2 && StringFind(symbol, "XAU") > -1)  { mpoints *=10; }
   if (mdigits == 2 && StringFind(symbol, "GOLD") > -1) { mpoints *= 10; }    // If 2 digits and currency is gold
  
  
   
    multi = mpoints;
    
return (multi);

}



void Draw_Area(string sName,  datetime time1, double price1, datetime time2, double price2, color dColor)
{
   ObjectCreate(sName,OBJ_RECTANGLE,0,time1,price1,time2,price2);
   ObjectSet(sName, OBJPROP_COLOR, dColor);
   ObjectSet(sName,OBJPROP_FILL,false);
   ObjectSet(sName,OBJPROP_BACK,0);
   ObjectSet(sName,OBJPROP_STYLE,STYLE_SOLID); 

    
}
  