//+------------------------------------------------------------------+
//|                                       smTMMS HeikinAshi-Chart_vX
//+------------------------------------------------------------------+
#property copyright "Copyright 14.08.2019, SwingMan"

/*--------------------------------------------------------------------
30.06.2019  v_1.0 -  First version: Chart, MovingAverage, HullAverage
01.07.2019  v_1.1 -  Signals
02.07.2019  v_1.2 -  Alerts, Signal filter for Hull-Average slope! with Expiration date
05.07.2019  v_1.3 -  Without Expiration date
--------------------------------------------------------------------*/

//--- Source Code:
/*+------------------------------------------------------------------+
//|                                                  Heiken Ashi.mq4 |
#property copyright   "2006-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
--------------------------------------------------------------------*/
//#property description "We recommend next chart settings (press F8 or select menu 'Charts'->'Properties...'):"
//#property description " - on 'Color' Tab select 'Black' for 'Line Graph'"
//#property description " - on 'Common' Tab disable 'Chart on Foreground' checkbox and select 'Line Chart' radiobutton"
//-------------------------------------------------------------------

#property strict

#property indicator_chart_window

#property indicator_buffers 9

//--- HeikinAshi Candles -------------------------
#property indicator_color1 clrChocolate
#property indicator_color2 clrAqua
#property indicator_color3 clrLightPink
#property indicator_color4 clrPowderBlue
#property indicator_width1 1
#property indicator_width2 1
#property indicator_width3 3
#property indicator_width4 3

//--- Moving Average
#property indicator_color5 clrYellow
#property indicator_width5 2
//--- Hull Moving Average
#property indicator_color6 clrTurquoise
#property indicator_color7 clrDeepPink
#property indicator_width6 3
#property indicator_width7 3

//---
//--- Signals
#property indicator_color8 clrLime
#property indicator_color9 clrMagenta
#property indicator_width8 2
#property indicator_width9 2
//
//--- inputs
//+------------------------------------------------------------------+
input bool Enable_HullSlope_Filter= true;
input bool Draw_Candle_Wicks      = false;
//
sinput string             sMAverage="MovingAverage"; //=================================  
input int                 MA_Period       = 5;
input int                 MA_Shift        = 2;
input ENUM_MA_METHOD      MA_Method       = MODE_EMA;
input ENUM_APPLIED_PRICE  MA_AppliedPrice = PRICE_CLOSE;
//
sinput string             sHullAverage="HULL MovingAverage"; //=================================  
input int                 Hull_Period     =12;
input double              Hull_Divisor    =2;
input ENUM_APPLIED_PRICE  Hull_AppliedPrice=PRICE_CLOSE;
//
sinput string             sAlerts="Alerts"; //=================================  
extern bool SendSignal_Alerts=true;
extern bool SendSignal_Emails=false;
//
sinput string           sArrows="Arrows"; //=================================  
input int  ArrowCode_EntrySignal=164; //181;
input int  ArrowCode_ExitSignal     = 203;
input int  Arrow_Width              = 0;
input color ArrowColor_SignalUP     = clrAqua;
input color ArrowColor_SignalDOWN   = clrMagenta;
input bool  Show_Comments           = true;
//+------------------------------------------------------------------+

//--- buffers Candles
double ExtLowHighBuffer[];
double ExtHighLowBuffer[];
double ExtOpenBuffer[];
double ExtCloseBuffer[];
//--- buffers Moving Averages
double bufMAverage[];
double bufHullUP[],bufHullDN[],bufHull[],buffHullAvg[],trend[];
double signalUP[],signalDN[];

//--- variables
string CR="\n";
//---

int lastSignal=0;
datetime thisTime,oldTime;
bool newBar;
//
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//|------------------------------------------------------------------|
void OnInit(void)
  {
//---
   IndicatorBuffers(12);

   IndicatorShortName(WindowExpertName());

   IndicatorDigits(Digits);
//---
   string sHullFilter;
   if(Enable_HullSlope_Filter==true)
      sHullFilter="with Hull-Slope-Filter";
   else
      sHullFilter="without Hull-Slope-Filter";

   if(Show_Comments==true)
     {
      Comment(CR,
              WindowExpertName(),CR,
              sHullFilter,CR,
              "======================");
     }

//--- chart settings
   ChartSetInteger(0,CHART_SHOW_GRID,false);
   ChartSetInteger(0,CHART_MODE,CHART_BARS);
   ChartSetInteger(0,CHART_COLOR_CHART_UP,clrOliveDrab);
   ChartSetInteger(0,CHART_COLOR_CHART_DOWN,clrOliveDrab);

//--- indicator lines
   int iBuff=-1;
   int iArrow=ArrowCode_EntrySignal; //164;
   iBuff++; SetIndexBuffer(iBuff,ExtLowHighBuffer); SetIndexStyle(iBuff,DRAW_HISTOGRAM);   SetIndexLabel(iBuff,"haLow/High");
   iBuff++; SetIndexBuffer(iBuff,ExtHighLowBuffer); SetIndexStyle(iBuff,DRAW_HISTOGRAM);   SetIndexLabel(iBuff,"haHigh/Low");
   iBuff++; SetIndexBuffer(iBuff,ExtOpenBuffer);    SetIndexStyle(iBuff,DRAW_HISTOGRAM);   SetIndexLabel(iBuff,"haOpen");
   iBuff++; SetIndexBuffer(iBuff,ExtCloseBuffer);   SetIndexStyle(iBuff,DRAW_HISTOGRAM);   SetIndexLabel(iBuff,"haClose");

   iBuff++; SetIndexBuffer(iBuff,bufMAverage);   SetIndexStyle(iBuff,DRAW_LINE);   SetIndexLabel(iBuff,"MA ("+(string)MA_Period+","+(string)MA_Shift+")");

   iBuff++; SetIndexBuffer(iBuff,bufHullUP);   SetIndexStyle(iBuff,DRAW_LINE);   SetIndexLabel(iBuff,"Hull-Up ("+(string)Hull_Period+")");
   iBuff++; SetIndexBuffer(iBuff,bufHullDN);   SetIndexStyle(iBuff,DRAW_LINE);   SetIndexLabel(iBuff,"Hull-Down ("+(string)Hull_Period+")");

   iBuff++; SetIndexBuffer(iBuff,signalUP);     SetIndexStyle(iBuff,DRAW_ARROW); SetIndexArrow(iBuff,iArrow); SetIndexLabel(iBuff,"Entry LONG");
   iBuff++; SetIndexBuffer(iBuff,signalDN);     SetIndexStyle(iBuff,DRAW_ARROW); SetIndexArrow(iBuff,iArrow); SetIndexLabel(iBuff,"Entry SHORT");
//--- more buffers
   iBuff++; SetIndexBuffer(iBuff,bufHull);
   iBuff++; SetIndexBuffer(iBuff,buffHullAvg);
   iBuff++; SetIndexBuffer(iBuff,trend);
//---
   if(Draw_Candle_Wicks==false)
     {
      SetIndexStyle(0,DRAW_NONE);
      SetIndexStyle(1,DRAW_NONE);
     }

   SetIndexDrawBegin(0,10);
   SetIndexDrawBegin(1,10);
   SetIndexDrawBegin(2,10);
   SetIndexDrawBegin(3,10);
//--- initialization done
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(Show_Comments)
      Comment("");
  }
//---

//+------------------------------------------------------------------+
//| Heikin Ashi                                                      |
//+------------------------------------------------------------------+
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,pos;
   double haOpen,haHigh,haLow,haClose;
//---
   if(rates_total<=10)
      return(0);
//--- new bar
   thisTime=Time[0];
   if(thisTime!=oldTime)
     {
      oldTime=thisTime;
      newBar=true;
     }
   else
      newBar=false;

   if(newBar==false)
      return(rates_total);

//--- preliminary calculation
   int i0=rates_total-1;

//--- set first candle
   if(open[i0]<close[i0])
     {
      ExtLowHighBuffer[i0]=low[i0];
      ExtHighLowBuffer[i0]=high[i0];
     }
   else
     {
      ExtLowHighBuffer[i0]=high[i0];
      ExtHighLowBuffer[i0]=low[i0];
     }
   ExtOpenBuffer[i0]=open[i0];
   ExtCloseBuffer[i0]=close[i0];
//---

   pos=0;
//--- main loop of calculations
   for(i=rates_total-2; i>=pos; i--)
     {
      //--- Heikin Ashi Candles ---------------------------
      haOpen=(ExtOpenBuffer[i+1]+ExtCloseBuffer[i+1])/2;
      haClose=(open[i]+high[i]+low[i]+close[i])/4;
      haHigh=MathMax(high[i],MathMax(haOpen,haClose));
      haLow=MathMin(low[i],MathMin(haOpen,haClose));
      if(haOpen<haClose)
        {
         ExtLowHighBuffer[i]=haLow;
         ExtHighLowBuffer[i]=haHigh;
        }
      else
        {
         ExtLowHighBuffer[i]=haHigh;
         ExtHighLowBuffer[i]=haLow;
        }
      ExtOpenBuffer[i] =haOpen;
      ExtCloseBuffer[i]=haClose;
     }

//--- Moving Average     
   for(i=0; i<rates_total; i++)
     {
      bufMAverage[i]=iMA(Symbol(),Period(),MA_Period,MA_Shift,MA_Method,MA_AppliedPrice,i);
     }

//--- Hull Moving Average          
   Get_HullMovingAverage(rates_total,bufHullUP,bufHullDN);

//--- Signals
   Get_ChartSignals(rates_total);

//--- done
   return(rates_total);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Get_HullMovingAverage(int limitX,double &hullUP[],double &hullDN[])
  {
//-- 3. Hull moving average current TF ----------
   int MA_period1=(int)(Hull_Period/Hull_Divisor);
   int pPeriod=(int)MathSqrt(Hull_Period);

   for(int i=0; i<limitX; i++)
      bufHull[i]=2*iMA(Symbol(),Period(),MA_period1,0,MODE_LWMA,Hull_AppliedPrice,i)-
                 iMA(Symbol(),Period(),Hull_Period,0,MODE_LWMA,Hull_AppliedPrice,i);

   for(int i=0; i<limitX-Hull_Period; i++)
      buffHullAvg[i]=iMAOnArray(bufHull,0,pPeriod,0,MODE_LWMA,i);

//-- 3.1 Matrix Hull moving average current TF --
   for(int i=limitX-Hull_Period; i>=0; i--)
     {
      trend[i]=trend[i+1];
      if(buffHullAvg[i]>=buffHullAvg[i+1]) trend[i]=1; else trend[i]=-1;

      if(trend[i]>0)
        {
         bufHullUP[i]=buffHullAvg[i];
         bufHullDN[i]=EMPTY_VALUE;
         if(trend[i+1]<0) bufHullUP[i+1]=buffHullAvg[i+1];
        }
      else
      if(trend[i]<0)
        {
         bufHullUP[i]=EMPTY_VALUE;
         bufHullDN[i]=buffHullAvg[i];
         if(trend[i+1]>0) bufHullDN[i+1]=buffHullAvg[i+1];
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Get_ChartSignals(int limitX)
  {
   int newColor=0,thisColor,prevColor;
   int averagePos,closePos;
   int hullSlope;

   for(int i=limitX-Hull_Period; i>=0; i--)
     {
      int i1=i+1;

      //--- 1. condition averages (1 bar before)
      if(buffHullAvg[i1]>=bufMAverage[i1])
         averagePos=1; else averagePos=-1;

      //--- 2. condition close (1 bar before))
      if(Close[i1]>=bufMAverage[i1])
         closePos=1; else closePos=-1;

      //--- 3. condition candles (maxim 5 bars before)
      newColor=0;
      for(int j=0;j<=5;j++)
        {
         if(ExtCloseBuffer[i1+j]>=ExtOpenBuffer[i1+j])
            thisColor=1; else thisColor=-1;
         if(ExtCloseBuffer[i1+1+j]>=ExtOpenBuffer[i1+1+j])
            prevColor=1; else prevColor=-1;

         if(thisColor!=prevColor)
           {
            newColor=thisColor;
            break;
           }
        }

      //--- 4. check Hull-Slope filter
      if(buffHullAvg[i1]>=buffHullAvg[i1+1])
         hullSlope=1;
      else
         hullSlope=-1;

      //--- delete old signal -----------------------------
      if(lastSignal==-1 && (averagePos==1 || closePos==1))
         lastSignal=0;
      if(lastSignal==1 && (averagePos==-1 || closePos==-1))
         lastSignal=0;

      //--- draw signals
      signalUP[i]=EMPTY_VALUE;
      signalDN[i]=EMPTY_VALUE;

      //===================================================
      //--- LONG signal
      if(newColor==1 && newColor==averagePos && newColor==closePos && lastSignal!=1)
        {
         if(Enable_HullSlope_Filter==false || (Enable_HullSlope_Filter==true && hullSlope==1))
           {
            signalUP[i]=Open[i];
            lastSignal=1;
            if(i==0)
               SendAlerts(i,OP_BUY,Symbol(),Period());
           }
        }
      else
      //===================================================
      //--- SHORT signal
      if(newColor==-1 && newColor==averagePos && newColor==closePos && lastSignal!=-1)
        {
         if(Enable_HullSlope_Filter==false || (Enable_HullSlope_Filter==true && hullSlope==-1))
           {
            signalDN[i]=Open[i];
            lastSignal=-1;
            if(i==0)
               SendAlerts(i,OP_SELL,Symbol(),Period());
           }
        }
     }
  }
//+------------------------------------------------------------------+
//    Send Alerts 
//+------------------------------------------------------------------+
void SendAlerts(int iBar,int iSignalDirection,string sSymbol,int iPeriod)
  {
   string subjectEmailAlert="TMMS";

   if(SendSignal_Alerts == false && SendSignal_Emails == false) return;

   string   sPeriod     = " ("+Get_PeriodString(iPeriod)+") ";
   double   dEntryPrice = iOpen(sSymbol,iPeriod,iBar);
   string   sEntryPrice = " "+DoubleToString(dEntryPrice,Digits);
   string   sTime       = "  " + TimeToStr(TimeCurrent(),TIME_MINUTES|TIME_SECONDS) + "  ";
   string   sBarTime    = "  Bar: " + TimeToStr(Time[iBar],TIME_MINUTES|TIME_SECONDS) + "  ";

   string sText,sTextAlert;

//--- LONG Entry Signal ------------------------------------------
   if(iSignalDirection==OP_BUY)
     {
      sText=" LONG entry";
     }
   else

//--- SHORT Entry Signal -----------------------------------------
   if(iSignalDirection==OP_SELL)
     {
      sText=" SHORT entry";
     }

//--- Send alerts
   sTextAlert=sSymbol+sPeriod+sText+sTime+"  TMMS: "+sEntryPrice;

   if(SendSignal_Alerts==true) Alert(sTextAlert);

   if(SendSignal_Emails==true) SendMail(subjectEmailAlert,sTextAlert);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Get_PeriodString(int iPeriod)
  {
   string sPeriod;
   switch(iPeriod)
     {
      case PERIOD_M1:   sPeriod="M1"; break;
      case PERIOD_M5:   sPeriod="M5"; break;
      case PERIOD_M15:  sPeriod="M15"; break;
      case PERIOD_M30:  sPeriod="M30"; break;
      case PERIOD_H1:   sPeriod="H1"; break;
      case PERIOD_H4:   sPeriod="H4"; break;
      case PERIOD_D1:   sPeriod="D1"; break;
      case PERIOD_W1:   sPeriod="W1"; break;
      case PERIOD_MN1:  sPeriod="MN1"; break;
     }
   return(sPeriod);
  }
//+------------------------------------------------------------------+
