
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "www,forex-station.com"
#property link      "www,forex-station.com"

#property indicator_separate_window
#property indicator_buffers 2
#property strict

//
//
//
//
//

extern ENUM_TIMEFRAMES   TimeFrame        = PERIOD_CURRENT;    // Time frame
input int                MaPeriod         = 9;                // Moving average period
input ENUM_MA_METHOD     MaMethod         = MODE_LWMA;          // Moving average method
input ENUM_APPLIED_PRICE MaPrice          = PRICE_WEIGHTED;       // Moving average price
input int                HistoWidth       = 3;                 // Histogram bars width
input color              UpHistoColor     = clrSkyBlue;      // Bullish color
input color              DnHistoColor     = clrTomato;            // Bearish color
input bool               alertsOn         = false;              // Alerts on true/false?
input bool               alertsOnCurrent  = true;             // 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   = true;             // Arrows drawn on newest bar of higher time frame bar true/false?
input string             arrowsIdentifier = "ma Arrows1";      // Unique ID for arrows
input double             arrowsUpperGap   = 1.0;               // Upper arrow gap
input double             arrowsLowerGap   = 1.0;               // Lower arrow gap
input color              arrowsUpColor    = clrRoyalBlue;           // Up arrow color
input color              arrowsDnColor    = clrRed;        // Down arrow color
input int                arrowsUpCode     = 233;               // Up arrow code
input int                arrowsDnCode     = 234;               // Down arrow code
input int                arrowsUpSize     = 2;                 // Up arrow size
input int                arrowsDnSize     = 2;                 // Down arrow size

double UpH[],DnH[],valc[],count[];
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,MaPeriod,MaMethod,MaPrice,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(4);   
   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,valc);
   SetIndexBuffer(3,count);
   
   IndicatorSetDouble(INDICATOR_MINIMUM,0);
   IndicatorSetDouble(INDICATOR_MAXIMUM,1);
   
   indicatorFileName = WindowExpertName();
   TimeFrame         = MathMax(TimeFrame,_Period);
     
   IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(TimeFrame)+"   Price cross ma");
return(INIT_SUCCEEDED);
}  
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);
    }
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------

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=rates_total-prev_calculated+1; if (i>=rates_total) i=rates_total-1; count[0] = i;
      if (TimeFrame!=_Period)
      {
         i = (int)fmax(i,fmin(rates_total-1,_mtfCall(3,0)*TimeFrame/_Period));
         for (; 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>=0 && !_StopFlag; i--)
   {
      double ma = iMA(NULL,0,MaPeriod,0,MaMethod,MaPrice,i);
      valc[i] = (i<rates_total-1) ? (close[i]>ma) ? 1 : (close[i]<ma) ? -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]; ObjectDelete(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)+" Price cross ma "+doWhat;
          if (alertsMessage) Alert(message);
          if (alertsNotify)  SendNotification(message);
          if (alertsEmail)   SendMail(_Symbol+" Price cross ma ",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 += _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);
}

//
//
//

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("");
}
