//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-station.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  DarkGray
#property  indicator_width1  2
#property  indicator_width3  2
#property  indicator_width5  2
#property  indicator_minimum -55
#property  indicator_maximum  55

//
//
//
//
//

extern ENUM_TIMEFRAMES    TimeFrame          = PERIOD_CURRENT;
extern double             RsiPeriod          = 14;
extern ENUM_APPLIED_PRICE RsiPrice           = PRICE_CLOSE;
extern double             RsiLevelUp         = 80;
extern double             RsiLevelDown       = 20;
extern int                MaPeriod           =  5;
extern ENUM_MA_METHOD     MaMethod           =  0;
extern bool               alertsOn           = false;
extern bool               alertsOnCurrent    = true;
extern bool               alertsMessage      = true;
extern bool               alertsSound        = false;
extern bool               alertsEmail        = false;
extern int                BarsPerSymbol      = 100;
extern string             Symbols            = "EURUSD;GBPUSD;USDCHF";
extern string             UniqueID           = "Multi pair rapid rsi";
extern string             _                  = "separator colors";
extern color              textColor          = Black;
extern color              backColor          = DarkGray;
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[];
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);
      SetLevelValue(0,0);
      SetLevelValue(1,RsiLevelUp  -50);
      SetLevelValue(2,RsiLevelDown-50);
      calculateValue    = (TimeFrame == -98); 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      = MathMax(TimeFrame,_Period);
   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 (work[i+shift]>RsiLevelUp-50.0)
         if (slope[i+shift]==1)
               histouu[i+shift] = work[i+shift];
         else  histoud[i+shift] = work[i+shift];
      if (work[i+shift]<RsiLevelDown-50.0)
         if (slope[i+shift]==-1)
               histodd[i+shift] = work[i+shift];
         else  histodu[i+shift] = work[i+shift];
   }
   createLabel(symbol,element,shift+limit+separatorWidth-2,max,isSignalCrossing(shift));
   
   //
   //
   //
   //
   //
   
   shift += (limit+separatorWidth-1);
}

//
//
//
//
//

int isSignalCrossing(int shift)
{
   if (work[shift]>RsiLevelUp  -50 && work[shift+1]<=RsiLevelUp  -50) return( 1);
   if (work[shift]<RsiLevelDown-50 && work[shift+1]>=RsiLevelDown-50) return(-1);
                                                                      return( 0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//

void calculateIndicator()
{
   int counted_bars=IndicatorCounted();
      if(counted_bars<0) return;
      if(counted_bars>0) counted_bars--;
           int limit=MathMax(Bars-counted_bars,Bars-1);
           
   //
   //
   //
   //
   //

   for(int i=limit; i>=0; i--)
   {
      double up   =0;
      double down =0;
      double diff =0;
      for(int k=0;  k<RsiPeriod; k++)
      {
         diff = iMA(NULL,0,MaPeriod,0,MaMethod,RsiPrice,i+k)-iMA(NULL,0,MaPeriod,0,MaMethod,RsiPrice,i+k+1);
         if(diff>0)
               up   += diff;
         else  down -= diff;
      }
      if(up + down == 0)
            value[i] = 0;
      else  value[i] = 100 * up / (up + down)-50;
   
      trend[i] = 0;
      slope[i] = slope[i+1];
         if (value[i]>RsiLevelUp-50)   trend[i] =  1;
         if (value[i]<RsiLevelDown-50) trend[i] = -1;
         if (value[i]>value[i+1])      slope[i] =  1;
         if (value[i]<value[i+1])      slope[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,-98,RsiPeriod,RsiPrice,RsiLevelUp,RsiLevelDown,MaPeriod,MaMethod,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,4,y);
         slope[i+shift] = iCustom(symbol,TimeFrame,indicatorFileName,-98,RsiPeriod,RsiPrice,RsiLevelUp,RsiLevelDown,MaPeriod,MaMethod,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,6,y);
         maxValues[element] =  50;
         maxValue           =  50;
         minValue           = -50;
   }            

   //
   //
   //
   //
   //

   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," rapid RSI crossed level "+DoubleToStr(RsiLevelUp  ,2)+" up");
            if (trend[whichBar] == -1) doAlert(time1,mess1," rapid RSI crossed level "+DoubleToStr(RsiLevelDown,2)+" 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()+" MFI",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 tchar = StringGetChar(s, length);
         if((tchar > 96 && tchar < 123) || (tchar > 223 && tchar < 256))
                     s = StringSetChar(s, length, tchar - 32);
         else if(tchar > -33 && tchar < 0)
                     s = StringSetChar(s, length, tchar + 224);
   }
   return(s);
}