//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-tsd.com"
//+------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 5
#property  indicator_color1  LimeGreen
#property  indicator_color2  LimeGreen
#property  indicator_color3  PaleVioletRed
#property  indicator_color4  PaleVioletRed
#property  indicator_color5  DimGray
#property  indicator_width1  2
#property  indicator_width4  2
#property  indicator_width5  2

//
//
//
//
//

extern string TimeFrame            = "Current time frame";
extern int    BandPassPeriod       = 50;
extern int    BandPassPrice        = PRICE_MEDIAN;
extern double Delta                = 0.1;
extern bool   alertsOn             = false;
extern bool   alertsOnCurrent      = true;
extern bool   alertsMessage        = true;
extern bool   alertsSound          = false;
extern bool   alertsEmail          = false;
extern int    BarsPerSymbol        = 70;
extern string Symbols              = "EURUSD;GBPUSD;USDCHF";
extern string UniqueID             = "Multi pair BPF";
extern string _                    = "separator colors";
extern color  textColor            = Black;
extern color  backColor            = LightGray;
extern color  zeroCrossUpColor     = LimeGreen;
extern color  zeroCrossDownColor   = HotPink;
extern int    separatorWidth       = 6;

//
//
//
//
//

double histouu[];
double histoud[];
double histodd[];
double histodu[];
double value[];
double work[];
double slope[];
double trend[];

//
//
//
//
//

int      window;  
string   aPairs[];
string   shortName;
double   minValue;
double   maxValue;
double   maxValues[];
int      timeFrame;
bool     calculateValue;
string   indicatorFileName;


//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(8);
   SetIndexBuffer(0,histouu); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,histoud); SetIndexStyle(1,DRAW_HISTOGRAM);
   SetIndexBuffer(2,histodd); SetIndexStyle(2,DRAW_HISTOGRAM);
   SetIndexBuffer(3,histodu); SetIndexStyle(3,DRAW_HISTOGRAM);
   SetIndexBuffer(4,value);
   SetIndexBuffer(5,work);
   SetIndexBuffer(6,slope);
   SetIndexBuffer(7,trend);
      calculateValue    = (TimeFrame == "calculateValue"); if (calculateValue) return(0);
      indicatorFileName = WindowExpertName();

      //
      //
      //
      //
      //

      Symbols = StringTrimLeft(StringTrimRight(Symbols));
      if (StringSubstr(Symbols,StringLen(Symbols),1) != ";")
                       Symbols = StringConcatenate(Symbols,";");

         //
         //
         //
         //
         //                                   
            
         int s =  0;
         int i =  StringFind(Symbols,";",s);
         while (i > 0)
         {
            string current = StringSubstr(Symbols,s,i-s);
            ArrayResize(aPairs,ArraySize(aPairs)+1);
                        aPairs[ArraySize(aPairs)-1] = current;
                        if (current == Symbol())
                        {
                           string temp      = aPairs[0];
                                  aPairs[0] = current;
                                  aPairs[ArraySize(aPairs)-1] = temp;
                        }                                       
            s = i + 1;
            i = StringFind(Symbols,";",s);
         }
         ArrayResize(maxValues,ArraySize(aPairs));

      //
      //
      //
      //
      //
 
      separatorWidth = MathMax(separatorWidth,4);
      shortName      = UniqueID;
      timeFrame      = stringToTimeFrame(TimeFrame);
   IndicatorShortName(shortName);
   return(0);
}

//
//
//
//
//

int deinit()
{
   for (int i = 0; i < ArraySize(aPairs); i++)
   { 
         ObjectDelete(shortName+i);
         ObjectDelete(shortName+i+i);
   }         
   return(0);
}


//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int start()
{
   if (calculateValue) { calculateIndicator(); return(0); }
   int    i,k,limit = ArraySize(aPairs);
   double max;
   
   //
   //
   //
   //
   //

   window = WindowFind(shortName);  
   ArrayInitialize(maxValues,0);
         minValue = 0;
         maxValue = 0;
                for(i=0,k=0; i<limit; i++) calculateValues(aPairs[i],BarsPerSymbol,k,i);
                for(i=0;     i<limit; i++) if (max < maxValues[i]) max = maxValues[i];
                for(i=0,k=0; i<limit; i++) plotGraph(aPairs[i],BarsPerSymbol,k,i,max);
   for (i=0;i<indicator_buffers;i++) SetIndexDrawBegin(i,Bars-k);
   return(0);
}


//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

void plotGraph(string symbol,int limit, int& shift,int element, double max)
{
   for(int i=limit; i>=0; i--)
   {   
      value[i+shift]   = work[i+shift];
      histouu[i+shift] = EMPTY_VALUE;
      histoud[i+shift] = EMPTY_VALUE;
      histodd[i+shift] = EMPTY_VALUE;
      histodu[i+shift] = EMPTY_VALUE;
         if (trend[i+shift]== 1 && slope[i+shift]== 1) histouu[i+shift] = value[i+shift];
         if (trend[i+shift]== 1 && slope[i+shift]==-1) histoud[i+shift] = value[i+shift];
         if (trend[i+shift]==-1 && slope[i+shift]== 1) histodd[i+shift] = value[i+shift];
         if (trend[i+shift]==-1 && slope[i+shift]==-1) histodu[i+shift] = value[i+shift];
   }
   createLabel(symbol,element,shift+limit+separatorWidth-2,max,isSignalCrossing(shift));
   
   //
   //
   //
   //
   //
   
   shift += (limit+separatorWidth-1);
}

//
//
//
//
//

int isSignalCrossing(int shift)
{
   if (trend[shift]!=trend[shift+1])
         return(trend[shift]);
   else  return(0);    
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//

#define Pi 3.141592653589793238462643383279
void calculateIndicator()
{
   int counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
           int limit=MathMin(Bars-counted_bars,Bars-1);
           
   //
   //
   //
   //
   //

   double beta  = MathCos(2.0*Pi/BandPassPeriod);
   double gamma = 1.0 / MathCos(4.0*Pi*Delta/BandPassPeriod);
   double alpha = gamma -MathSqrt(gamma*gamma-1.0);
   for(int i=limit; i>=0; i--)
   {
      work[i]  = iMA(NULL,0,1,0,MODE_SMA,BandPassPrice,i);
      value[i] = 0.5*(1.0-alpha)*(work[i]-work[i+2])+beta*(1.0+alpha)*value[i+1]-alpha*value[i+2];
      trend[i] = trend[i+1];
         if (value[i]>value[i+1]) slope[i] =  1;
         if (value[i]<value[i+1]) slope[i] = -1;
         if (value[i]>0)          trend[i] =  1;
         if (value[i]<0)          trend[i] = -1;
   }
   manageAlerts();
}

//
//
//
//
//

void calculateValues(string symbol,int limit,int& shift,int element)
{
   for(int i=0; i<limit; i++)
   {
      int y=iBarShift(NULL,timeFrame,Time[i]);
         work[i+shift]  = iCustom(symbol,timeFrame,indicatorFileName,"calculateValue",BandPassPeriod,BandPassPrice,Delta,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,4,y);
         slope[i+shift] = iCustom(symbol,timeFrame,indicatorFileName,"calculateValue",BandPassPeriod,BandPassPrice,Delta,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,6,y);
         trend[i+shift] = iCustom(symbol,timeFrame,indicatorFileName,"calculateValue",BandPassPeriod,BandPassPrice,Delta,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,7,y);
          
      maxValues[element] = MathMax(MathAbs(work[i+shift]),maxValues[element]);
      maxValue           = MathMax(work[i+shift],maxValue);
      minValue           = MathMin(work[i+shift],minValue);
   }            

   //
   //
   //
   //
   //

   for (i=0;i<separatorWidth;i++) {
         histouu[shift+limit+i] = EMPTY_VALUE;
         histoud[shift+limit+i] = EMPTY_VALUE;
         histodd[shift+limit+i] = EMPTY_VALUE;
         histodu[shift+limit+i] = EMPTY_VALUE;
         value[shift+limit+i]   = EMPTY_VALUE;
         work[shift+limit+i]    = EMPTY_VALUE;
      }         
   shift += (limit+separatorWidth-1);
   return;
}



//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//

void createLabel(string symbol,int element, int shift, double max, int signalCrossing)
{
   string name = shortName+element;
   double price1 = maxValue;
   double price2 = minValue;
   
   //
   //
   //
   //
   //
   
   if (ObjectFind(name) == -1)
      {
         ObjectCreate(name,OBJ_TEXT,window,0,0);
            ObjectSet(name,OBJPROP_ANGLE,90);
            ObjectSetText(name,symbol,10,"Arial bold");
      }
      ObjectSet(name,OBJPROP_TIME1 ,Time[shift]);
      ObjectSet(name,OBJPROP_PRICE1,(price1+price2)/2);
      ObjectSet(name,OBJPROP_COLOR,textColor);

   //
   //
   //
   //
   //

   name = shortName+element+element;
   if (ObjectFind(name) == -1)
      {
         ObjectCreate(name,OBJ_RECTANGLE,window,0,0,0,0);
            ObjectSet(name,OBJPROP_COLOR,backColor);
      }         
      ObjectSet(name,OBJPROP_TIME1,Time[shift]);
      ObjectSet(name,OBJPROP_PRICE1,price1);
      ObjectSet(name,OBJPROP_TIME2,Time[shift-(separatorWidth-2)]);
      ObjectSet(name,OBJPROP_PRICE2,price2);
      if (signalCrossing!=0)
           if (signalCrossing>0)
                  ObjectSet(name,OBJPROP_COLOR,zeroCrossUpColor);
           else   ObjectSet(name,OBJPROP_COLOR,zeroCrossDownColor);
      else ObjectSet(name,OBJPROP_COLOR,backColor);
}

//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

void manageAlerts()
{
   if (alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1;
      
      //
      //
      //
      //
      //
            
      if (trend[whichBar]!= trend[whichBar+1])
      {
         static datetime time1 = 0;
         static string   mess1 = "";
            if (trend[whichBar] ==  1) doAlert(time1,mess1," BPF crossed zero line up");
            if (trend[whichBar] == -1) doAlert(time1,mess1," BPF crossed zero line down");
      }
   }
}

//
//
//
//
//

void doAlert(datetime& previousTime, string& previousAlert, string doWhat)
{
   string message;
   
   if (previousAlert != doWhat || previousTime != Time[0]) {
       previousAlert  = doWhat;
       previousTime   = Time[0];

       //
       //
       //
       //
       //

       message =  timeFrameToString(Period())+" "+Symbol()+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+doWhat;
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(Symbol()+" Band pass filter",message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

//
//
//
//
//

int stringToTimeFrame(string tfs)
{
   tfs = StringUpperCase(tfs);
   for (int i=ArraySize(iTfTable)-1; i>=0; i--)
         if (tfs==sTfTable[i] || tfs==""+iTfTable[i]) return(MathMax(iTfTable[i],Period()));
                                                      return(Period());
}
string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

//
//
//
//
//

string StringUpperCase(string str)
{
   string   s = str;

   for (int length=StringLen(str)-1; length>=0; length--)
   {
      int char = StringGetChar(s, length);
         if((char > 96 && char < 123) || (char > 223 && char < 256))
                     s = StringSetChar(s, length, char - 32);
         else if(char > -33 && char < 0)
                     s = StringSetChar(s, length, char + 224);
   }
   return(s);
}