//+------------------------------------------------------------------+
//|                                                    WprMa1Ma2.mq4 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   3
//--- plot WPR
#property indicator_label1  "WPR"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot MA1
#property indicator_label2  "MA1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGold
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot MA2
#property indicator_label3  "MA2"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrDodgerBlue
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

extern ENUM_TIMEFRAMES    TimeFrame        = PERIOD_CURRENT;    // Time frame
input int                 wpr_period       = 14;
input int                 ma1_period       = 14;
input ENUM_MA_METHOD      ma1_method       = MODE_SMA;
input int                 ma2_period       = 14;
input ENUM_MA_METHOD      ma2_method       = MODE_SMA;
input bool                alertsOn         = false;             // Alerts on true/false?
input bool                alertsOnCurrent  = true;              // Alerts on open bar true/false?
input bool                alertsMessage    = true;              // Alerts message true/false?
input bool                alertsSound      = false;             // Alerts sound true/false?
input bool                alertsNotify     = false;             // Alerts push notification true/false?
input bool                alertsEmail      = false;             // Alerts email true/false?
input string              soundFile        = "alert2.wav";      // Sound file
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 = "wpr Arrows1";     // Unique ID for arrows
input double              arrowsUpperGap   = 0.5;               // Upper arrow gap
input double              arrowsLowerGap   = 0.5;               // Lower arrow gap
input color               arrowsUpColor    = clrBlue;           // Up arrow color
input color               arrowsDnColor    = clrCrimson;        // Down arrow color
input int                 arrowsUpCode     = 116;               // Up arrow code
input int                 arrowsDnCode     = 116;               // Down arrow code
input int                 arrowsUpSize     = 2;                 // Up arrow size
input int                 arrowsDnSize     = 2;                 // Down arrow size
input bool                Interpolate     = true;              // Interpolate in multi time frame mode?


//--- indicator buffers
double         WPRBuffer[];
double         MA1Buffer[];
double         MA2Buffer[],trend[],count[];
string IndicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,IndicatorFileName,PERIOD_CURRENT,wpr_period,ma1_period,ma1_method,ma2_period,ma2_method,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsNotify,alertsEmail,soundFile,arrowsVisible,arrowsOnNewest,arrowsIdentifier,arrowsUpperGap,arrowsLowerGap,arrowsUpColor,arrowsDnColor,arrowsUpCode,arrowsDnCode,arrowsUpSize,arrowsDnSize,_buff,_ind)
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,WPRBuffer);
   SetIndexBuffer(1,MA1Buffer);
   SetIndexBuffer(2,MA2Buffer);
   SetIndexBuffer(3,trend);
   SetIndexBuffer(4,count);
   
   IndicatorFileName = WindowExpertName();
   TimeFrame         = fmax(TimeFrame,_Period); 
   
   IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(TimeFrame)+" WprMa1Ma2");
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);
    }
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+

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(4,0)*TimeFrame/_Period));
         for (; i>=0 && !_StopFlag; i--)
         {
            int y = iBarShift(NULL,TimeFrame,time[i]);
               WPRBuffer[i] = _mtfCall(0,y);
               MA1Buffer[i] = _mtfCall(1,y);
               MA2Buffer[i] = _mtfCall(2,y);
               
               if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,time[i-1]))) continue;
                  
               //
               //
               //
                  
               #define _interpolate(buff) buff[i+k] = buff[i]+(buff[i+n]-buff[i])*k/n
               int n,k; datetime btime = iTime(NULL,TimeFrame,y);
                  for(n = 1; (i+n)<rates_total && time[i+n] >= btime; n++) continue;	
                  for(k = 1; k<n && (i+n)<rates_total && (i+k)<rates_total; k++) 
                  {
                     _interpolate(WPRBuffer);
                     _interpolate(MA1Buffer);
                     _interpolate(MA2Buffer);
                   }          
         }
   return(rates_total);
   }            

   //
   //
   //

   for (; i>=0 && !_StopFlag; i--)
   {
      WPRBuffer[i] = iWPR(_Symbol,_Period,wpr_period,i);
      MA1Buffer[i] = iMAOnArray(WPRBuffer,0,ma1_period,0,ma1_method,i);
      MA2Buffer[i] = iMAOnArray(MA1Buffer,0,ma2_period,0,ma2_method,i);
      trend[i] = (MA1Buffer[i]>MA2Buffer[i]) ? 1 : (MA1Buffer[i]<MA2Buffer[i]) ? -1 : (i<rates_total-1) ? trend[i+1] : 0;
      
      //
      //
      //
               
      if (arrowsVisible)
      {
         string lookFor = arrowsIdentifier+":"+(string)time[i]; ObjectDelete(lookFor);            
         if (i<(rates_total-1) && trend[i] != trend[i+1])
          {
            if (trend[i] == 1) drawArrow(i,arrowsUpColor,arrowsUpCode,arrowsUpSize,false);
            if (trend[i] ==-1) drawArrow(i,arrowsDnColor,arrowsDnCode,arrowsDnSize, true);
          }
      }  
   }
   if (alertsOn)
   {
      int whichBar = 1; if (alertsOnCurrent) whichBar = 0; 
      if (trend[whichBar] != trend[whichBar+1])
      {
         if (trend[whichBar] == 1) doAlert(" crossing up");
         if (trend[whichBar] ==-1) doAlert(" crossing down");       
      }         
    }      
return(rates_total);
}

//------------------------------------------------------------------
// Alert function
//------------------------------------------------------------------

void doAlert(string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[0]) {
          previousAlert  = doWhat;
          previousTime   = Time[0];

          //
          //
          //
          //
          //

          message = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" WprMa1Ma2 "+doWhat;
             if (alertsMessage) Alert(message);
             if (alertsNotify)  SendNotification(message);
             if (alertsEmail)   SendMail(_Symbol+" WprMa1Ma2 ",message);
             if (alertsSound)   PlaySound(soundFile);
      }
}

//-------------------------------------------------------------------
//    Arrow function                                                              
//-------------------------------------------------------------------

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("");
}

