Effective Averaging Algorithms with Minimal Lag: Use in Indicators and Expert Advisors

Nikolay Kositsin | 22 April, 2009


Introduction

In mechanical trading systems built on the basis of indicators that are based on any averaging algorithms, their developers rarely use more than one averaging algorithm. In many cases, if an EA algorithm is based on simple movings and indicators that are included into the standard set of indicators of the MetaTrader 4 terminal, only four standard algorithms are used: simple, exponential, smoothed and linear-weighted averaging. Such an approach very much limits possibilities of an Expert Advisor.

One and the same trading system with the use of different averaging algorithms can show substantial differences in trading results. And it is impossible to say beforehand which of the available algorithms will show the maximum profitability of a trading system. So it is more reasonable to write a code with the possibility of using absolutely different averaging algorithms that can be chosen by changing values of external variables of an EA. As the result in such an approach we replace indicators used by an EA by our own ones with a more flexible setting of averaging algorithm selection. Thus, such an approach can be divided into three stages:

1. We write a code of an Expert Advisor based on standard movings and indicators included into the set of technical indicators in MetaTrader 4 client terminal.
2. We write custom indicators according to descriptions of standard indicators with the possibility of a more flexible replacement of smoothing algorithms.
3. We replace calls of technical indicators by calls of these custom indicators with extracting of external parameters of these indicators into external variables of the EA.


In this article I would like to dwell on more universal indicators with the possibility (if this can be said so) of a hot replacement of averaging algorithms that are used in these indicators. The article is the continuation of "Effective Averaging Algorithms with Minimal Lag: Use in Indicators", so before reading this one it is recommended to carefully study the previous article.

The Universal Function of Averaging

In my previous article I introduced to you five functions of averaging. I would like to add one more function into this list - MASeries() with classical algorithms of averaging:

double MASeries
(
  int number, int MA_Method, int MaxBar, int limit, int period, double series, int bar, int& reset
)
As of its usage, this function is absolutely analogous to the previous five functions. The code of the function is attached to the article - MASeries.mqh.

Now on the basis of these six functions we can build a universal function of averaging which I called SmoothXSeries() and placed in the file SmoothXSeries.mqh. Like previous functions, this one is #include < > directive:

#include <SmoothXSeries.mqh>
In terms of external variables this function is analogous to JJMASeries(), but there is a new variable of smoothing algorithm identifier - SmoothMode:
double SmoothXSeries
(
  int number,int SmoothMode, int din, int MaxBar, int limit, int Phase, int Length, double Series, int bar, int& reset
)

Selection of the required averaging algorithm is performed by the variation of the value of the SmoothMode parameter from zero to eight:

  // 0 : JJMA
  // 1 : JurX        
  // 2 : ParMA
  // 3 : LRMA
  // 4 : T3
  // 5 : SMA
  // 6 : EMA
  // 7 : SSMA
  // 8 : LWMA
Naturally, variables din and Phase are applied only for those averaging algorithms, for which they were initially defined. Before using this function in an indicator code, variables of this function should be initialized and memory should be allocated for them. In order to do this, in the indicator initialization block make a call to the SmoothXSeriesResize() function. As the value of its external variable Size use the number of the SmoothXSeries() function calls in the indicator code.
  //Ten calls of the SmoothXSeriesResize() function in the indicator code
  SmoothXSeriesResize(10);

Now having the universal algorithm of averaging SmoothXSeries() we can start writing the code of indicators.

The Universal Moving

Any moving is obtained by the smoothing of a price timeseries. In the previous article I wrote about the PriceSeries() function for selecting values of a price row of a timeseries. The task of building a moving is actually processing these values of the price series by the SmoothXSeries() function and passing them into an indicator buffer. Here is the variant of code implementation:

/*
For the operation of the indicator the files

SmoothXSeries.mqh
T3Series.mqh
MASeries.mqh
LRMASeries.mqh
JurXSeries.mqh
ParMASeries.mqh
JJMASeries.mqh 
PriceSeries.mqh 
should be located in  the directory: MetaTrader\experts\include\

Heiken Ashi#.mq4
should be located in the directory: MetaTrader\indicators\
*/
//+X================================================================X+  
//|                                                         X1MA.mq4 | 
//|                        Copyright © 2009,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+X================================================================X+   
#property copyright "Copyright © 2009, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing the indicator in the main window
#property indicator_chart_window 
//---- number of indicator buffers
#property indicator_buffers 1 
//---- color of the indicator
#property indicator_color1 Red
//---- INPUT PARAMETERS OF THE INDICATOR +--------------------------------------------+
extern int Smooth_Mode = 0;   // Choosing the smoothing algorithm 0 - JJMA, 1 - JurX,        
                 // 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int Length = 11;   // depth of smoothing
extern int Phase  = 100; // parameter changing in limits -100 ... +100, 
                                       //influences the quality of the transient process; 
extern int Shift  = 0;   // indicator shift along the time axis
extern int Input_Price_Customs = 0; /* Selecting prices, upon which the calculation of
the indicator is performed (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */
//---- +------------------------------------------------------------------------------+
//---- buffers
double XMA[]; 
//---- variables
bool INIT;
int  StartBar;
//+X================================================================X+   
//| SmoothXSeries() function                                         |
//+X================================================================X+    
//----+ Declaring the function SmoothXSeries
//----+ Declaring the function SmoothXSeriesResize 
//----+ Declaring the function SmoothXSeriesAlert   
#include <SmoothXSeries.mqh> 
//+X================================================================X+   
//| PriceSeries() function                                           |
//+X================================================================X+    
//----+ Declaring the function PriceSeries
//----+ Declaring the function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+X================================================================X+   
//| X1MA initialization function                                     |
//+X================================================================X+ 
int init() 
{ 
//----+
   //---- setting the style of the indicator presentation 
   SetIndexStyle(0, DRAW_LINE); 
   //---- defining a buffer for calculations 
   SetIndexBuffer(0, XMA);
   //---- setting the values of the indicator that will not be visible on the chart
   SetIndexEmptyValue(0, 0.0);  
   //---- setting alerts for not allowed values of external variables
   JJMASeriesAlert (0, "Length", Length);
   JJMASeriesAlert (1, "Phase",   Phase);
   PriceSeriesAlert(Input_Price_Customs);
   //----+ Changing sizes of buffer variables of the function
           //SmoothXSeries, number = 1(One call of the SmoothXSeries function)
   if (SmoothXSeriesResize(1) != 1)
    {
     INIT = false;
     return(0);
    }
   //---- initialization of variables
   if (Smooth_Mode > 0 && Smooth_Mode < 9) 
                              StartBar = Length;
   else StartBar = 30;
   //---- setting the bar number,
                     //starting from which the indicator will be drawn 
   SetIndexDrawBegin(0, StartBar); 
   //---- Setting the format of accuracy of the indicator drawing
   IndicatorDigits(Digits);
   //---- end of initialization
   INIT = true;
   return(0);
//----+ 
}
//+X================================================================X+  
//| X1MA iteration function                                          | 
//+X================================================================X+   
int start()
{
//----+ 
   //---- Getting the number of all bars
   int Bars_ = Bars - 1;
//---- checking the initialization end and 
     //checking if the number of bars is enough for calculation
if (!INIT || Bars_ <= StartBar)
                  return(-1); 
//---- Introducing variables with a floating point
double Price, xma;
//---- Introducing integer variables and obtaining the number 
                           //of already calculated bars
int reset, MaxBar, limit, bar, counted_bars = IndicatorCounted();
//---- checking for possible errors
if (counted_bars < 0)
    return(-1);
//---- the last calculated bar must be recalculated
if (counted_bars > 0)
counted_bars--;
//---- defining the number of the oldest bar, 
//starting from which new bars will be recalculated 
limit = Bars_ - counted_bars;
//---- defining the number of the oldest bar, 
//starting from which all bars will be recalculated 
MaxBar = Bars_;
//----+ the main cycle of the indicator calculation
for(bar = limit; bar >= 0; bar--)
{
  //---- Getting the initial value of the price series
  Price = PriceSeries(Input_Price_Customs, bar);
  //---- X1MA smoothing of the initial value of the price series 
  //---- Call of the SmoothXSeries function number 0, 
//parameters Phase and Length are not changed at each bar (din = 0)
  xma = SmoothXSeries(0, Smooth_Mode, 0, MaxBar, limit, 
                                     Phase, Length, Price, bar, reset);
  //---- checking that there are no errors in the previous operation
  if(reset != 0)
  return(-1);
  
  XMA[bar] = xma;
  //----
}
//---- end of the indicator values calculation
return(0); 
//----+  
} 
//+X--------------------+ <<< The End >>> +--------------------X+
In this indicator the averaging algorithm is chosen by changing the value of the Smooth_Mode variable.

The Universal Moving with the Use of a Double Averaging

The efficiency of working with such a moving can be considerably improved, if we perform the additional averaging of the obtained indicator by the same SmoothXSeries() function

/*
For the operation of the indicator the files 

SmoothXSeries.mqh
T3Series.mqh
MASeries.mqh
LRMASeries.mqh
JurXSeries.mqh
ParMASeries.mqh
JJMASeries.mqh 
PriceSeries.mqh 
should be located in the directory: MetaTrader\experts\include\

Heiken Ashi#.mq4
should be located in the directory: MetaTrader\indicators\
*/
//+X================================================================X+  
//|                                                         X2MA.mq4 | 
//|                        Copyright © 2009,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+X================================================================X+   
#property copyright "Copyright © 2009, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing the indicator in the main window
#property indicator_chart_window 
//---- number of indicator buffers
#property indicator_buffers 1 
//---- color of the indicator
#property indicator_color1 Lime
//---- INPUT PARAMETERS OF THE INDICATOR +---------------------------------------------+
extern int Smooth_Mode1 = 0;   // Choosing the 1st smoothing algorithm 0 - JJMA, 1 - JurX,        
                 // 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int Length1 = 9;   // depth of smoothing 
extern int Phase1  = 100; // parameter changing in limits -100 ... +100, 
                                       //influences the quality of the transient process;
extern int Smooth_Mode2 = 0;   // Choosing the 2nd smoothing algorithm 0 - JJMA, 1 - JurX,        
                 // 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int Length2 = 5;   // depth of smoothing 
extern int Phase2  = 100; // parameter changing in limits -100 ... +100, 
                                       //influences the quality of the transient process;  
extern int Shift  = 0;   // indicator shift along the time axis 
extern int Input_Price_Customs = 0; /* Selecting prices, upon which the calculation of 
the indicator is performed (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */
//---- +------------------------------------------------------------------------------+
//---- buffers
double X2MA[];
//---- variables  
bool INIT;
int  StartBar, StartBar1, StartBar2;
//+X================================================================X+   
//| SmoothXSeries() function                                         |
//+X================================================================X+    
//----+ Declaring the function SmoothXSeries
//----+ Declaring the function SmoothXSeriesResize 
//----+ Declaring the function SmoothXSeriesAlert   
#include <SmoothXSeries.mqh> 
//+X================================================================X+   
//| PriceSeries() function                                           |
//+X================================================================X+    
//----+ Declaring the function PriceSeries
//----+ Declaring the function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+X================================================================X+   
//| X2MA initialization function                                     |
//+X================================================================X+ 
int init() 
{ 
//----+
   //---- setting the style of the indicator presentation 
   SetIndexStyle(0, DRAW_LINE); 
   //---- defining a buffer for calculations 
   SetIndexBuffer(0, X2MA);
   //---- setting the values of the indicator that will not be visible on the chart
   SetIndexEmptyValue(0, 0.0); 
   //---- setting alerts for not allowed values of external variables
   JJMASeriesAlert (0, "Length1", Length1);
   JJMASeriesAlert (1, "Phase1",   Phase1);
   JJMASeriesAlert (0, "Length2", Length2);
   JJMASeriesAlert (1, "Phase2",   Phase2);
   PriceSeriesAlert(Input_Price_Customs);
   //----+ Changing sizes of buffer variables of the function
           //SmoothXSeries, number = 2(Two calls of the SmoothXSeries function)
   if (SmoothXSeriesResize(2) != 2)
    {
     INIT = false;
     return(0);
    }
   //---- initialization of variables
   if (Smooth_Mode1 > 0 && Smooth_Mode1 < 9) 
                              StartBar1 = Length1;
   else StartBar1 = 30;
   
   if (Smooth_Mode2 > 0 && Smooth_Mode2 < 9) 
                              StartBar2 = Length2;
   else StartBar2 = 30;
   StartBar = StartBar1 + StartBar2;
   //---- setting the bar number,
                     //starting from which the indicator will be drawn 
   SetIndexDrawBegin(0, StartBar); 
   //---- Setting the format of accuracy of the indicator drawing
   IndicatorDigits(Digits);
   //---- end of initialization
   INIT = true;
   return(0);
//----+ 
}
//+X================================================================X+  
//| X2MA iteration function                                          | 
//+X================================================================X+   
int start()
{
//----+ 
   //---- Getting the number of the last bar
   int Bars_ = Bars - 1;
//---- checking the initialization end and 
     //checking if the number of bars is enough for calculation
if (!INIT || Bars_ <= StartBar)
                  return(-1); 
//---- Introducing variables with a floating point
double Price, x1ma, x2ma;
//---- Introducing integer variables and obtaining the number 
                        //of already calculated bars
int reset, MaxBar1, MaxBar2, limit, 
                   bar, counted_bars = IndicatorCounted();
//---- checking for possible errors
if (counted_bars < 0)
    return(-1);
//---- the last calculated bar must be recalculated
if (counted_bars > 0)
counted_bars--;
//---- defining the number of the oldest bar, 
//starting from which new bars will be recalculated 
limit = Bars_ - counted_bars;
//---- defining the number of the oldest bar, 
//starting from which all bars will be recalculated 
MaxBar1 = Bars_;
MaxBar2 = MaxBar1 - StartBar1;

//----+ the main cycle of the indicator calculation
for(bar = limit; bar >= 0; bar--)
{
  //---- Getting the initial value of the price series
  Price = PriceSeries(Input_Price_Customs, bar);
  //---- X1MA smoothing of the initial value of the price series, 
  //---- Call of the SmoothXSeries function number 0, 
//parameters Phase and Length are not changed at each bar (din = 0)
  x1ma = SmoothXSeries(0, Smooth_Mode1, 0, MaxBar1, limit, 
                                     Phase1, Length1, Price, bar, reset);
  //---- checking that there are no errors in the previous operation
  if(reset != 0)
  return(-1);
  //---- X2MA smoothing of the obtained indicator, 
  //---- Call of the SmoothXSeries function number 1, 
//parameters Phase and Length are not changed at each bar (din = 0)
  x2ma = SmoothXSeries(1, Smooth_Mode2, 0, MaxBar2, limit, 
                                     Phase2, Length2, x1ma,  bar, reset);
  //---- checking that there are no errors in the previous operation
  if(reset != 0)
  return(-1);
  //----      
  X2MA[bar] = x2ma;
  //----
}
//----+ end of the indicator values calculation
return(0); 
//----+  
} 
//+X--------------------+ <<< The End >>> +--------------------X+
Of course, the final indicator will have a little delay as compared to the original one, but the number of false alerts received by such a moving will be much lower which compensates the delay.

This indicator can be improved by turning it into the continuous series of values that it may obtain into a quantal (discrete) one. A simple algorithm is used for this purpose:

       //----+ normalizing the obtained value x2ma
       double Norma = Step * Point;
       //----
       x2ma /= Norma;
       x2ma = NormalizeDouble(x2ma, 0);
       x2ma *= Norma;
The Step variable is a whole external parameter of the indicator, which defines the step of discretion of values of the obtained moving in points. I will not include its code in the article - you can see it using the indicator X2DigMa.mq4 attached to the article.

Practical Recommendations on the Optimization of Expert Advisors that Use the X2DigMa.mq4 Indicator

This moving has a large number of external variables that is why any Expert Advisor made on the basis of this indicator can be quite well adjusted to any market. However, the formal fitting of EA parameters is not the most optimal way of its programming for further operation. Let's dwell on the work details of working with external variables of such a moving in an Expert Advisor. Suppose we have an EA in which all external variables of the moving X2DigMA.mq4 are made external variables of the EA.

extern int Smooth_Mode1 = 0; 
extern int Length1 = 9; 
extern int Phase1  = 100;
extern int Smooth_Mode2 = 0;
extern int Length2 = 5; 
extern int Phase2  = 100;
extern int Step = 10;
extern int Input_Price_Customs = 0;
The Smooth_Mode1 variable accepts values from zero to eight, but I do not recommend optimizing the value of this variable in a tester using a genetic algorithm. It is better to perform eight independent optimizations for each value of this variable. The value of the analogous variable for a repeated smoothing Smooth_Mode2 should be better fixed as equal to zero. In such a case the JMA averaging algorithm will be used as a repeated smoothing. This algorithm has the minimal lag and gives the best results as the additional averaging in many cases.

Parameters Phase1 and Phase2 that are used only in JMA series and T3 series averaging should be better fixed as equal to 100. The Length2 parameter can take any values, but in many situations and in absolutely different EAs the most optimal ones are very often the same values from the series 3, 5, 7, 9, 11. The use of these values of the Length2 parameter is enough as a rule. The Step parameter very much depends on the market, in which the EA operates, and the chart period; however, very often it is stabilized on the same values. The best values of the Input_Price_Customs parameter are usually zero and nine. As a result of thorough investigation only one parameter - Length1 is left; its values can be different.

The Universal MACD Diagram

Using the SmoothXSeries() function offered by me, you can build any indicator of the classical technical analysis, for example MACD diagram which is a chart of two indicators. The first one is a diagram of the difference between two movings; the second one is a moving average of this difference.

/*
For the operation of the indicator the files 

SmoothXSeries.mqh
T3Series.mqh
MASeries.mqh
LRMASeries.mqh
JurXSeries.mqh
ParMASeries.mqh
JJMASeries.mqh 
PriceSeries.mqh 
should be located in  the directory: MetaTrader\experts\include\

Heiken Ashi#.mq4
should be located in  the directory: MetaTrader\indicators\
*/
//+X================================================================X+  
//|                                                        XMACD.mq4 | 
//|                        Copyright © 2009,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+X================================================================X+   
#property copyright "Copyright © 2009, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing the indicator in the main window
#property  indicator_separate_window 
//---- number of indicator buffers
#property indicator_buffers 2 
//---- colors of the indicator
#property  indicator_color1  Blue
#property  indicator_color2  Magenta
//---- width of the diagram line
#property  indicator_width1  2
//---- INPUT PARAMETERS OF THE INDICATOR
extern int MACD_Mode = 0;  // Choosing the smoothing algorithm for MACD 0 - JJMA, 1 - JurX,        
                 // 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int MACD_Phase = 100;
extern int FastXMA = 12;
extern int SlowXMA = 26;
extern int Signal_Mode = 0;  // Choosing the smoothing algorithm for the signal line 
  //0 - JJMA, 1 - JurX, 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int Signal_Phase = 100;
extern int SignalXMA = 9;
extern int Input_Price_Customs = 0; /* Selecting prices, upon which the calculation of 
the indicator is performed (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */
//---- indicator buffers
double     XMacdBuffer[];
double     XSignalBuffer[];
//---- variabless 
bool   INIT;
int    StartBar, StartBar1, StartBar2;
//+X================================================================X+   
//| SmoothXSeries() function                                         |
//+X================================================================X+    
//----+ Declaring the function SmoothXSeries
//----+ Declaring the function SmoothXSeriesResize 
//----+ Declaring the function SmoothXSeriesAlert   
#include <SmoothXSeries.mqh> 
//+X================================================================X+   
//| PriceSeries() function                                           |
//+X================================================================X+    
//----+ Declaring the function PriceSeries
//----+ Declaring the function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+X================================================================X+ 
//| XMACD indicator initialization function                          |
//+X================================================================X+ 
int init()
  {
//----+
   //---- setting the style of the indicator presentation 
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexStyle(1, DRAW_LINE);
   //---- Setting the accuracy format (number of digits 
        //after the decimal point) for the visualization of the indicator values 
   IndicatorDigits(Digits + 1);
   //---- defining buffers for calculation 
   SetIndexBuffer(0, XMacdBuffer);
   SetIndexBuffer(1, XSignalBuffer);
   //---- names for data windows and labels for subwindows
   IndicatorShortName(StringConcatenate
            ("XMACD(", FastXMA, ",", SlowXMA, ",", SignalXMA, ")"));
   SetIndexLabel(0, "XMACD");
   SetIndexLabel(1, "XSignal");
   //---- setting alerts for not allowed values of external variables
   JJMASeriesAlert (0, "FastXMA", FastXMA);
   JJMASeriesAlert (0, "SlowXMA", SlowXMA);
   JJMASeriesAlert (0, "SignalXMA", SignalXMA);
   //----
   JJMASeriesAlert (1, "MACD_Phase", MACD_Phase);  
   JJMASeriesAlert (1, "Signal_Phase", Signal_Phase);
   PriceSeriesAlert(Input_Price_Customs);
   //---- Changing sizes of buffer variables of the function
           //SmoothXSeries, number = 3(Three calls of the SmoothXSeries function)
   if (SmoothXSeriesResize(3) != 3)
    {
     INIT = false;
     return(0);
    }
   //---- initialization of variables 
   if (MACD_Mode > 0 && MACD_Mode < 9) 
                            StartBar1 = MathMax( FastXMA, SlowXMA);
   else StartBar1 = 30;
   //----
   if (Signal_Mode > 0 && Signal_Mode < 9) 
                          StartBar2 = SignalXMA;
   else StartBar2 = 30;
   //----
   StartBar = StartBar1 + StartBar2;
   //----
   SetIndexDrawBegin(0, StartBar1);
   SetIndexDrawBegin(1, StartBar);
   //---- end of initialization
   INIT = true;
   return(0);
//----+
  }
//+X================================================================X+ 
//| XMACD indicator iteration function                               |
//+X================================================================X+ 
int start()
  {
//----+
   //---- Getting the number of the last bat
   int Bars_ = Bars - 1;
//---- checking the initialization end and 
     //checking if the number of bars is enough for calculation
if (!INIT || Bars_ <= StartBar)
                  return(-1); 
//---- Introducing variables with a floating point
double Price, FastXMA_, SlowXMA_, XMACD, SignalXMA_;
//---- Introducing integer variables and obtaining the number 
                        //of already calculated bars
int reset, MaxBar1, MaxBar2, limit, 
                   bar, counted_bars = IndicatorCounted();
//---- checking for possible errors
if (counted_bars < 0)
    return(-1);
//---- the last calculated bar must be recalculated
if (counted_bars > 0)
counted_bars--;
//---- defining the number of the oldest bar, 
//starting from which new bars will be recalculated 
limit = Bars_ - counted_bars;
//---- defining the number of the oldest bar, 
//starting from which all bars will be recalculated 
MaxBar1 = Bars_;
MaxBar2 = MaxBar1 - StartBar1;

   //----+ the main cycle of the indicator calculation
for(bar = limit; bar >= 0; bar--)
{
  //---- Getting the initial value of the price series
  Price = PriceSeries(Input_Price_Customs, bar);
  //---- FastXMA smoothing of the initial value of the price series, 
  //---- Call of the SmoothXSeries function number 0, 
//parameters Phase and Length are not changed at each bar (din = 0)
  FastXMA_ = SmoothXSeries(0, MACD_Mode, 0, MaxBar1, limit, 
                              MACD_Phase, FastXMA, Price, bar, reset);
  //---- checking that there are no errors in the previous operation
  if(reset != 0)
  return(-1);
  //---- SlowXMA smoothing of the initial value of the price series, 
  //---- Call of the SmoothXSeries function number 1, 
//parameters Phase and Length are not changed at each bar (din = 0)
  SlowXMA_ = SmoothXSeries(1, MACD_Mode, 0, MaxBar1, limit, 
                             MACD_Phase, SlowXMA, Price,  bar, reset);                       
  //---- checking that there are no errors in the previous operation
  if(reset != 0)
  return(-1);
  //----   
  if(bar < MaxBar2) 
         XMACD = FastXMA_ - SlowXMA_;
  
  //---- SignalXMA smoothing of the obtained XMACD diagram, 
  //---- Call of the SmoothXSeries function number 2, 
//parameters Phase and Length are not changed at each bar (din = 0)
  SignalXMA_ = SmoothXSeries(2, Signal_Mode, 0, MaxBar2, limit, 
                         Signal_Phase, SignalXMA, XMACD,  bar, reset);            
  //---- checking that there are no errors in the previous operation
  if(reset != 0)
  return(-1);
  //----
  XMacdBuffer[bar] = XMACD;
  XSignalBuffer[bar] = SignalXMA_;   
    }
   return(0);
  
//----+
  }
//+X----------------------+ <<< The End >>> +-----------------------X+
The logics of working with such an indicator in an Expert Advisor is in many aspects analogous to what I have written above, but in this case the value of the Signal_Mode variable should better undergo genetic optimization.

Conclusion

Using call of the SmoothXSeries() function you can build any indicator of the technical analysis, the possibilities of which often appear to be higher than those of its classical analog. Of course, this requires a certain experience in indicator writing, but the final result is worth of all the efforts.