Promediación efectiva de algoritmos con retraso mínimo: Uso en indicadores y en Asesores Expertos

Nikolay Kositsin | 4 mayo, 2016


Introducción

En los sistemas de trading mecánicos construidos en base a los indicadores que están basados en cualquier algoritmo de promediación, los desarrolladores rara vez utilizan más de un algoritmo de promediación. En muchos casos, si el algoritmo de un AE está basado en movimientos simples y los indicadores están incluidos en el grupo estándar de los indicadores de la terminal MetaTrader 4, sólo se utilizan cuatro algoritmos estándar: promediación simple, exponencial, suavizada, y ponderada-lineal. Un método así limita mucho las posibilidades de un Asesor Experto.

Un único sistema de trading con el uso de diferentes algoritmos de promediación pueden mostrar diferencias importantes en los resultados del trading. Y es imposible decir con antelación qué algoritmo de los que hay disponibles mostrará la rentabilidad máxima de un sistema de trading. Por lo tanto, es más razonable escribir un código con la posibilidad de utilizar un algoritmos de promediación completamente diferente que se puede elegir cambiando los valores de las variables externas de un AE. Como resultado de un método así, se remplazan los indicadores utilizados por el AE por los propios del usuario con una configuración de selección de algoritmos de promediación más flexible. Por lo tanto, un método de este tipo puede dividirse en tres etapas:

1. Se escribe un código de un Asesor Experto basado en los movimientos estándar y en los indicadores incluidos en el conjunto de indicadores técnicos de la terminal de cliente de MetaTrader 4.
2. Se escriben indicadores personalizados según las descripciones de los indicadores estándar con la posibilidad de una sustitución más flexible de los algoritmos suavizados.
3. Reemplazamos las llamadas de los indicadores técnicos con las llamadas de estos indicadores personalizados con la extracción de parámetros externos de estos indicadores en las variables externas del AE.


En este artículo me gustaría hablar más de los indicadores universales con la posibilidad (si se puede llamar así) de una sustitución en caliente de los algoritmos de promediación que se utilizan en estos indicadores. El artículo es la continuación de Algoritmos de promediación efectivos con Minimal Lag: Uso en indicadores", por lo que antes de leer este artículo, se recomienda estudiar con detenimiento el artículo anterior.

La función universal de la promediación

En mi artículo anterior, introduje cinco funciones de promediación. Me gustaría añadir una función más en esta lista: MASeries(), con los algoritmos clásicos de promediación.

double MASeries
(
  int number, int MA_Method, int MaxBar, int limit, int period, double series, int bar, int& reset
)

En cuanto a su uso, esta función es completamente análoga a las otras cinco funciones. El código de la función se adjunta al artículo: MASeries.mqh.

Ahora, en base a estas seis funciones, se puede construir una función universal de promediación a la que llamé SmoothXSeries() y la coloqué en el archivo SmoothXSeries.mqh. Como las funciones anteriores, esta es #include< > directive:

#include <SmoothXSeries.mqh>

En términos de variables externas esta función es análoga a JJMASeries(), pero hay una nueva variable de suavización del identificador del algoritmo:

double SmoothXSeries
(
  int number,int SmoothMode, int din, int MaxBar, int limit, int Phase, int Length, double Series, int bar, int& reset
)

La selección de los algoritmos de promediación necesarios se realiza con la variación del valor del parámetro SmoothMode de cero a ocho.

  // 0 : JJMA
  // 1 : JurX        
  // 2 : ParMA
  // 3 : LRMA
  // 4 : T3
  // 5 : SMA
  // 6 : EMA
  // 7 : SSMA
  // 8 : LWMA

Naturalmente, las variables din y Phase, se aplican sólo para aquellos algoritmos de promediación para los que estaban definidos inicialmente. Antes de utilizar esta función en un código de indicador, se tienen que iniciar sus variables y la memoria tiene que estar asignada a ellas. Para ello, al inicio del bloque del indicador, llame a la función SmoothXSeriesResize(). Ya que el valor de la variable externa Size utiliza el número de llamadas a la función SmoothXSeries(), en el código del indicador.

  //Ten calls of the SmoothXSeriesResize() function in the indicator code
  SmoothXSeriesResize(10);

Ahora que se tiene el algoritmo universal de promediación de SmoothXSeries(), se puede empezar a escribir el código de indicadores.

El movimiento universal

Cualquier movimiento se obtiene con la suavización de series temporales de precio. En el artículo anterior, escribí sobre la función PriceSeries() para seleccionar los valores de una fila de precios de una serie temporal. La tarea de construcción de un movimiento la realizan en realidad estos valores de las series de precios mediante la función SmoothXSeries(), y pasándolas al búfer de un indicador. Aquí está la variante del código de implementación:

/*
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+

En este indicador, el algoritmo de promediación se elige cambiando el valor de la variable Smooth_Mode.

El movimiento universal con el uso de una promediación doble

La eficacia del trabajo con un movimiento así se puede mejorar considerablemente si se realiza una promediación adicional del indicador obtenido mediante la misma función SmootXSeries().

/*
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+

El indicador final tendrá un pequeño retraso comparado con el original, pero el número de alertas falsas recibidas por un movimiento así será mucho más bajo, lo que compensa el retraso.

Este indicador se puede mejorar girándolo hacia la serie continua de los valores puede obtener en uno discreto. Para esto se utiliza un algoritmo simple:

       //----+ normalizing the obtained value x2ma
       double Norma = Step * Point;
       //----
       x2ma /= Norma;
       x2ma = NormalizeDouble(x2ma, 0);
       x2ma *= Norma;

La variable Step es todo un parámetro externo del indicador, que define el step de discreción de los valores del movimiento obtenido en puntos. No incluiré su código en el artículo: puede verlo utilizando el indicador X2DigMa.mq4 adjunto en el artículo.

Recomendaciones prácticas para la optimización de Asesores Expertos que utilizan el indicador X2DigMa.mq4

Este movimiento tiene un gran número de variables externas, es por eso que cualquier Asesor Experto hecho en base a este indicador puede ajustarse bastante bien a cualquier mercado. Sin embargo, el ajuste formal de los parámetros del AE no es lo más adecuado de su programación para futuras operaciones. Vamos a hablar de los detalles de trabajar con variables externas de un movimiento así en un Asesor Experto. Suponga que tiene un AE en el que todas las variables externas de los movimientos de X2DigMA.mq4 se convierten en variables externas del AE.

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;

La variable Smooth_Mode1 acepta los valores de cero a ocho, pero no recomiendo la optimización del valor de esta variable en un tester utilizando un algoritmo genérico. Es mejor realizar ocho optimizaciones independientes para cada valor de esta variable. Sería mejor fijar en cero el valor de la variable análoga para una suavización repetida de Smooh_Mode2 . En este caso, el algoritmo de promediación de JMA se utilizará como una suavización repetida. Este algoritmo tiene el lag mínimo y proporciona los mejores resultados como promediación adicional en muchos casos.

Los parámetros Phase1 y Phase2 que sólo se utilizan en la serie JMA y T3 deberían fijarse en 100. El parámetro Lenght2 puede tener cualquier valor, pero en muchas situaciones y en AEs completamente diferentes, las mejores tienen, a menudo, los mismos valores de las series 3, 5, 7, 9, 11. Por norma general, el uso de estos valores del parámetro Lenght2 es suficiente. El parámetro Step depende mucho del mercado en el que funciona el AE, y en el periodo del gráfico; sin embargo, a menudo se estabiliza con los mismos valores. Los mejores valores de los parámetros Input_Price_Customs son normalmente cero y nueve. Como resultado de una investigación profunda, sólo queda un parámetro: Lenght1; sus valores pueden ser diferentes.

El diagrama universal MACD

Utilizando la función SmoothXSeries() que les he ofrecido, pueden construir cualquier indicador del análisis técnico clásico, por ejemplo el diagrama MACD, que es un gráfico de dos indicadores. El primero es un diagrama de la diferencia entre dos movimientos; el segundo es un movimiento promedio de esta diferencia.

/*
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+

La lógica de trabajar con este indicador en un Asesor Experto es análoga en muchos aspectos a lo que he escrito arriba, pero en este caso, el valor de la variable Signal_Moder debería recibir una optimización genética.

Conclusión

Utilizando la llamada de la SmoothXSeries() puede construir cualquier indicador del análisis técnico, cuyas posibilidades, a menudo parecen ser más altas que aquellas de su análogo clásico. Por supuesto, es necesaria tener alguna experiencia en la escritura de indicadores, pero el resultado final merece todos los esfuerzos.