//+--------------------------------------------------------------------------+
//|                                                3 MA Cross with alert.mq4 |
//|                                                                   mladen |
//+--------------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_chart_window
#property indicator_buffers 9
#property indicator_color1  clrBlue
#property indicator_color2  clrRed
#property indicator_color3  clrDeepSkyBlue
#property indicator_color4  clrOrange
#property indicator_color5  clrBlue
#property indicator_color6  clrRed
#property indicator_color7  clrBlue
#property indicator_color8  clrLimeGreen
#property indicator_color9  clrRed
#property indicator_width5  2
#property indicator_width6  2
#property indicator_width7  2
#property indicator_width8  2
#property indicator_width9  2
#property strict

//
//
//
//
//

extern ENUM_TIMEFRAMES TimeFrame        = PERIOD_CURRENT;   // Time frame
input int              FasterMA         = 10;               // Fast ma period 
input int              FasterShift      = 0;                // Fast ma shift
input ENUM_MA_METHOD   FasterMode       = 1;                // Fast ma mode
input ENUM_APPLIED_PRICE FasterPrice    = PRICE_CLOSE;      // Fast ma price
input int              MediumMA         = 20;               // Medium ma period
input int              MediumShift      = 0;                // Medium ma shift
input ENUM_MA_METHOD   MediumMode       = 1;                // Medium ma mode
input ENUM_APPLIED_PRICE MediumPrice    = PRICE_CLOSE;      // Medium ma price
input int              SlowerMA         = 40;               // Slow ma period      
input int              SlowerShift      = 0;                // Slow ma shift
input ENUM_MA_METHOD   SlowerMode       = 1;                // Slow ma mode
input ENUM_APPLIED_PRICE SlowerPrice    = PRICE_CLOSE;      // Slow ma price
input bool             showMAs          = true;             // Show ma lines on/off?
input bool             showMSarrows     = false;             // Show medium/slow ma cross arrows on/off?
input bool             showFSarrows     = false;             // Show fast/slow ma cross arrows on/off? 
input bool             showFMarrows     = false;             // Show fast/medium ma cross arrows on/off?
input bool             alertsOn         = true;             // Turn alerts on/off?
input bool             alertsOnFMcross  = false;            // Alerts on fast/medium ma cross on/off?
input bool             alertsOnFScross  = false;            // Alerts on fast/slow ma cross on/off?
input bool             alertsOnMScross  = true;             // Alerts on medium/slow ma cross on/off?
input bool             alertsOnCurrent  = false;            // Alerts on open bar on/off?
input bool             alertsMessage    = true;             // Alerts message on/off?
input bool             alertsSound      = false;            // Alerts sound on/off?
input bool             alertsEmail      = false;            // Alerts email on/off?
input bool             alertsNotify     = false;            // Alerts notification on/off?
input bool             ArrowsOnFirstBar = false;             // Arrow on first mtf bar on/off?
input double           arrowsFMGap      = 0.50;             // Arrow on fast/medium ma cross gap
input double           arrowsFSGap      = 0.75;             // Arrow on fast/slow ma cross gap
input double           arrowsMSGap      = 1.00;             // Arrow on medium/slow ma cross gap
input int              arrowUpCode_ms   = 159;              // Up arrow on medium/slow cross code
input int              arrowDnCode_ms   = 159;              // Down arrow on medium/slow cross code 
input int              arrowUpCode_fs   = 233;              // Up arrow on fast/slow cross code
input int              arrowDnCode_fs   = 234;              // Down arrow on fast/slow cross code
input int              arrowUpCode_fm   = 116;              // Up arrow on fast/medium cross code
input int              arrowDnCode_fm   = 116;              // Down arrow on fast/medium cross code 
input bool             Interpolate      = true;             // Interpolate in mtf mode on/off?

double CrossfmUp[],CrossfmDn[],CrossfsUp[],CrossfsDn[],CrossmsUp[],CrossmsDn[],ma1[],ma2[],ma3[],trendfm[],trendfs[],trendms[],count[];
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,FasterMA,0,FasterMode,FasterPrice,MediumMA,0,MediumMode,MediumPrice,SlowerMA,0,SlowerMode,SlowerPrice,showMAs,showMSarrows,showFSarrows,showFMarrows,alertsOn,alertsOnFMcross,alertsOnFScross,alertsOnMScross,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsNotify,ArrowsOnFirstBar,arrowsFMGap,arrowsFSGap,arrowsMSGap,_buff,_ind)

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int OnInit()
{
   IndicatorBuffers(13);
   SetIndexBuffer(0,CrossmsUp); SetIndexStyle(0,showMSarrows  ? DRAW_ARROW :  DRAW_NONE); SetIndexArrow(0, arrowUpCode_ms);
   SetIndexBuffer(1,CrossmsDn); SetIndexStyle(1,showMSarrows  ? DRAW_ARROW :  DRAW_NONE); SetIndexArrow(1, arrowDnCode_ms);
   SetIndexBuffer(2,CrossfsUp); SetIndexStyle(2,showFSarrows  ? DRAW_ARROW :  DRAW_NONE); SetIndexArrow(2, arrowUpCode_fs);
   SetIndexBuffer(3,CrossfsDn); SetIndexStyle(3,showFSarrows  ? DRAW_ARROW :  DRAW_NONE); SetIndexArrow(3, arrowDnCode_fs);
   SetIndexBuffer(4,CrossfmUp); SetIndexStyle(4,showFMarrows  ? DRAW_ARROW :  DRAW_NONE); SetIndexArrow(4, arrowUpCode_fm);
   SetIndexBuffer(5,CrossfmDn); SetIndexStyle(5,showFMarrows  ? DRAW_ARROW :  DRAW_NONE); SetIndexArrow(5, arrowDnCode_fm);
   SetIndexBuffer(6,ma1);       SetIndexStyle(6,showMAs       ? DRAW_LINE  :  DRAW_NONE);
   SetIndexBuffer(7,ma2);       SetIndexStyle(7,showMAs       ? DRAW_LINE  :  DRAW_NONE);
   SetIndexBuffer(8,ma3);       SetIndexStyle(8,showMAs       ? DRAW_LINE  :  DRAW_NONE);
   SetIndexBuffer(9 ,trendfm); 
   SetIndexBuffer(10,trendfs); 
   SetIndexBuffer(11,trendms); 
   SetIndexBuffer(12,count);
   
   //
   //
   //
   //
   //
   
   indicatorFileName = WindowExpertName();
   TimeFrame         = fmax(TimeFrame,_Period);
   SetIndexShift(6,FasterShift*TimeFrame/_Period);
   SetIndexShift(7,MediumShift*TimeFrame/_Period);
   SetIndexShift(8,SlowerShift*TimeFrame/_Period);
   
   IndicatorShortName(timeFrameToString(TimeFrame)+" 3 ma cross ");     
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) {     }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//
 
int start()
{ 
   int i,counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = fmin(Bars-counted_bars,Bars-1); count[0] = limit;
         if (FasterShift < 0) limit = fmax(limit,-FasterShift);
         if (MediumShift < 0) limit = fmax(limit,-MediumShift);
         if (SlowerShift < 0) limit = fmax(limit,-SlowerShift);
         if (TimeFrame != _Period)
         {
            limit = (int)fmax(limit,fmin(Bars-1,_mtfCall(12,0)*TimeFrame/_Period));
            for (i=limit;i>=0 && !_StopFlag; i--)
            {
                int y = iBarShift(NULL,TimeFrame,Time[i]);
                int x = y;
                if (ArrowsOnFirstBar)
                      {  if (i<Bars-1) x = iBarShift(NULL,TimeFrame,Time[i+1]);               }
                else  {  if (i>0)      x = iBarShift(NULL,TimeFrame,Time[i-1]); else x = -1;  }
                     ma1[i]  = _mtfCall(6,y);
                     ma2[i]  = _mtfCall(7,y);
                     ma3[i]  = _mtfCall(8,y);
                     CrossfmUp[i] = EMPTY_VALUE;
                     CrossfmDn[i] = EMPTY_VALUE;
                     CrossfsUp[i] = EMPTY_VALUE;
                     CrossfsDn[i] = EMPTY_VALUE;
                     CrossmsUp[i] = EMPTY_VALUE;
                     CrossmsDn[i] = EMPTY_VALUE;
                     trendfm[i] = _mtfCall(9, y);
                     trendfs[i] = _mtfCall(10,y);
                     trendms[i] = _mtfCall(11,y);
                     if (x!=y)
                     {
                       CrossmsUp[i] = _mtfCall(0,y);
                       CrossmsDn[i] = _mtfCall(1,y);
                       CrossfsUp[i] = _mtfCall(2,y);
                       CrossfsDn[i] = _mtfCall(3,y);
                       CrossfmUp[i] = _mtfCall(4,y);
                       CrossfmDn[i] = _mtfCall(5,y);
                     }
                     
                     if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
                  
                     //
                     //
                     //
                     //
                     //
                  
                     if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
                        #define _interpolate(buff) buff[i+j] = buff[i]+(buff[i+n]-buff[i])*j/n
                        int n,j; datetime time = iTime(NULL,TimeFrame,y);
                           for(n = 1; (i+n)<Bars && Time[i+n] >= time; n++) continue;	
                           for(j = 1; j<n && (i+n)<Bars && (i+j)<Bars; j++) 
                           {
                              _interpolate(ma1);
                              _interpolate(ma2);
                              _interpolate(ma3);
                          }                           
            }
     return(0);
     }
     
     //
     //
     //
     //
     //
     
     for(i = limit; i >=0; i--)
     {    
         CrossfmUp[i] = EMPTY_VALUE;
         CrossfmDn[i] = EMPTY_VALUE;
         CrossfsUp[i] = EMPTY_VALUE;
         CrossfsDn[i] = EMPTY_VALUE;
         CrossmsUp[i] = EMPTY_VALUE;
         CrossmsDn[i] = EMPTY_VALUE;
         ma1[i]       = iMA(NULL, 0, FasterMA, FasterShift, FasterMode, FasterPrice, i);
         ma2[i]       = iMA(NULL, 0, MediumMA, MediumShift, MediumMode, MediumPrice, i);
         ma3[i]       = iMA(NULL, 0, SlowerMA, SlowerShift, SlowerMode, SlowerPrice, i);
         trendfm[i] = (i<Bars-1) ? (ma1[i]>ma2[i]) ? 1 : (ma1[i]<ma2[i]) ? -1 : trendfm[i+1] : 0; 
         trendfs[i] = (i<Bars-1) ? (ma1[i]>ma3[i]) ? 1 : (ma1[i]<ma3[i]) ? -1 : trendfs[i+1] : 0; 
         trendms[i] = (i<Bars-1) ? (ma2[i]>ma3[i]) ? 1 : (ma2[i]<ma3[i]) ? -1 : trendms[i+1] : 0; 
         
      //
      //
      //
      //
      //
         
      double range = iATR(NULL,0,15,i);        
         if (i<Bars-1 && trendfm[i]!=trendfm[i+1]) 
            if (trendfm[i] == 1)
                  CrossfmUp[i] = fmin(ma1[i],ma2[i])-range*arrowsFMGap;
            else  CrossfmDn[i] = fmax(ma1[i],ma2[i])+range*arrowsFMGap;
         if (i<Bars-1 && trendfs[i]!=trendfs[i+1]) 
            if (trendfs[i] == 1)
                  CrossfsUp[i] = fmin(ma1[i],ma3[i])-range*arrowsFSGap;
            else  CrossfsDn[i] = fmax(ma1[i],ma3[i])+range*arrowsFSGap;
         if (i<Bars-1 && trendms[i]!=trendms[i+1]) 
            if (trendms[i] == 1)
                  CrossmsUp[i] = fmin(ma2[i],ma3[i])-range*arrowsMSGap;
            else  CrossmsDn[i] = fmax(ma2[i],ma3[i])+range*arrowsMSGap;
   }   
   manageAlerts();
   return(0);
 }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//

void manageAlerts()
{
   if (alertsOn)
   {
      int whichBar=1; if (alertsOnCurrent) whichBar = 0;
   
      //
      //
      //
      //
      //
         
         static string   mess1 = "";
         static datetime time1 = 0;
            if (trendfm[whichBar]!=trendfm[whichBar+1] && alertsOnFMcross) 
            if (trendfm[whichBar] == 1)
                  doAlert(mess1,time1,"Fast MA crossed Medium MA UP");
            else  doAlert(mess1,time1,"Fast MA crossed Medium MA DOWN");
         static string   mess2 = "";
         static datetime time2 = 0;
            if (trendfs[whichBar]!=trendfs[whichBar+1] && alertsOnFScross) 
            if (trendfs[whichBar] == 1)
                  doAlert(mess2,time2,"Fast MA crossed Slow MA UP");
            else  doAlert(mess2,time2,"Fast MA crossed Slow MA DOWN");
         static string   mess3 = "";
         static datetime time3 = 0;
            if (trendms[whichBar]!=trendms[whichBar+1] && alertsOnMScross) 
            if (trendms[whichBar] == 1)
                  doAlert(mess3,time3,"Medium MA crossed Slow MA UP");
            else  doAlert(mess3,time3,"Medium MA crossed Slow MA DOWN");
   }               
}
 
//
//
//
//
//
//
 
void doAlert(string& previousAlert, datetime& previousTime, string doWhat)
{
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[0]) {
          previousAlert  = doWhat;
          previousTime   = Time[0];

          //
          //
          //
          //
          //

           message =  StringConcatenate(Symbol()," ",timeFrameToString(TimeFrame)," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," 3 MA line crossing ",doWhat);
             if (alertsMessage) Alert(message);
             if (alertsNotify)  SendNotification(message);
             if (alertsEmail)   SendMail(StringConcatenate(Symbol(),"3 MA line crossing"),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};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}

