//+--------------------------------------------------------------------------+
//|                        3 ma - cross histo (mtf + alerts + arrows) v2.mq4 |
//+--------------------------------------------------------------------------+
#property copyright "www,forex-station.com"
#property link      "www,forex-station.com"

#property indicator_separate_window
#property indicator_buffers 2
#property strict

//
//
//

enum enCrossType
{
   cross_fm,  // Fast/Medium Ma Cross
   cross_fs,  // Fast/Slow Ma Cross
   cross_ms,  // Medium/Slow Ma Cross
   cross_fms  // Fast/Medium/Slow Ma Cross
};

enum enArrowsUp
{
   arr_00 = 108,  // Ball
   arr_01 = 159,  // Dot
   arr_02 = 217,  // Fractal up
   arr_03 = 241,  // Hollow up
   arr_04 = 246,  // Hollow right up
   arr_05 = 225,  // Thin up
   arr_06 = 228,  // Thin right up
   arr_07 = 233,  // Heavy up
   arr_08 = 236,  // Heavy right up
   arr_09 = 200,  // Curled up
   arr_10 = 221,  // Up in a circle
   arr_11 = 251,  // X
   arr_12 = 253,  // X in a box
   arr_13 = 171,  // Five pointed star
   arr_14 = 172,  // Six pointed star
   arr_15 = 173,  // Eight pointed star
   arr_16 = 174   // Twelve pointed star
};

enum enArrowsDn
{
   ard_00 = 108,  // Ball
   ard_01 = 159,  // Dot
   ard_02 = 218,  // Fractal down
   ard_03 = 242,  // Hollow down
   ard_04 = 248,  // Hollow right down
   ard_05 = 226,  // Thin down
   ard_06 = 230,  // Thin right down
   ard_07 = 234,  // Heavy down
   ard_08 = 238,  // Heavy right down
   ard_09 = 202,  // Curled down
   ard_10 = 222,  // Down in a circle
   ard_11 = 251,  // X
   ard_12 = 253,  // X in a box
   ard_13 = 171,  // Five pointed star
   ard_14 = 172,  // Six pointed star
   ard_15 = 173,  // Eight pointed star
   ard_16 = 174   // Twelve pointed star
};

//
//
//

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       = MODE_EMA;          // 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       = MODE_EMA;;         // 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       = MODE_EMA;;         // Slow ma mode
input ENUM_APPLIED_PRICE SlowerPrice      = PRICE_CLOSE;       // Slow ma price
//+-----------------------------------------------------------------------------------------------------------+
input enCrossType        MaCrossType      = cross_fm;          // Ma Cross Type
//+-----------------------------------------------------------------------------------------------------------+
input int                HistoWidth       = 3;                 // Histogram bars width
input color              UpHistoColor     = clrDodgerBlue;     // Bullish color
input color              DnHistoColor     = clrRed;            // Bearish color
//+-----------------------------------------------------------------------------------------------------------+
input bool               alertsOn         = false;             // Alerts on true/false?
input bool               alertsOnCurrent  = false;             // Alerts open bar true/false?
input bool               alertsMessage    = true;              // Alerts message true/false?
input bool               alertsSound      = true;              // Alerts sound true/false?
input bool               alertsNotify     = false;             // Alerts notification true/false?
input bool               alertsEmail      = false;             // Alerts email true/false?
input string             soundfile        = "alert2.wav";      // Sound file to use
//+-----------------------------------------------------------------------------------------------------------+
input bool               arrowsVisible    = false;             // Arrows visible true/false?
input bool               arrowsOnNewest   = false;             // Arrows drawn on newest bar of higher time frame bar true/false?
input string             arrowsIdentifier = "ma Arrows2";      // Unique ID for arrows
input double             arrowsUpperGap   = 1.0;               // Upper arrow gap
input double             arrowsLowerGap   = 1.0;               // Lower arrow gap
input color              arrowsUpColor    = clrBlue;           // Up arrow color
input color              arrowsDnColor    = clrCrimson;        // Down arrow color
input enArrowsUp         arrowsUpCode     = arr_07;            // Up arrow code
input enArrowsDn         arrowsDnCode     = ard_07;            // Down arrow code
input int                arrowsUpSize     = 2;                 // Up arrow size
input int                arrowsDnSize     = 2;                 // Down arrow size

double UpH[],DnH[],ma1[],ma2[],ma3[],valc[],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,MaCrossType,HistoWidth,UpHistoColor,DnHistoColor,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsNotify,alertsEmail,soundfile,arrowsVisible,arrowsOnNewest,arrowsIdentifier,arrowsUpperGap,arrowsLowerGap,arrowsUpColor,arrowsDnColor,arrowsUpCode,arrowsDnCode,arrowsUpSize,arrowsDnSize,_buff,_ind)

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

int OnInit()
{
   IndicatorBuffers(7);   
   SetIndexBuffer(0,UpH,INDICATOR_DATA); SetIndexStyle(0,DRAW_HISTOGRAM,EMPTY,HistoWidth,UpHistoColor);
   SetIndexBuffer(1,DnH,INDICATOR_DATA); SetIndexStyle(1,DRAW_HISTOGRAM,EMPTY,HistoWidth,DnHistoColor);
   SetIndexBuffer(2,ma1);
   SetIndexBuffer(3,ma2);
   SetIndexBuffer(4,ma3); 
   SetIndexBuffer(5,valc);
   SetIndexBuffer(6,count);
   
   IndicatorSetDouble(INDICATOR_MINIMUM,0);
   IndicatorSetDouble(INDICATOR_MAXIMUM,1);
   
   indicatorFileName = WindowExpertName();
   TimeFrame         = MathMax(TimeFrame,_Period);
   SetIndexShift(2,FasterShift*TimeFrame/_Period);
   SetIndexShift(3,MediumShift*TimeFrame/_Period);
   SetIndexShift(4,SlowerShift*TimeFrame/_Period);
     
   IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(TimeFrame)+"   3ma cross");
return(INIT_SUCCEEDED);
}  
void OnDeinit(const int reason)  {  ObjectsDeleteAll(0,arrowsIdentifier+":"); }

//------------------------------------------------------------------
//
//------------------------------------------------------------------

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   int i,limit=fmin(rates_total-prev_calculated+1,rates_total-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(rates_total-1,_mtfCall(6,0)*TimeFrame/_Period));
         for (i=limit;i>=0 && !_StopFlag; i--)
         {
                  int y = iBarShift(NULL,TimeFrame,time[i]);
                     UpH[i] = _mtfCall(0,y);
                     DnH[i] = _mtfCall(1,y);
         }  
   return(rates_total);
   }            
   
   //
   //
   //
           
   for (i=limit;i>=0 && !_StopFlag; i--)
   {
      ma1[i]  = iMA(_Symbol,_Period,FasterMA,FasterShift,FasterMode,FasterPrice,i);
      ma2[i]  = iMA(_Symbol,_Period,MediumMA,MediumShift,MediumMode,MediumPrice,i);
      ma3[i]  = iMA(_Symbol,_Period,SlowerMA,SlowerShift,SlowerMode,SlowerPrice,i);

      if(MaCrossType == cross_fm)
      {
         valc[i] = (i<rates_total-1) ? (ma1[i]>ma2[i]) ? 1 : (ma1[i]<ma2[i]) ? -1 : valc[i+1] : 0;
      }
      else if(MaCrossType == cross_fs)
      {
         valc[i] = (i<rates_total-1) ? (ma1[i]>ma3[i]) ? 1 : (ma1[i]<ma3[i]) ? -1 : valc[i+1] : 0;
      }
      else if(MaCrossType == cross_ms)
      {
         valc[i] = (i<rates_total-1) ? (ma2[i]>ma3[i]) ? 1 : (ma2[i]<ma3[i]) ? -1 : valc[i+1] : 0;
      }
      else // if(MaCrossType == cross_fms)
      {
         valc[i] = (i<rates_total-1) ? (ma1[i]>ma2[i] && ma2[i]>ma3[i]) ? 1 : (ma1[i]<ma2[i] && ma2[i]<ma3[i]) ? -1 : valc[i+1] : 0;
      }

      UpH[i]  = (valc[i] == 1) ? 1 : EMPTY_VALUE;
      DnH[i]  = (valc[i] ==-1) ? 1 : EMPTY_VALUE;   

      //
      //
      //

      if (arrowsVisible)
      {
      string lookFor = arrowsIdentifier+":"+(string)time[i]; if (ObjectFind(0,lookFor)==0) ObjectDelete(0,lookFor);                       
      if (i<(rates_total-1) && valc[i] != valc[i+1])
      {
         if (valc[i] == 1) drawArrow(i,arrowsUpColor,arrowsUpCode,arrowsUpSize,false);
         if (valc[i] ==-1) drawArrow(i,arrowsDnColor,arrowsDnCode,arrowsDnSize, true);
      }
   }                  
   }
   manageAlerts();
return(rates_total);
}
      
//-------------------------------------------------------------------
//
//-------------------------------------------------------------------

void manageAlerts()
{
   if (alertsOn)
   {
      int whichBar = 1; if (alertsOnCurrent) whichBar = 0; 
      if (valc[whichBar]!= valc[whichBar+1])
      {
         static datetime time1 = 0;
         static string   mess1 = "";
            if (valc[whichBar] == 1) doAlert(time1,mess1," crossing up");
            if (valc[whichBar] ==-1) doAlert(time1,mess1," crossing 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)+" 3 ma cross "+doWhat;
          if (alertsMessage) Alert(message);
          if (alertsNotify)  SendNotification(message);
          if (alertsEmail)   SendMail(_Symbol+" 3 ma cross ",message);
          if (alertsSound)   PlaySound(soundfile);
   }
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------

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 += PeriodSeconds(_Period)-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);
}

//
//
//

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("");
}
