Effektive Alogrithmen mit minimaler Verzögerung zur Mittelwertbildung: Zur Verwendung in Indikatoren und Expert Advisors

Nikolay Kositsin | 6 April, 2016

Einleitung

Bei mechanischen Handelssystemen, die auf der Grundlage von Indikatoren aufgebaut sind, die wiederum auf irgendwelchen Algorithmen zur Mittelwertbildung basieren, verwenden ihre Entwickler selten mehr als einen Mittelungsalgorithmus. In vielen Fällen, wenn ein EA-Algorithmus auf einfache Bewegungen und Indikatoren basiert, die im Indikatoren-Standardset des MetaTrader 4 Terminals enthalten sind, werden nur vier Standard-Algorithmen eingesetzt: einfache (simple), exponentielle (exponential), glatte (smoothed) und linear gewichtete (linear-weighted) Mittelwertbildung. Ein solcher Ansatz schränkt die Möglichkeiten eines Expert Advisors doch recht stark ein.

Ein und dasselbe Handelssystem kann durch die Verwendung unterschiedlicher Mittelungsalgorithmen erhebliche Unterschiede bei den Handelsergebnissen aufweisen. Und es ist unmöglich, im voraus zu sagen, welcher der verfügbaren Algorithmen die maximale Rentabilität eines Handelssystems zeigen wird. Es ist daher sinnvoll, einen Code mit der Möglichkeit zu schreiben, komplett unterschiedliche Mittelungsalgorithmen zu verwenden, die durch das Ändern der Werte von externen Variablen eines Expert Advisors gewählt werden können. Als Ergebnis eines solchen Ansatzes, ersetzen wir die Indikatoren, die von einem Expert Advisor verwendet werden, durch unsere eigenen mit einer flexibleren Einstellung hinsichtlich der Auswahl von Mittelungsalgorithmen. Somit kann ein solcher Ansatz in drei Stufen unterteilt werden:

1. Wir schreiben einen Code von einem Expert Advisor, der auf Standard-Bewegungen und Indikatoren basiert, die im Set der technischen Indikatoren im MetaTrader 4 Kundenterminal enthalten sind.
2. Wir schreiben individuelle Indikatoren gemäß der Beschreibungen der Standardindikatoren mit der Möglichkeit eines flexibleren Austausches der Glättungsalgorithmen.
3. Wir ersetzen Signale von technischen Indikatoren durch Signale von diesen individuellen Indikatoren durch Extrahieren der externen Parameter dieser Indikatoren in die externen Variablen des Expert Advisors.


In diesem Artikel möchte ich näher auf universellere Indikatoren eingehen, bei denen (wenn man das so sagen kann) die Agorithmen zur Mittelwertbildung ersetzt werden können. Der Artikel ist die Fortsetzung von "Effektive Algorithmen zur Mittelwertbildung mit minimaler Verzögerung: Einsatz in Indikatoren", daher wird empfohlen, den vorherigen Artikel sorgfältig zu studieren, bevor Sie diesen hier lesen.

Die universelle Funktion zur Mittelwertbildung

In meinem vorigen Artikel habe ich Ihnen fünf Funktionen der Mittelwertbildung vorgestellt. Ich möchte dieser Liste gerne eine weitere Funktion hinzufügen - MASeries() mit klassischen Algorithmen zur Mittelwertbildung:

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

Hinsichtlich ihrer Verwendung ist diese Funktion absolut analog zu den bisherigen fünf Funktionen. Der Code der Funktion ist diesem Artikel angehängt - MASeries.mqh.

Auf der Grundlage dieser sechs Funktionen können wir jetzt eine universelle Funktion zur Mittelwertbildung bauen, die ich SmoothXSeries() genannt und in der Datei SmoothXSeries.mqh platziert habe. Wie auch bei den bisherigen Funktionen, ist es der Befehl #include < >:

#include <SmoothXSeries.mqh>

Hinsichtlich der externen Variablen ist diese Funktion analog zu JJMASeries(), aber es gibt eine neue Variable zur Glättung des Algorithmusfinders - SmoothMode:

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

Die Auswahl des erforderlichen Mittelungsalgorithmus erfolgt durch die Veränderung des SmoothMode Parameterwerts von Null bis Acht:

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

Normalerweise werden die Variablen din und Phase nur für diese Mittelungsalgorithmen angewendet, für die sie ursprünglich definiert wurden. Bevor diese Funktion in einem Indikator verwendet wird, sollten die Variablen dieser Funktion initialisiert werden und ihnen Speicher zugewiesen werden. Um dies zu tun, rufen Sie im Indikator Initialiserungsblock die Funktion SmoothXSeriesResize() auf. Verwenden Sie als Wert für ihre externe variable Größe die Anzahl der SmoothXSeries() Funktionsaufrufe im Indikator-Code.

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

Jetzt, wo wir den universellen Algorithmus zur Mittelwertbildung, SmoothXSeries() haben, können wir damit beginnen, den Code der Indikatoren zu schreiben.

Die universelle Verschiebung

Jede Verschiebung entsteht durch die Glättung einer Preiszeitreihe. Im vorigen Artikel habe ich über die PriceSeries() Funktion zur Auswahl von Werten aus einem Kursverlauf einer Zeitreihe geschrieben. Die Aufgabe besteht darin, diese Werte der Kursverläufe durch die Funktion SmoothXSeries() zu verarbeiten und sie an einen Indikator-Puffer zu übergeben. Hier ist die Variante der Code-Implementierung:

/*
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 diesem Indikator wird der Mittelungsalgorithmus gewählt, indem der Wert der Smooth_Mode Variablen geändert wird.

Die universelle Verschiebung mit der Nutzung einer doppelten Mittelwertbildung

Die Effizienz beim Arbeiten mit einer solchen Verschiebung kann erheblich verbessert werden, wenn wir mit Hilfe der SmoothXSeries() Funktion die zusätzliche Mittelwertbildung vom erhaltenen Indikator durchführen.

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

Natürlich weist der finale Indikator im Vergleich zum ursprünglichen eine kleine Verzögerung auf, aber die Anzahl von Fehlalarmen, die durch eine solche Verschiebung ausgelöst werden, wird viel niedriger sein, was für die Verzögerung entschädigt.

Dieser Indikator kann durch die Umwandlung in eine fortlaufende Reihe von Werten, die er in einem Quantum (eigenständig) abrufen kann, verbessert werden. Ein einfacher Algorithmus wird für diesen Zweck verwendet:

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

Die Variable Step ist ein externer Parameter in ganzen Schritten des Indikators, der je nach Ermessen den Schritt der Wete der erhaltenen Verschiebung in Punkten definiert. Ich werde dessen Code nicht im Artikel anführen - Sie können ihn sehen, wenn Sie den Indikator X2DigMa.mq4 verwenden, der dem Artikel angefügt ist.

Praktische Empfehlungen für die Optimierung von Expert Advisors, die den X2DigMa.mq4 Indikator verwenden

Diese Verschiebung verfügt über eine große Anzahl von externen Variablen, was der Grund dafür ist, dass jeder Expert Advisor, der auf der Grundlage dieses Indikators arbeitet, recht gut an jeden Markt angepasst werden kann. Allerdings ist die formale Anpassung der EA-Paramter nicht der optimalste Weg hinsichtlich der Programmierung für den weiteren Betrieb. Richten wir unseren Blick auf die Details, wenn es um das Arbeiten mit externen Variablen einer solchen Verschiebung in einem Expert Advisor geht. Nehmen wir an, dass wir einen EA haben, in dem alle externen Variablen des X2DigMA.mq4 Indikators aus externen Variablen des Expert Advisors stammen.

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;

Die Variable Smooth_Mode1 akzeptiert Werte von Null bis Acht, aber ich empfehle, den Wert dieser Variable nicht mit einem genetischen Algorithmus zu optimieren. Es ist besser, acht unabhängige Optimierungen für jeden einzelnen Wert dieser Variable durchzuführen. Der Wert der analogen Variable für eine wiederholte Glättung, Smooth_Mode2, sollte besser mit dem Wert Null fixiert werden. In einem solchen Fall wird der JAM Mittelungsalgorithmus als eine wiederholte Glättung verwendet werden. Dieser Algorithmus hat nur eine minimale Verzögerung und bringt in vielen Fällen die besten Ergebnisse bei der zusätzlichen Mittelwertbildung.

Die Parameter Phase1 und Phase2, die nur in der JMA Serie und T3 Serie zur Mittelwertbildung verwendet werden, sollten besser mit dem Wert 100 fixiert werden. Der Parameter Length2 kann jeden Wert annehmen, aber in vielen Situationen und in absolut verschiedenen EAs, sind die optimalsten Werte dafür jene aus der Zahlenreihe 3, 5, 7, 9, 11. Die Verwendung dieser Werte für den Parameter Length2 reicht als einzige Regel aus. Der Parameter Step hängt stark vom Markt ab, in dem der EA arbeitet sowie auch von der Chart-Periode; allerdings werden meistens die gleichen Werte verwendet. Die besten Werte für den Parameter Input_Price_Customs sind in der Regel Null und Neun. Im Rahmen unserer Analyse ist jetzt nur mehr ein Parameter übrig - Length1; sein Wert kann unterschiedlich sein.

Das universelle MACD Diagramm

Mit der von mir angebotenen Funktion SmoothXSeries() können Sie einen beliebigen Indikator für die klassische technische Analyse bauen. Zum Beispiel ein MACD Diagramm, das ein Diagramm von zwei Indikatoren ist. Der erste ist ein Chart, der die Differenz zwischen zwei Verschiebungen anzeigt; der zweite ist ein gleitender Mittelwert (Moving Average) dieser Differenz.

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

Die Logik beim Arbeiten mit solch einem Indikator in einem Expert Advisor ist in vielerlei Hinsicht analog zu dem, was ich oben geschrieben habe, aber in diesem Fall sollte der Wert der Variable Signal_Mode einer genetischen Optimierung unterzogen werden.

Fazit

Durch die Verwendung der Funktion SmoothXSeries(), mit der Sie jeden Indikator für die technische Analyse bauen können, scheinen die Möglichkeiten höher zu sein als bei jenen ihrer klassischen analogen. Natürlich erfordert dies eine gewisse Erfahrung beim Schreiben von Indikatoren, aber das Endergebnis ist die Anstrengung auf jeden Fall wert.