//+------------------------------------------------------------------+
//|                                     AllHeikin-Ashi_v2.3 600+.mq4 |
//|                                Copyright � 2014, TrendLaboratory |
//|            http://finance.groups.yahoo.com/group/TrendLaboratory |
//|                                   E-mail: igorad2003@yahoo.co.uk |
//+------------------------------------------------------------------+
// List of MAs:
// MA_Method= 0: SMA        - Simple Moving Average
// MA_Method= 1: EMA        - Exponential Moving Average
// MA_Method= 2: Wilder     - Wilder Exponential Moving Average
// MA_Method= 3: LWMA       - Linear Weighted Moving Average 
// MA_Method= 4: SineWMA    - Sine Weighted Moving Average
// MA_Method= 5: TriMA      - Triangular Moving Average
// MA_Method= 6: LSMA       - Least Square Moving Average (or EPMA, Linear Regression Line)
// MA_Method= 7: SMMA       - Smoothed Moving Average
// MA_Method= 8: HMA        - Hull Moving Average by Alan Hull
// MA_Method= 9: ZeroLagEMA - Zero-Lag Exponential Moving Average
// MA_Method=10: DEMA       - Double Exponential Moving Average by Patrick Mulloy
// MA_Method=11: T3_basic   - T3 by T.Tillson (original version)
// MA_Method=12: ITrend     - Instantaneous Trendline by J.Ehlers
// MA_Method=13: Median     - Moving Median
// MA_Method=14: GeoMean    - Geometric Mean
// MA_Method=15: REMA       - Regularized EMA by Chris Satchwell
// MA_Method=16: ILRS       - Integral of Linear Regression Slope 
// MA_Method=17: IE/2       - Combination of LSMA and ILRS 
// MA_Method=18: TriMAgen   - Triangular Moving Average generalized by J.Ehlers
// MA_Method=19: VWMA       - Volume Weighted Moving Average 
// MA_Method=20: JSmooth    - Smoothing by Mark Jurik
// MA_Method=21: SMA_eq     - Simplified SMA
// MA_Method=22: ALMA       - Arnaud Legoux Moving Average
// MA_Method=23: TEMA       - Triple Exponential Moving Average by Patrick Mulloy
// MA_Method=24: T3         - T3 by T.Tillson (correct version)
// MA_Method=25: Laguerre   - Laguerre filter by J.Ehlers
// MA_Method=26: MD         - McGinley Dynamic


#property copyright "Copyright � 2014, TrendLaboratory"
#property link      "http://finance.groups.yahoo.com/group/TrendLaboratory"


#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1 RoyalBlue
#property indicator_color2 Red
#property indicator_color3 RoyalBlue
#property indicator_color4 Red
#property indicator_width1 1
#property indicator_width2 1
#property indicator_width3 3
#property indicator_width4 3
  
//---- 
extern int     TimeFrame         =     0;   //TimeFrame in min
extern int     MA_Period         =    40;   //Period of smoothing
extern int     MA_Method         =    23;   //Method of Moving Average  
extern double  MinMove           =   0.0;   //in pips
extern bool    ShowHACandles     =  true;   //true-HA Candles,false-OHLC     

extern string  Alerts            = "--- Alerts & E-Mails ---";
extern int     AlertMode         =     0;
extern int     SoundsNumber      =     5;   //Number of sounds after Signal
extern int     SoundsPause       =     5;   //Pause in sec between sounds 
extern string  UpSound           = "alert.wav";
extern string  DnSound           = "alert2.wav";
extern int     EmailMode         =     0;   //0-on,1-off   
extern int     EmailsNumber      =     1;   //0-on,1-off


double haHigh[];
double haLow[];
double haClose[];
double haOpen[];
double closePrice[];
double openPrice[];
double highPrice[];
double lowPrice[];

int      draw_begin, masize; 
double   tmp[][4][2], ma[4][3], _point, haclose[2], haopen[2];
datetime prevtime[4], preTime, ptime, prevhatime;
string   IndicatorName, TF, maname, prevmess, prevemail;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int init()
{
   if(TimeFrame <= Period()) TimeFrame = Period();
   TF = tf(TimeFrame);
   if(TF  == "Unknown timeframe") TimeFrame = Period();
   
   IndicatorDigits(Digits);
   IndicatorBuffers(8);
   SetIndexBuffer(0,    haHigh); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,     haLow); SetIndexStyle(1,DRAW_HISTOGRAM);
   SetIndexBuffer(2,   haClose); SetIndexStyle(2,DRAW_HISTOGRAM);
   SetIndexBuffer(3,    haOpen); SetIndexStyle(3,DRAW_HISTOGRAM);
   SetIndexBuffer(4,closePrice);
   SetIndexBuffer(5, openPrice);
   SetIndexBuffer(6, highPrice);
   SetIndexBuffer(7,  lowPrice);
            
   maname = averageName(MA_Method, masize);
   
   IndicatorName = WindowExpertName(); 
   IndicatorShortName(IndicatorName+"["+TF+"]("+MA_Period+","+maname+","+DoubleToStr(MinMove,2)+")");
   SetIndexLabel(0,"haHigh" );   
   SetIndexLabel(1,"haLow"  ); 
   SetIndexLabel(2,"haClose");
   SetIndexLabel(3,"haOpen" );     
   
   draw_begin=2*MathCeil(0.5*(MA_Period+1))*TimeFrame/Period();
   SetIndexDrawBegin(0,draw_begin);   
   SetIndexDrawBegin(1,draw_begin);
   SetIndexDrawBegin(2,draw_begin);
   SetIndexDrawBegin(3,draw_begin);
      
   _point   = Point*MathPow(10,Digits%2);
   
   ArrayResize(tmp,masize);
   
   return(0);
}

//+------------------------------------------------------------------+
//|  AllHeikin-Ashi_v2.3 600+                                        |
//+------------------------------------------------------------------+

int start()
{
   int i, shift, limit, counted_bars=IndicatorCounted();
      
   if(counted_bars > 0) limit = Bars - counted_bars - 1;
   if(counted_bars < 0) return(0);
   if(counted_bars < 1)
   { 
   limit = Bars-1;   
      for(i=limit;i>=0;i--) 
      {
      haHigh[i]  = EMPTY_VALUE;
      haLow[i]   = EMPTY_VALUE;
      haClose[i] = EMPTY_VALUE;
      haOpen[i]  = EMPTY_VALUE;
      }
   }   
   
   if(TimeFrame != Period())
	{
   limit = MathMax(limit,TimeFrame/Period());   
      
      for(shift = 0;shift < limit;shift++) 
      {	
      int y = iBarShift(NULL,TimeFrame,Time[shift]);
      
      haClose[shift] = iCustom(NULL,TimeFrame,IndicatorName,0,MA_Period,MA_Method,MinMove,ShowHACandles,"",AlertMode,SoundsNumber,SoundsPause,UpSound,DnSound,EmailMode,EmailsNumber,2,y);
      haOpen [shift] = iCustom(NULL,TimeFrame,IndicatorName,0,MA_Period,MA_Method,MinMove,ShowHACandles,"",AlertMode,SoundsNumber,SoundsPause,UpSound,DnSound,EmailMode,EmailsNumber,3,y);
      haHigh [shift] = iCustom(NULL,TimeFrame,IndicatorName,0,MA_Period,MA_Method,MinMove,ShowHACandles,"",AlertMode,SoundsNumber,SoundsPause,UpSound,DnSound,EmailMode,EmailsNumber,0,y);
      haLow  [shift] = iCustom(NULL,TimeFrame,IndicatorName,0,MA_Period,MA_Method,MinMove,ShowHACandles,"",AlertMode,SoundsNumber,SoundsPause,UpSound,DnSound,EmailMode,EmailsNumber,1,y);
      }  
	
	return(0);
	}
	else
   {
      for(shift=limit;shift>=0;shift--) 
      {
         if(prevhatime != Time[shift])
         {
         haclose[1] = haclose[0];
         haopen [1] = haopen [0];
         prevhatime = Time[shift];  
         } 
      
      
      closePrice[shift] = Close[shift];         
      openPrice [shift] = Open [shift];
      highPrice [shift] = High [shift];         
      lowPrice  [shift] = Low  [shift];
      
      double close = allAverages(0,closePrice,MA_Period,MA_Method,masize,shift);  
      double open  = allAverages(1,openPrice ,MA_Period,MA_Method,masize,shift); 
      double high  = allAverages(2,highPrice ,MA_Period,MA_Method,masize,shift); 
      double low   = allAverages(3,lowPrice  ,MA_Period,MA_Method,masize,shift); 
         
         if(shift == Bars - MA_Period)
         {
            if(ShowHACandles)
            {
            haClose[shift] = close;
            haOpen [shift] = open ;
            haHigh [shift] = high ;
            haLow  [shift] = low  ;
            }
            else
            {
            haClose[shift] = Close[shift];
            haOpen [shift] = Open [shift];
            haHigh [shift] = High [shift];
            haLow  [shift] = Low  [shift];
            }
         haclose[0] = close;
         haopen [0] = open ;
         }
         else
         if(shift < Bars - MA_Period)
         {  
         haclose[0] = (high + low + close + open)/4;
         haopen [0] = (haopen[1] + haclose[1])/2;
         
            if(MinMove > 0)
            {
            if(MathAbs(haclose[0] - haclose[1]) < MinMove*_point) haclose[0] = haclose[1];   
            if(MathAbs(haopen [0] - haopen [1]) < MinMove*_point) haopen [0] = haopen [1];
            }
            
            
            if(haclose[0] > haopen[0])
            {
               if(ShowHACandles)
               {
               haClose[shift] = haclose[0];
               haOpen [shift] = haopen [0];
               haHigh [shift] = MathMax(high, MathMax(haopen[0], haclose[0]));
               haLow  [shift] = MathMin(low , MathMin(haopen[0], haclose[0]));        
               }
               else
               {
               haClose[shift] = MathMax(Close[shift],Open[shift]);
               haOpen [shift] = MathMin(Close[shift],Open[shift]);
               haHigh [shift] = High [shift];
               haLow  [shift] = Low  [shift];
               }
            if(haClose[shift] == haOpen[shift]) haClose[shift] = haOpen[shift] + 0.01*_point; 
            }
            else
            {
               if(ShowHACandles)
               {
               haClose[shift] = haclose[0];
               haOpen [shift] = haopen [0];
               haHigh [shift] = MathMin(low , MathMin(haopen[0], haclose[0])); 
               haLow  [shift] = MathMax(high, MathMax(haopen[0], haclose[0]));  
               }
               else
               {
               haClose[shift] = MathMin(Close[shift],Open[shift]);
               haOpen [shift] = MathMax(Close[shift],Open[shift]);
               haHigh [shift] = Low  [shift];  
               haLow  [shift] = High [shift];
               }
            if(haClose[shift] == haOpen[shift]) haOpen[shift] = haClose[shift] + 0.01*_point; 
            }
         }
      } 
      
      if(AlertMode > 0)
      {
      bool uptrend = haClose[1] > haOpen[1] && haClose[2] < haOpen[2];                  
      bool dntrend = haClose[1] < haOpen[1] && haClose[2] > haOpen[2];
        
         if(uptrend || dntrend)
         {
            if(isNewBar(TimeFrame))
            {
            BoxAlert(uptrend," : BUY Signal at " +DoubleToStr(Close[1],Digits));   
            BoxAlert(dntrend," : SELL Signal at "+DoubleToStr(Close[1],Digits)); 
            }
      
         WarningSound(uptrend,SoundsNumber,SoundsPause,UpSound,Time[1]);
         WarningSound(dntrend,SoundsNumber,SoundsPause,DnSound,Time[1]);
         
            if(EmailMode > 0)
            {
            EmailAlert(uptrend,"BUY" ," : BUY Signal at " +DoubleToStr(Close[1],Digits),EmailsNumber); 
            EmailAlert(dntrend,"SELL"," : SELL Signal at "+DoubleToStr(Close[1],Digits),EmailsNumber); 
            }
         }
      }
                 
   }
   
   return(0);
}

//+------------------------------------------------------------------+
string averageName(int mode,int& arraysize)
{   
   string ma_name = "";
   
   switch(mode)
   {
   case 1 : ma_name="EMA"       ; break;
   case 2 : ma_name="Wilder"    ; break;
   case 3 : ma_name="LWMA"      ; break;
   case 4 : ma_name="SineWMA"   ; break;
   case 5 : ma_name="TriMA"     ; break;
   case 6 : ma_name="LSMA"      ; break;
   case 7 : ma_name="SMMA"      ; break;
   case 8 : ma_name="HMA"       ; break;
   case 9 : ma_name="ZeroLagEMA"; break;
   case 10: ma_name="DEMA"      ; arraysize = 2; break;
   case 11: ma_name="T3 basic"  ; arraysize = 6; break;
   case 12: ma_name="InstTrend" ; break;
   case 13: ma_name="Median"    ; break;
   case 14: ma_name="GeoMean"   ; break;
   case 15: ma_name="REMA"      ; break;
   case 16: ma_name="ILRS"      ; break;
   case 17: ma_name="IE/2"      ; break;
   case 18: ma_name="TriMA_gen" ; break;
   case 19: ma_name="VWMA"      ; break;
   case 20: ma_name="JSmooth"   ; arraysize = 5; break;
   case 21: ma_name="SMA_eq"    ; break;
   case 22: ma_name="ALMA"      ; break;
   case 23: ma_name="TEMA"      ; arraysize = 4; break;
   case 24: ma_name="T3"        ; arraysize = 6; break;
   case 25: ma_name="Laguerre"  ; arraysize = 4; break;
   case 26: ma_name="MD"        ; break;
   default: ma_name="SMA";
   }
   
   return(ma_name);
   
}

double allAverages(int index,double& price[],int period,int mode,int arraysize,int bar)
{
   double MA[3];  
    
   if(prevtime[index] != Time[bar])
   {
   ma[index][2]  = ma[index][1]; 
   ma[index][1]  = ma[index][0]; 
   for(int i=0;i<arraysize;i++) tmp[i][index][1] = tmp[i][index][0];
    
   prevtime[index] = Time[bar]; 
   }
   
   for(i=0;i<3;i++) MA[i] = ma[index][i];   
   
   switch(MA_Method)
   {
   case 1 : ma[index][0] = EMA(price[bar],ma[index][1],period,bar); break;
   case 2 : ma[index][0] = Wilder(price[bar],ma[index][1],period,bar); break;  
   case 3 : ma[index][0] = LWMA(price,period,bar); break;
   case 4 : ma[index][0] = SineWMA(price,period,bar); break;
   case 5 : ma[index][0] = TriMA(price,period,bar); break;
   case 6 : ma[index][0] = LSMA(price,period,bar); break;
   case 7 : ma[index][0] = SMMA(price,ma[index][1],period,bar); break;
   case 8 : ma[index][0] = HMA(price,period,bar); break;
   case 9 : ma[index][0] = ZeroLagEMA(price,ma[index][1],period,bar); break;
   case 10: ma[index][0] = DEMA(index,0,price[bar],period,1,bar); break;
   case 11: ma[index][0] = T3_basic(index,0,price[bar],period,0.7,bar); break;
   case 12: ma[index][0] = ITrend(price,MA,period,bar); break;
   case 13: ma[index][0] = Median(price,period,bar); break;
   case 14: ma[index][0] = GeoMean(price,period,bar); break;
   case 15: ma[index][0] = REMA(price[bar],MA,period,0.5,bar); break;
   case 16: ma[index][0] = ILRS(price,period,bar); break;
   case 17: ma[index][0] = IE2(price,period,bar); break;
   case 18: ma[index][0] = TriMA_gen(price,period,bar); break;
   case 19: ma[index][0] = VWMA(price,period,bar); break;
   case 20: ma[index][0] = JSmooth(index,0,price[bar],period,1,bar); break;
   case 21: ma[index][0] = SMA_eq(price,MA,period,bar); break;
   case 22: ma[index][0] = ALMA(price,period,0.85,8,bar); break;
   case 23: ma[index][0] = TEMA(index,price[bar],period,1,bar); break;
   case 24: ma[index][0] = T3(index,0,price[bar],period,0.7,bar); break;
   case 25: ma[index][0] = Laguerre(index,price[bar],period,4,bar); break;
   case 26: ma[index][0] = McGinley(price[bar],MA,period,bar); break;
   default: ma[index][0] = SMA(price,period,bar); break;
   }
   
   return(ma[index][0]);
}
// MA_Method=0: SMA - Simple Moving Average
double SMA(double& array[],int per,int bar)
{
   double Sum = 0;
   for(int i = 0;i < per;i++) Sum += array[bar+i];
   
   return(Sum/per);
}                
// MA_Method=1: EMA - Exponential Moving Average
double EMA(double price,double prev,int per,int bar)
{
   if(bar >= Bars - 2) double ema = price;
   else 
   ema = prev + 2.0/(1+per)*(price - prev); 
   
   return(ema);
}
// MA_Method=2: Wilder - Wilder Exponential Moving Average
double Wilder(double price,double prev,int per,int bar)
{
   if(bar >= Bars - 2) double wilder = price; //SMA(array1,per,bar);
   else 
   wilder = prev + (price - prev)/per; 
   
   return(wilder);
}
// MA_Method=3: LWMA - Linear Weighted Moving Average 
double LWMA(double& array[],int per,int bar)
{
   double Sum = 0;
   double Weight = 0;
   
      for(int i = 0;i < per;i++)
      { 
      Weight+= (per - i);
      Sum += array[bar+i]*(per - i);
      }
   if(Weight>0) double lwma = Sum/Weight;
   else lwma = 0; 
   return(lwma);
} 
// MA_Method=4: SineWMA - Sine Weighted Moving Average
double SineWMA(double& array[],int per,int bar)
{
   double pi = 3.1415926535;
   double Sum = 0;
   double Weight = 0;
  
      for(int i = 0;i < per;i++)
      { 
      Weight+= MathSin(pi*(i+1)/(per+1));
      Sum += array[bar+i]*MathSin(pi*(i+1)/(per+1)); 
      }
   if(Weight>0) double swma = Sum/Weight;
   else swma = 0; 
   return(swma);
}
// MA_Method=5: TriMA - Triangular Moving Average
double TriMA(double& array[],int per,int bar)
{
   double sma;
   int len = MathCeil((per+1)*0.5);
   
   double sum=0;
   for(int i = 0;i < len;i++) 
   {
   sma = SMA(array,len,bar+i);
   sum += sma;
   } 
   double trima = sum/len;
   
   return(trima);
}
// MA_Method=6: LSMA - Least Square Moving Average (or EPMA, Linear Regression Line)
double LSMA(double& array[],int per,int bar)
{   
   double Sum=0;
   for(int i=per; i>=1; i--) Sum += (i-(per+1)/3.0)*array[bar+per-i];
   double lsma = Sum*6/(per*(per+1));
   return(lsma);
}
// MA_Method=7: SMMA - Smoothed Moving Average
double SMMA(double& array[],double prev,int per,int bar)
{
   if(bar == Bars - per) double smma = SMA(array,per,bar);
   else 
   if(bar < Bars - per)
   {
   double Sum = 0;
   for(int i = 0;i < per;i++) Sum += array[bar+i+1];
   smma = (Sum - prev + array[bar])/per;
   }
   
   return(smma);
}                
// MA_Method=8: HMA - Hull Moving Average by Alan Hull
double HMA(double& array[],int per,int bar)
{
   double _tmp[];
   int len = MathSqrt(per);
   
   ArrayResize(_tmp,len);
   
   if(bar == Bars - per) double hma = array[bar]; 
   else
   if(bar < Bars - per)
   {
   for(int i=0;i<len;i++) _tmp[i] = 2*LWMA(array,per/2,bar+i) - LWMA(array,per,bar+i);  
   hma = LWMA(_tmp,len,0); 
   }  

   return(hma);
}
// MA_Method=9: ZeroLagEMA - Zero-Lag Exponential Moving Average
double ZeroLagEMA(double& price[],double prev,int per,int bar)
{
   double alfa = 2.0/(1+per); 
   int lag = 0.5*(per - 1); 
   
   if(bar >= Bars - lag) double zema = price[bar];
   else 
   zema = alfa*(2*price[bar] - price[bar+lag]) + (1-alfa)*prev;
   
   return(zema);
}
// MA_Method=10: DEMA - Double Exponential Moving Average by Patrick Mulloy
double DEMA(int index,int num,double price,double per,double v,int bar)
{
   double alpha = 2.0/(1+per);
   if(bar == Bars - 2) {double dema = price; tmp[num][index][0] = dema; tmp[num+1][index][0] = dema;}
   else 
   if(bar <  Bars - 2) 
   {
   tmp[num  ][index][0] = tmp[num  ][index][1] + alpha*(price              - tmp[num  ][index][1]); 
   tmp[num+1][index][0] = tmp[num+1][index][1] + alpha*(tmp[num][index][0] - tmp[num+1][index][1]); 
   dema                 = tmp[num  ][index][0]*(1+v) - tmp[num+1][index][0]*v;
   }
   
   return(dema);
}
// MA_Method=11: T3 by T.Tillson
double T3_basic(int index,int num,double price,int per,double v,int bar)
{
   double dema1, dema2;
   if(bar == Bars - 2) 
   {
   double T3 = price; 
   for(int k=0;k<6;k++) tmp[num+k][index][0] = T3;
   }
   else 
   if(bar < Bars - 2) 
   {
   dema1 = DEMA(index,num  ,price,per,v,bar); 
   dema2 = DEMA(index,num+2,dema1,per,v,bar); 
   T3    = DEMA(index,num+4,dema2,per,v,bar);
   }
   return(T3);
}
// MA_Method=12: ITrend - Instantaneous Trendline by J.Ehlers
double ITrend(double& price[],double& array[],int per,int bar)
{
   double alfa = 2.0/(per+1);
   if(bar < Bars - 7)
   double it = (alfa - 0.25*alfa*alfa)*price[bar] + 0.5*alfa*alfa*price[bar+1] - (alfa - 0.75*alfa*alfa)*price[bar+2] +
   2*(1-alfa)*array[1] - (1-alfa)*(1-alfa)*array[2];
   else
   it = (price[bar] + 2*price[bar+1] + price[bar+2])/4;
   
   return(it);
}
// MA_Method=13: Median - Moving Median
double Median(double& price[],int per,int bar)
{
   double array[];
   ArrayResize(array,per);
   
   for(int i = 0; i < per;i++) array[i] = price[bar+i];
   ArraySort(array);
   
   int num = MathRound((per-1)/2); 
   if(MathMod(per,2) > 0) double median = array[num]; else median = 0.5*(array[num]+array[num+1]);
    
   return(median); 
}
// MA_Method=14: GeoMean - Geometric Mean
double GeoMean(double& price[],int per,int bar)
{
   if(bar < Bars - per)
   { 
   double gmean = MathPow(price[bar],1.0/per); 
   for(int i = 1; i < per;i++) gmean *= MathPow(price[bar+i],1.0/per); 
   }
   
   return(gmean);
}
// MA_Method=15: REMA - Regularized EMA by Chris Satchwell 
double REMA(double price,double& array[],int per,double lambda,int bar)
{
   double alpha =  2.0/(per + 1);
   if(bar >= Bars - 3) double rema = price;
   else 
   rema = (array[1]*(1+2*lambda) + alpha*(price - array[1]) - lambda*array[2])/(1+lambda); 
   
   return(rema);
}
// MA_Method=16: ILRS - Integral of Linear Regression Slope 
double ILRS(double& price[],int per,int bar)
{
   double sum = per*(per-1)*0.5;
   double sum2 = (per-1)*per*(2*per-1)/6.0;
     
   double sum1 = 0;
   double sumy = 0;
      for(int i=0;i<per;i++)
      { 
      sum1 += i*price[bar+i];
      sumy += price[bar+i];
      }
   double num1 = per*sum1 - sum*sumy;
   double num2 = sum*sum - per*sum2;
   
   if(num2 != 0) double slope = num1/num2; else slope = 0; 
   double ilrs = slope + SMA(price,per,bar);
   
   return(ilrs);
}
// MA_Method=17: IE/2 - Combination of LSMA and ILRS 
double IE2(double& price[],int per,int bar)
{
   double ie = 0.5*(ILRS(price,per,bar) + LSMA(price,per,bar));
      
   return(ie); 
}
 
// MA_Method=18: TriMAgen - Triangular Moving Average Generalized by J.Ehlers
double TriMA_gen(double& array[],int per,int bar)
{
   int len1 = MathFloor((per+1)*0.5);
   int len2 = MathCeil((per+1)*0.5);
   double sum=0;
   for(int i = 0;i < len2;i++) sum += SMA(array,len1,bar+i);
   double trimagen = sum/len2;
   
   return(trimagen);
}

// MA_Method=19: VWMA - Volume Weighted Moving Average 
double VWMA(double& array[],int per,int bar)
{
   double Sum = 0;
   double Weight = 0;
   
      for(int i = 0;i < per;i++)
      { 
      Weight+= Volume[bar+i];
      Sum += array[bar+i]*Volume[bar+i];
      }
   if(Weight>0) double vwma = Sum/Weight;
   else vwma = 0; 
   return(vwma);
} 

// MA_Method=20: JSmooth - Smoothing by Mark Jurik
double JSmooth(int index,int num,double price,int per,double pow,int bar)
{
   double beta = 0.45*(per-1)/(0.45*(per-1)+2);
	double alpha = MathPow(beta,pow);
	if(bar == Bars - 2) {tmp[num+4][index][0] = price; tmp[num+0][index][0] = price; tmp[num+2][index][0] = price;}
	else 
   if(bar <  Bars - 2) 
   {
	tmp[num+0][index][0] = (1-alpha)*price + alpha*tmp[num+0][index][1];
	tmp[num+1][index][0] = (price - tmp[num+0][index][0])*(1-beta) + beta*tmp[num+1][index][1];
	tmp[num+2][index][0] = tmp[num+0][index][0] + tmp[num+1][index][0];
	tmp[num+3][index][0] = (tmp[num+2][index][0] - tmp[num+4][index][1])*MathPow((1-alpha),2) + MathPow(alpha,2)*tmp[num+3][index][1];
	tmp[num+4][index][0] = tmp[num+4][index][1] + tmp[num+3][index][0]; 
   }
   return(tmp[num+4][index][0]);
}

// MA_Method=21: SMA_eq     - Simplified SMA
double SMA_eq(double& price[],double& array[],int per,int bar)
{
   if(bar == Bars - per) double sma = SMA(price,per,bar);
   else 
   if(bar <  Bars - per) sma = (price[bar] - price[bar+per])/per + array[1]; 
   
   return(sma);
}                        		

// MA_Method=22: ALMA by Arnaud Legoux / Dimitris Kouzis-Loukas / Anthony Cascino
double ALMA(double& price[],int per,double offset,double sigma,int bar)
{
   double m = MathFloor(offset * (per - 1));
	double s = per/sigma;
		
	double w, sum =0, wsum = 0;		
	for (int i=0;i < per;i++) 
	{
	w = MathExp(-((i - m)*(i - m))/(2*s*s));
   wsum += w;
   sum += price[bar+(per-1-i)] * w; 
   }
   
   if(wsum != 0) double alma = sum/wsum; 
   
   return(alma);
}   

// MA_Method=23: TEMA - Triple Exponential Moving Average by Patrick Mulloy
double TEMA(int index,double price,int per,double v,int bar)
{
   double alpha = 2.0/(per+1);
	
	if(bar == Bars - 2) {tmp[0][index][0] = price; tmp[1][index][0] = price; tmp[2][index][0] = price;}
	else 
   if(bar <  Bars - 2) 
   {
	tmp[0][index][0] = tmp[0][index][1] + alpha *(price     - tmp[0][index][1]);
	tmp[1][index][0] = tmp[1][index][1] + alpha *(tmp[0][index][0] - tmp[1][index][1]);
	tmp[2][index][0] = tmp[2][index][1] + alpha *(tmp[1][index][0] - tmp[2][index][1]);
	tmp[3][index][0] = tmp[0][index][0] + v*(tmp[0][index][0] + v*(tmp[0][index][0]-tmp[1][index][0]) - tmp[1][index][0] - v*(tmp[1][index][0] - tmp[2][index][0])); 
	}
   
   return(tmp[3][index][0]);
}

// MA_Method=24: T3 by T.Tillson (correct version) 
double T3(int index,int num,double price,int per,double v,int bar)
{
   double len = MathMax((per + 5.0)/3.0-1,1), dema1, dema2;
   
   if(bar == Bars - 2) 
   {
   double T3 = price; 
   for(int k=0;k<6;k++) tmp[num+k][index][0] = T3;
   }
   else 
   if(bar < Bars - 2) 
   {
   dema1 = DEMA(index,num  ,price,len,v,bar); 
   dema2 = DEMA(index,num+2,dema1,len,v,bar); 
   T3    = DEMA(index,num+4,dema2,len,v,bar);
   }
      
   return(T3);
}

// MA_Method=25: Laguerre filter by J.Ehlers
double Laguerre(int index,double price,int per,int order,int bar)
{
   double gamma = 1-10.0/(per+9);
   double aPrice[];
   
   ArrayResize(aPrice,order);
   
   for(int i=0;i<order;i++)
   {
      if(bar >= Bars - order) tmp[i][index][0] = price;
      else
      {
         if(i == 0) tmp[i][index][0] = (1 - gamma)*price + gamma*tmp[i][index][1];
         else
         tmp[i][index][0] = -gamma * tmp[i-1][index][0] + tmp[i-1][index][1] + gamma * tmp[i][index][1];
      
      aPrice[i] = tmp[i][index][0];
      }
   }
   double laguerre = TriMA_gen(aPrice,order,0);  

   return(laguerre);
}

// MA_Method=26:  MD - McGinley Dynamic
double McGinley(double price,double& array[],int per,int bar)
{
   if(bar == Bars - 2) double md = price;
   else 
   if(bar <  Bars - 2) md = array[1] + (price - array[1])/(per*MathPow(price/array[1],4)/2); 

   return(md);
}


bool isNewBar(int tf)
{
   static datetime pTime;
   bool res=false;
   
   if(tf >= 0)
   {
      if (iTime(NULL,tf,0)!= pTime)
      {
      res=true;
      pTime=iTime(NULL,tf,0);
      }   
   }
   else res = true;
   
   return(res);
}

bool BoxAlert(bool cond,string text)   
{      
   string mess = IndicatorName + "("+Symbol()+","+TF + ")" + text;
   
   if (cond && mess != prevmess)
	{
	Alert (mess);
	prevmess = mess; 
	return(true);
	} 
  
   return(false);  
}

bool Pause(int sec)
{
   if(TimeCurrent() >= preTime + sec) {preTime = TimeCurrent(); return(true);}
   
   return(false);
}

void WarningSound(bool cond,int num,int sec,string sound,datetime ctime)
{
   static int i;
   
   if(cond)
   {
   if(ctime != ptime) i = 0; 
   if(i < num && Pause(sec)) {PlaySound(sound); ptime = ctime; i++;}       	
   }
}

bool EmailAlert(bool cond,string text1,string text2,int num)   
{      
   string subj = "New " + text1 +" Signal from " + IndicatorName + "!!!";    
   string mess = IndicatorName + "("+Symbol()+","+TF + ")" + text2;
   
   if (cond && mess != prevemail)
	{
	if(subj != "" && mess != "") for(int i=0;i<num;i++) SendMail(subj, mess);  
	prevemail = mess; 
	return(true);
	} 
  
   return(false);  
}	         

string tf(int timeframe)
{
   switch(timeframe)
   {
   case PERIOD_M1:   return("M1");
   case PERIOD_M5:   return("M5");
   case PERIOD_M15:  return("M15");
   case PERIOD_M30:  return("M30");
   case PERIOD_H1:   return("H1");
   case PERIOD_H4:   return("H4");
   case PERIOD_D1:   return("D1");
   case PERIOD_W1:   return("W1");
   case PERIOD_MN1:  return("MN1");
   default:          return("Unknown timeframe");
   }
}