//+------------------------------------------------------------------+
//|                                                   macd cross.mq4 | 
//|                                            original by Eli Hayun |
//|                                             mod by mrtools       |
//+------------------------------------------------------------------+

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1  Red
#property indicator_color2  Blue
#property indicator_color3  Blue
#property indicator_color4  Red
#property indicator_width1  2
#property indicator_width2  2


//
//
//
//
//

extern int   FastHull        = 8;
extern int   SlowHull        = 13;
extern int   Price           = PRICE_CLOSE;
extern bool  ShowArrows      = true;
extern int   arrowSize       = 9;
extern int   uparrowCode     = 119;
extern int   dnarrowCode     = 119;
extern bool  alertsOn        = true;
extern bool  alertsOnCurrent = false;
extern bool  alertsMessage   = true;
extern bool  alertsSound     = false;
extern bool  alertsEmail     = false;
extern bool  alertsNotify    = false;

//
//
//
//
//

double fastMa[];
double slowMa[];
double CrossUp[];
double CrossDn[];
double trend[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(5);  
   SetIndexBuffer(0,fastMa);
   SetIndexBuffer(1,slowMa);
   SetIndexBuffer(2,CrossUp);  
   SetIndexBuffer(3,CrossDn);
   SetIndexBuffer(4,trend);
   if (ShowArrows)
   {
     SetIndexStyle(2,DRAW_ARROW,0,arrowSize); SetIndexArrow(2,uparrowCode);
     SetIndexStyle(3,DRAW_ARROW,0,arrowSize); SetIndexArrow(3,dnarrowCode);   
   }
   else
   {
     SetIndexStyle(2,DRAW_NONE);
     SetIndexStyle(3,DRAW_NONE);
   }       
   
   IndicatorShortName("HmaCross ");
return(0);
}

int deinit()  {   return(0);  }

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
   int i,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = MathMin(Bars-counted_bars,Bars-1);

   //
   //
   //
   //
   //
   
     for (i=limit; i>=0; i--)
     {
         double price = iMA(NULL,0,1,0,MODE_SMA,Price,i);
         fastMa[i]    = iHull(price,FastHull,i,0);
         slowMa[i]    = iHull(price,SlowHull,i,1);
         
      
         trend[i] = trend[i+1];
         if (fastMa[i]>slowMa[i]) trend[i] = 1;
         if (fastMa[i]<slowMa[i]) trend[i] =-1;
         
         //
         //
         //
         //
         //
      
         CrossUp[i] = EMPTY_VALUE;
         CrossDn[i] = EMPTY_VALUE;
         if (trend[i]!= trend[i+1])
         if (trend[i] == 1)
               CrossUp[i] = Low[i]  - iATR(NULL,0,20,i)/2.0;
         else  CrossDn[i] = High[i] + iATR(NULL,0,20,i)/2.0;
      }
      
      //
      //
      //
      //
      //
   
      if (alertsOn)
      {
         if (alertsOnCurrent)
              int whichBar = 0;
         else     whichBar = 1;
         if (trend[whichBar] != trend[whichBar+1])
         if (trend[whichBar] == 1)
               doAlert("crossing up");
         else  doAlert("crossing down");       
       }   
return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double workHull[][4];
double iHull(double price, double period, int r, int instanceNo=0)
{
   if (ArrayRange(workHull,0)!= Bars) ArrayResize(workHull,Bars); r = Bars-r-1;

   //
   //
   //
   //
   //

      int HmaPeriod  = MathMax(period,2);
      int HalfPeriod = MathFloor(HmaPeriod/2);
      int HullPeriod = MathFloor(MathSqrt(HmaPeriod));
      double hma,hmw,weight; instanceNo *= 2;

         workHull[r][instanceNo] = price;

         //
         //
         //
         //
         //
               
         hmw = HalfPeriod; hma = hmw*price; 
            for(int k=1; k<HalfPeriod && (r-k)>=0; k++)
            {
               weight = HalfPeriod-k;
               hmw   += weight;
               hma   += weight*workHull[r-k][instanceNo];  
            }             
            workHull[r][instanceNo+1] = 2.0*hma/hmw;

         hmw = HmaPeriod; hma = hmw*price; 
            for(k=1; k<period && (r-k)>=0; k++)
            {
               weight = HmaPeriod-k;
               hmw   += weight;
               hma   += weight*workHull[r-k][instanceNo];
            }             
            workHull[r][instanceNo+1] -= hma/hmw;

         //
         //
         //
         //
         //
         
         hmw = HullPeriod; hma = hmw*workHull[r][instanceNo+1];
            for(k=1; k<HullPeriod && (r-k)>=0; k++)
            {
               weight = HullPeriod-k;
               hmw   += weight;
               hma   += weight*workHull[r-k][1+instanceNo];  
            }
   return(hma/hmw);
}

//
//
//
//
//

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 =  StringConcatenate(Symbol()," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," Hull ",doWhat);
             if (alertsMessage) Alert(message);
             if (alertsNotify)  SendNotification(message);
             if (alertsEmail)   SendMail(StringConcatenate(Symbol()," Hull "),message);
             if (alertsSound)   PlaySound("alert2.wav");
      }
}


