//+------------------------------------------------------------------+
//|                                                  Bands V1.01.mq4 |
//|                                             Copyright 2020, rair |
//|                                        https://www.eabuilder.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, rair"
#property link      "https://www.eabuilder.com"
#property version   "1.00"
#property strict

#property indicator_separate_window
#property indicator_buffers  6
#property indicator_color1   clrRed
#property indicator_color2   clrYellow // Pink // Red
#property indicator_color3   clrSilver
#property indicator_color4   clrSilver
#property indicator_color5   clrLime//Red
#property indicator_color6   clrPink // Red

#property indicator_width5 1
#property indicator_width6 1

#property indicator_style3 2
#property indicator_style4 2

#property  indicator_levelstyle 2 
#property  indicator_levelcolor clrYellow

//#property indicator_minimum -5 
//#property indicator_maximum 105 

extern int    Bands_period = 20;
extern double Bands_deviation = 2;
extern int    smoothing = 3; 
extern bool   Level_or_BB = false;
extern int    Bands_period_2 = 30;
extern double Bands_deviation_2 = 1.5;
extern double upper_level = 90;
extern double lower_level = 10;
extern int    History = 5000;
input bool        alertsOn         = true;                 // Alerts true/false?
input bool        alertsOnCurrent  = false;                // Alerts open bar true/false?
input bool        alertsMessage    = true;                 // Alerts pop-up message true/false?
input bool        alertsSound      = false;                // Alerts sound true/false?
input bool        alertsNotify     = false;                // Alerts push notification true/false?
input bool        alertsEmail      = false;                // Alerts email true/false?
input string      soundFile        = "alert2.wav";         // Sound file
input bool        arrowsVisible    = false;                // Arrows visible true/false?
input string      arrowsIdentifier = "bb Arrows1";         // Unique ID for arrows
input double      arrowsUpperGap   = 0.5;                  // Upper arrow gap
input double      arrowsLowerGap   = 0.5;                  // Lower arrow gap
input color       arrowsUpColor    = clrBlue;              // Up arrow color
input color       arrowsDnColor    = clrCrimson;           // Down arrow color
input int         arrowsUpCode     = 221;                  // Up arrow code
input int         arrowsDnCode     = 222;                  // Down arrow code
input int         arrowsUpSize     = 2;                    // Up arrow size
input int         arrowsDnSize     = 2;                    // Down arrow size
//---- buffers
double PercentBB[];
double BB_Smooth[];
double Fleche_up_1[];
double Fleche_down_1[];
double BBUp[];
double BBDn[],trend[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   IndicatorBuffers(7);
   SetIndexStyle (0, DRAW_LINE);
   SetIndexBuffer(0, PercentBB);
   SetIndexLabel (0, "%BB");
   SetIndexDrawBegin(0, Bands_period);
//----
   SetIndexStyle (1,  DRAW_LINE);
   SetIndexBuffer(1, BB_Smooth);
   SetIndexLabel (1, "%BB_Smooth");
   SetIndexDrawBegin(1, Bands_period);
//----
   SetIndexStyle (2, DRAW_LINE);
   SetIndexBuffer(2, BBUp);
   SetIndexLabel (2, "BB2Up");
   SetIndexDrawBegin(2, Bands_period);
//----
   SetIndexStyle (3,  DRAW_LINE);
   SetIndexBuffer(3, BBDn);
   SetIndexLabel (3, "BB2Dn");
   SetIndexDrawBegin(3, Bands_period);
//----   
   SetIndexBuffer(4, Fleche_up_1 );
   SetIndexStyle (4, DRAW_ARROW);
   SetIndexArrow (4,233);
   SetIndexEmptyValue(4,0.0);
//-----   
   SetIndexBuffer(5,Fleche_down_1);
   SetIndexStyle (5, DRAW_ARROW);
   SetIndexArrow (5,234);
   SetIndexEmptyValue(5,0.0);// 
//-----  
   SetIndexBuffer(6,trend); 
   if(Level_or_BB)
    {
      SetLevelValue( 0, 50.0 );
      SetLevelValue( 1,upper_level );
      SetLevelValue( 2,lower_level );
      //SetLevelStyle( 0,1, Yellow);
    }else{
      SetLevelValue( 0,-100);
      SetLevelValue( 1,-100);
      SetLevelValue( 2,-100);  
    }
   int MaxPer = MathMax(Bands_period,Bands_period_2); 
   MaxPer = MathMax(MaxPer,smoothing);
   
   if(History>Bars-MaxPer)  History = Bars-MaxPer-1;
   
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{ 
    string lookFor       = arrowsIdentifier+":";
    int    lookForLength = StringLen(lookFor);
    for (int i=ObjectsTotal()-1; i>=0; i--)
    {
       string objectName = ObjectName(i);
       if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
    }
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int counted_bars = IndicatorCounted(); 
   //int History = 5000;
//----
   double LB, UB;
   int i,limit;
   
   if(counted_bars > 0) counted_bars--;
   limit = Bars - counted_bars;
   if(limit > History) limit = History;
      
   for(i = 0; i < limit; i++)
    {
      LB = iBands(NULL, 0, Bands_period, Bands_deviation, 0, PRICE_CLOSE, MODE_LOWER, i);
      UB = iBands(NULL, 0, Bands_period, Bands_deviation, 0, PRICE_CLOSE, MODE_UPPER, i);
 
      PercentBB[i] =  ( Close[i+1] - LB)/(UB - LB) * 100;
    }
//---- signal line is simple movimg average
   for(i=0; i<limit; i++)
      BB_Smooth[i]=iMAOnArray(PercentBB,Bars,smoothing,0,MODE_SMA,i);
//---- signal line is simple movimg average
   if(Level_or_BB)
    {
      for(i=0; i<limit; i++)
       {
         if(BB_Smooth[i+1] > upper_level &&   BB_Smooth[i] < upper_level)
           Fleche_down_1[i] = upper_level; else Fleche_down_1[i] = 0;                      
               
         if(BB_Smooth[i+1] < lower_level &&   BB_Smooth[i] > lower_level)
           Fleche_up_1[i] = lower_level;   else Fleche_up_1[i] = 0;  
       }
    }else{
      for(i=0; i<limit; i++)
       {
         BBUp[i] = iBandsOnArray(BB_Smooth,0,Bands_period_2, Bands_deviation_2,0,MODE_UPPER,i);
         BBDn[i] = iBandsOnArray(BB_Smooth,0,Bands_period_2, Bands_deviation_2,0,MODE_LOWER,i);
       }
      for(i=0; i<limit; i++)
       { 
         if(BB_Smooth[i+1] > BBUp[i+1] && BB_Smooth[i] < BBUp[i]) 
           Fleche_down_1[i] = BBUp[i]+15; else Fleche_down_1[i] = 0;
        
         if(BB_Smooth[i+1] < BBDn[i+1] && BB_Smooth[i] > BBDn[i])
           Fleche_up_1[i] = BBDn[i]-15;   else Fleche_up_1[i] = 0; 
       }
       for(i=limit; i>=0; i--)
       {
          trend[i] = 0;
          if (Fleche_up_1[i]   != 0 && Fleche_up_1[i+1]   == 0) trend[i] =  1;
          if (Fleche_down_1[i] != 0 && Fleche_down_1[i+1] == 0) trend[i] = -1;
          
          //
          //
          //
          
          if (arrowsVisible)
          {
             string lookFor = arrowsIdentifier+":"+(string)Time[i]; ObjectDelete(lookFor);            
             if (i<(Bars-1) && trend[i] != trend[i+1])
             {
                if (trend[i] == 1) drawArrow(i,arrowsUpColor,arrowsUpCode,arrowsUpSize,false);
                if (trend[i] ==-1) drawArrow(i,arrowsDnColor,arrowsDnCode,arrowsDnSize, true);
             }
          }
        }    
    }
    if (alertsOn)
    {
      int whichBar = (alertsOnCurrent) ? 0 : 1;
      if (Fleche_down_1[whichBar+1] == 0 && Fleche_down_1[whichBar] != 0) doAlert(whichBar,"down");
      if (Fleche_up_1[whichBar+1]   == 0 && Fleche_up_1[whichBar]   != 0) doAlert(whichBar,"up");
    }         
   return(0);
  }

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------

void drawArrow(int i,color theColor,int theCode, int theSize, bool up)
{
   string name = arrowsIdentifier+":"+(string)Time[i];
   double gap  = iATR(NULL,0,20,i);   
   
      //
      //
      //

      datetime atime = Time[i]; //if (arrowsOnNewest) atime += _Period*60-1;      
      ObjectCreate(name,OBJ_ARROW,0,atime,0);
         ObjectSet(name,OBJPROP_ARROWCODE,theCode);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         ObjectSet(name,OBJPROP_WIDTH,theSize);
         if (up)
               ObjectSet(name,OBJPROP_PRICE1,High[i] + arrowsUpperGap * gap);
         else  ObjectSet(name,OBJPROP_PRICE1,Low[i]  - arrowsLowerGap * gap);
}

//
//
//
//
//

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 = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" Bands "+doWhat;
             if (alertsMessage) Alert(message);
             if (alertsNotify)  SendNotification(message);
             if (alertsEmail)   SendMail(_Symbol+" Bands ",message);
             if (alertsSound)   PlaySound(soundFile);
      }
}

//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,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("");
}




