Effektive Mittelwertbildungsalgorithmen mit minimalen Lags und ihre Verwendung in Indikatoren

Nikolay Kositsin | 14 April, 2016

Einleitung

Ich denke, es gibt keine Notwendigkeit zu erklären, wie wichtig die Glättungsalgorithmen für die technische Analyse und für Handelssysteme sind. Es ist genug, nur mal auf einen Code eines Indikators zu gucken, um da explizite oder implizite einen Mittelwertbildungsalgorithmus zu finden. Wenn wir einen genaueren Blick auf Online-Handelsplattformen und Client-Terminals werfen, dann stellen wir fest, dass in meisten von ihnen einfache aber nicht so effektive Mittelwertbildungsalgorithmen verwendet werden, zwar sind aber viele basierend auf diesen Mittelwertbildungsalgorithmen programmiert worden.

Es sind schon momentan viel effektiver Glättungsalgorithmen entwickelt worden. Allerdings der Versuch, sie in Indikatoren anzuwenden, aufgrund erheblicher Komplexität der Algorithmen, haben ergeben, dass die Programmierer einfach keine Geduld hatten und machten höchstens ein oder zwei Indikatoren, die keineswegs immer richtig bedienten. Danach hatten sie in der Regel keine Lust mehr, in diese Richtung zu arbeiten. Der grundlegende Vorteil der einfachen Mittelwerte ist, dass sie immer verfügbar sind als einfache benutzerdefinierte Funktionen, die überall und jederzeit angewendet werden können.

Betreff des Artikels


In diesem Artikel möchte ich Händler, die MQL4 kennen, effektiver Mittelwertbildungsalgorithmen mit minimaler Verzögerung vorschlagen, die als einfache benutzerdefinierte Funktionen dargestellt werden. Die Verwendung dieser Funktionen ist nicht komplizierter als die Verwendung der technischen Indikatoren. Die Funktionen wurden schon vor langer Zeit geschrieben, und ihre Betriebsqualität wurde auch ziemlich lange geprüft. Aber es wurden bei ihrer Arbeit keine Fehler oder Probleme, oder falsche Berechnungen gefunden. So werden wir die folgenden Algorithmen berücksichtigen:

- JJMASeries () - ist der adaptive JMA Glättungsalgorithmus;
- JLiteSeries() - ist der JMA Glättungsalgorithmus ohne einen adaptiven Algorithmus;
- JurXSeries () - ist der Ultra-Linear-Glättungsalgorithmus aus dem Indikator JRSX;
- ParMASeries() - ist der Glättungsalgorithmus basierend auf parabolischer Annäherung;
- LRMASeries () - ist der Algorithmus basierend auf den linearen Regressions-Glättung;
- T3Series () - ist der Glättungsalgorithmus basierend auf den Tilson-Algorithmus.

Die Realisierung der Glättungsfunktion


Die Funktionen werden als die folgenden Dateien dargestellt: JJMASeries.mqh, JLiteSeries.mqh, JurXSeries. mqh, ParMASeries.mqh, LRMASeries.mqh, T3Series.mqh.

Die Funktionsaufrufe selbst sind absolut gleich, der einzige Unterschied ist, dass einige Funktionen keine einige externer Variablen haben. Solche Funktionen werden in der Regel für die Verarbeitung der individuellen und Indikator-Arrays gebaut, die als externer Variablen arbeiten. Meiner Meinung nach ist es nicht immer bequem, so wäre es viel besser, solche Funktionen für die Verarbeitung der normalen Variablen zu verwenden, und nicht Arrays. In diesem Fall kann man eine unbegrenzte Menge von Glättungen mit diesen Algorithmen innerhalb von einer Berechnungsloop machen! Ich denke, dass es nicht notwendig ist, den Code der Funktionen in diesem Artikel zu geben. Der Code wird nur für diejenigen interessant sein, die ähnliche Funktionen basierend auf die anderen Algorithmen erstellen will. Wir interessieren uns nur für den Algorithmus des Funktionsaufrufs im Code des Indikators, das heißt, die praktische Anwendung der Funktionen.


Funktion JJMASeries ()

Lass uns am Anfang die Funktion JJMASeries() kennenlernen:

double JJMASeries(int number, int din, int MaxBar, int limit, 
                  int Phase, int Length, double series, int bar,
                  int& reset)

Die Datei JJMASeries.mqh enthält vier Funktionen: JJMASeries(), JJMASeriesResize(), JJMASeriesAlert() и JMA_ErrDescr(). Die Datei enthält auch Variablen, die als globale erklärt sind.

Die Funktion JJMASeries() wird für die Verwendung des JMA-Algorithmus beim Schreiben aller technischen Indikatoren oder Expert Advisors vorgesehen, in dem die Berechnung für die klassischen Mittelwertbildung mit dem Algorithmus ersetzt wird. Die Funktion funktioniert nicht, wenn limit den Wert von Null nimmt! Alle Indikatoren, die ich für JJMASeries entwickelt habe, wurden diese Einschränkung berücksichtigen. Die Datei muss im Ordner MetaTrader\Experten\include\ gespeichert werden. Man muss auch beachten, dass die Funktion JJMASeries() den Nullwert im Bar zurück liefert, wenn der Wert der Variable bar mehr ist, als der Wert der Variable MaxBar! Und deshalb kann dieser Wert nicht als Nenner in einem Bruch für die Berechnungen eines Indikators sein! In den folgenden 30 Bars liefert die Funktion JJMASeries() auch Null zurück!

Diese Version der Funktion JJMASeries() unterstützt Advisors Experts, wenn sie in den Benutzerindikatoren verwendet wird, die von dem Expert Advisor aufgerufen werden. Außerdem ist diese Version der Funktion JJMASeries() unterstützt Advisors Experts, wenn sie im Code des Indikators verwendet wird, der vollständig im Experten-Code platziert ist, und haltet alle DO-Protokollen und Variablen gespeichert! Beim Schreiben der Indikatoren oder Expert Advisors mit der Funktion JJMASeries, ist es nicht empfohlen, die Variablen-Namen mit dem Anfang nJMA...oder dJMA ...zu benennen Die Funktion JJMASeries() kann im internen Code der anderen benutzerdefinierten Funktionen verwendet werden, wenn es angenommen wird, dass jeder Aufruf zu JJMASeries () bei jedem Aufruf zu einer solchen benutzerdefinierten Funktion seine eindeutige Nummer haben muss. Diese Version der Funktion JJMASeries() ist für die Verarbeitung der Variablen vorgesehen, die mit Arrays der Zeitreihenanordnungen vom aktuellen Chart verbunden sind! Wenn diese Funktion für die Verarbeitung der Variablen verwendet wird, die basierend auf Arrays der Zeitreihenanordnungen von den anderen Charts berechnet sind, wird ein Fehler in der Berechnung sein!

Eingabeparameter:
- number - die Ordnungsnummer des Funktionsaufrufs JJMASeries() im Code des Indikators (0, 1, 2, 3 u.s.w);
- din - der Parameter, der die Parameter Length und Phase auf jedem Bar ändern kann. 0 - das Verbot, die Parameter zu ändern, jeder andere Wert bedeutet, dass es möglich ist;
- MaxBar - Der Maximalwert, der die Nummer des berechneten Bars annehmen kann(bar). Normalerweise ist es Bars-1-Periode, wo "period" ist die Anzahl der Bars ist, auf den der Anfangswert series nicht berechnet wird;
- limit - Die Anzahl des noch nicht berechneten Bars sowie eine oder die Nummer des letzten noch nicht berechneten Bars. Es muss gleich mit Bars-IndicatorCounted()-1 sein;
- Length - Glättungstiefe;
- Phase - Der Parameter im Bereich zwischen -100 .. . und +100, Sie beeinflusst auf die Qualität des vorübergehenden Prozess;
- series - Der Eingabeparameter, über den die Berechnung der Funktion JJMASeries() durchgeführt wird;
- bar - Die Nummer des berechneten Bars. Dieser Parameter muss von dem DO aus dem Maximalwert auf Null geändert werden. Daraufhin muss der Maximalwert immer mit dem Wert von limit gleich sein!


Eingabeparameter:
- JMASeries() - der Wert der Funktion JMA. Bei Werten des Parameters bar mehr, als MaxBar-30 ist, liefert die Funktion JJMASeries() immer Null zurück!
- reset - Der Parameter, der über dem Link den Wert zurückliefert, der von 0 unterschiedlich ist, wenn es einen Fehler in der Funktionsberechnung gab und der liefert 0, wenn die Berechnung in Ordnung war. Dieser Parameter kann nur variabel sein, aber nicht einem Wert!


Funktionsinitialisierung
Bevor die Funktion JJMASeries() aufgerufen wird, und die Anzahl der berechneten Bars schon gleich mit 0 ist, sollten die Größen der internen Puffersvariablen der Funktion verändert werden (es wäre noch besser, das im Initialisierungsblock des benutzerdefinierten Indikators oder des Expert Advisors zu tun). Dazu ist es notwendig, die Variablen von der Funktion JJMASeries() durch die Hilfsfunktion JJMASeriesResize() mit den folgenden Parametern aufzurufen: JJMASeriesResize(number+1); es ist notwendig, den Parameter "number" (MaxJMA.number) gleich der Aufrufszahl zu JJMASeries zu machen, das heißt, um 1 größer als der Maximalwert von number zu machen. Zusammen mit der Änderungen der Puffersgröße von JJMASeries() kann man im Initialisierungsblock die Eingabewerte der Variable Length und Phase durch JJMASeriesAlert() prüfen, ob ihre Änderungsbereich entsprechend sind. Diese Variable sind auch die Eingabeparameter der Funktion JJMASeries():

JJMASeriesAlert(int Number, string name, int ExternVar)

- Number - Der Parameter, der zwei Werte annehmen kann: 0 - für die Überprüfung des Eingabeparameters ExternVar, ob er innerhalb des Änderungsbereichs des Eingabeparameters Length von JJMASeries() liegt und 1 - für die Überprüfung des Eingabeparameters ExternVar, ob er innerhalb des Änderungsbereichs des Eingabeparameters Phase von JJMASeries() liegt;
- name - Der String Name des Eingabeparamters ExternVar, um eine Warnung zu geben;

- ExternVar - Der Eingabeparameter des Indikators

Fehleranzeige

Wenn Indikatoren eingerichtet werden, können ihre Code Fehler enthalten. Um die Gründe zu erfahren, sollte man die Log-Datei betrachten. Die Funktion JJMASeries() zeichnet alle Fehler in der Log-Datei im Ordner mit dem Namen \MetaTrader\EXPERTS\LOGS\. Wenn ein MQL4-Fehler im Code der vorhergehenden Funktion auftritt, bevor die Funktion JJMASeries() aufgerufen wird, dann schreibt die Funktion den Fehlercode und den Inhalt des Fehlers in einer Log-Datei. Wenn ein MQL4-Fehler beim Aufruf der Funktion JJMASeries() im Algorithmus JJMASeries() auftritt, dann schreibt die Funktion den Fehlercode und den Inhalt des Fehlers in einer Log-Datei. Wenn die Nummer number beim Aufruf der Funktion JJMASeries() falsch eingegeben wird oder die Größe der Puffervariablen von nJJMAResize falsch definiert wird. In Size der Log-Datei wird die Meldung über die falsche Definition dieser Variablen geschrieben. Genauso wird die Information bei der falschen Definition des Parameters limit geschrieben.

Wenn es bei der Änderung der Puffer-Größen der Funktion JJMASeries während des Aufrufs der Funktion init() fehlschlägt, dann schreibt die Funktion JJMASeriesResize() die Information über die fehlgeschlagenen Änderung der Größen in der Log-Datei. Wenn die richtige Reihenfolge der Änderung des Parameters bar beim Aufruf der Funktion JJMASeries() durch den externen DO gestört wurde, dann wird auch diese Information in der Log-Datei geschrieben. Man muss auch beachten, dass einige Fehler des Programmcodes künftig noch andere Fehler in seiner Ausführung schaffen, und deswegen, wenn die Funktion JJMASeries() in ihrer Log-Datei direkt ein paar Fehler schreibt, dann sollen sie in der Reihenfolge ihres Auftretens beseitigt werden. In einem richtig geschriebenen Indikator kann die Funktion JJMASeries() Datensätze in der Log-Datei nur dann machen, wenn die Systemstörungen geben. Ausnahmsweise können die Größe-Änderungen der Puffer-Variablen bei der Überbelastung des Indikators oder des Expertes geschrieben werden, die bei jedem Aufruf der Funktion init() geschieht. Alle MQL4-Fehler werden in der Log-Datei mit der Funktion JMA_ErrDescr () geschrieben, die den Code und den Fehlerinhalt nach seinem Code schickt, welcher mit Hilfe von GetLastError() erhalten wird.

Das Beispiel des Aufrufs der Funktion JJMASeries() (doppelte JMA Glättung des Eingangspreises):

/*
Für  die Arbeit  des Indikators  müssen  die Daten 
JJMASeries.mqh 
PriceSeries.mqh 
im Verzeichnis: MetaTrader\experts\include\ abgelegt werden 
Heiken Ashi#.mq4
im Verzeichnis: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+   
//|                                                        J2JMA.mq4 | 
//|                       JMA code: Copyright © 2005, Jurik Research | 
//|                                         http://www.jurikres.com/ | 
//|    MQL4 JJMASeries+J2JMA: Copyright © 2006,     Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+   
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- Darstellung des Indikators im Hauptfenster
#property indicator_chart_window 
//---- die Anzahl der Indikatorpuffers
#property indicator_buffers 1 
//---- die Farbe des Indikators
#property indicator_color1 Magenta 
//---- Eingabeparameter des Indikators 
extern int Length1 = 5; // die erste  Glättungstiefe 
extern int Length2 = 5; // die zweite  Glättungstiefe 
// Der Parameter der ersten Glättung, der sich im Bereich zwischen -100 ... +100 ändert, 
//beeinflusst auf die Qualität des vorübergehenden Prozess; 
extern int Phase1  = 100;
// Der Parameter der zweiten Glättung, der sich im Bereich zwischen -100 ... +100 ändert, 
//beeinflusst auf die Qualität des vorübergehenden Prozess; 
extern int Phase2  = 100;
// Die Verschiebung des Indikators entlang der Zeitachse 
extern int Shift   = 0;
/* Die Wahl der Preise, nach den der Indikator berechnet wird 
(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.) */
extern int Input_Price_Customs = 0;
//---- Indikatorpuffers
double J2JMA[];
//---- die Variablen mit Gleitkomma  
double Temp_Series; 
//----+ Eingabe der Funktion JJMASeries 
//----+ Eingabe der Funktion JJMASeriesResize 
//----+ Eingabe der Funktion JJMASeriesAlert  
//----+ Eingabe der Funktion JMA_ErrDescr  
#include <JJMASeries.mqh>   
//----+ Eingabe der Funktion PriceSeries
//----+ Eingabe der Funktion PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+ 
//| J2JMA indicator initialization function                          | 
//+------------------------------------------------------------------+ 
int init() 
  {  
//---- Definieren des Zeichenstils vom Chart 
   SetIndexStyle (0, DRAW_LINE); 
//---- 1 Indikatorpuffer wurde für die Zählung verwendet 
   SetIndexBuffer(0, J2JMA);
//----  Horizontale Verschiebung der Indikator-Linie 
   SetIndexShift (0, Shift);  
//---- Die Einstellung der Indikator-Werten, die im Chart unsichtbar werden
   SetIndexEmptyValue(0, 0); 
//---- Die Namen für Datenfenster und Labels für Unterfenster 
   IndicatorShortName ("J2JMA(Length1=" + Length1 + ", Phase1=" + Phase1 +
                       ", Length2=" + Length2 + ", Phase2=" + Phase2 + 
                       ", Shift=" + Shift + ")"); 
   SetIndexLabel (0, "J2JMA"); 
//---- Einstellung der Abbildungsgenauigkeit des Indikatorsformats 
   IndicatorDigits(Digits);
//----+ Die Änderung der Größe bei Puffervariablen der Funktion JJMASeries, 
//nJMAnumber=2(zwei Aufrufe zur Funktion JJMASeries)
   if(JJMASeriesResize(2) != 2)
       return(-1);
//---- Einstellung der Warnungen für nicht akzeptablen Werte der externen Variablen
   JJMASeriesAlert (0,"Length1", Length1);
   JJMASeriesAlert (0,"Length2", Length2);
   JJMASeriesAlert (1,"Phase1", Phase1 );
   JJMASeriesAlert (1,"Phase2", Phase2 );
   PriceSeriesAlert(Input_Price_Customs);
//---- Das Ende des Initialisierens 
   return(0); 
  } 
//+------------------------------------------------------------------+   
//| J2JMA iteration function                                         | 
//+------------------------------------------------------------------+ 
int start() 
  { 
//---- Die Überprüfung der Anzahl der Bars, damit sie ausreichend für die Berechnung wären
   if(Bars - 1 < 61)
       return(0);
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
   int reset, MaxBar1, MaxBar2, counted_bars = IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
   if(counted_bars < 0) 
       return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden 
//---- (Ohne diese Neuberechnung für  counted_bars wird die Funktion JJMASeries  
//     nicht korrekt funktionieren!!!)
   if(counted_bars > 0) 
       counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     der neuen Bars beginnt
   int limit = Bars - counted_bars - 1; 
   MaxBar1 = Bars - 1; 
   MaxBar2 = MaxBar1 - 30;
 
//----+ Die Hauptloop der Berechnung des Indikators 
   for(int bar = limit; bar >= 0; bar--)
     {
       // Der Aufruf zu der Funktion PriceSeries für die Erhaltung des Eingangspreises Series
       Temp_Series = PriceSeries(Input_Price_Customs, bar);
       // zwei Aufrufe zur Funktion JJMASeries nach Nummern 0, 1. Parameter 
       //nJMA.Phase und nJMA.Length 
       //Ändern sich nicht an jedem Bar  (nJMA.din=0)
       //(Im zweiten  Aufruf des Parameters nJMA.MaxBar  wird um 30   verringert. denn es  
       //ist die wiederholte JMA Glättung)
       Temp_Series = JJMASeries(0,0,MaxBar1,limit,Phase1,Length1,
                                Temp_Series,bar,reset);
       // Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
       if(reset != 0)
           return(-1);
       Temp_Series = JJMASeries(1,0,MaxBar2,limit,Phase2,Length2,
                                Temp_Series,bar,reset);
       // Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
       if(reset != 0)
           return(-1);
       J2JMA[bar] = Temp_Series;
     }
//---- Das Ende der Berechnung der Indikator-Werte
   return(0); 
  } 
//+--------------------------------------------------------+


So können die folgenden Punkte in der Anwendung dieser Funktion hervorgehoben werden:
1. Erklärung der Funktionen, die im Inhalt der Datei JJMASeries. mqh mit der Zeile #include <JJMASeries.mqh> am Textanfang des Indikators sind. Es werden Variablen und vier Funktionen erklärt: JJMASeries(), JJMASeriesResize(), JJMASeriesAlert() и JMA_ErrDescr();
2. Die Änderung der Größen der Pufferelemente, die in der Funktion JJMASeries() mit der Funktion JJMASeriesResize() im Initialisierungsblock verwendet werden;
3. Die Überprüfung mit der Funktion JJMASeriesAlert() im Initialisierungsblock, ob die Werte der externen Variable vom Indikator korrekt sind, welche die externen Variable der Funktion JJMASeries() sind;
4. Die Aufrufe zur Funktion JJMASeries(), die durch den DO mit den entsprechenden Fehlerüberprüfungen gemacht wurden.


Weitere Funktionen


Der Aufruf-Algorithmus zu den anderen Funktionen mit dem oben betrachteten Algorithmus ist ähnlich, aber es gibt einige Unterschiede in der Anzahl der externen Variablen in Funktionen:
JJMASeries (int number, int din, int MaxBar, int limit, int Phase,
            int Length, double series, int bar, int&reset)
JLiteSeries(int number, int din, int MaxBar, int limit, int Phase,
            int Length, double series, int bar, int&reset)
JurXSeries (int number, int din, int MaxBar, int limit,
            int Length, double series, int bar, int&reset)
T3Series   (int number, int din, int MaxBar, int limit, int Phase,
            int Length, double series, int bar, int&reset )
ParMASeries(int number, int MaxBar, int limit, int period, 
            double series, int bar, int&reset)
LRMASeries (int number, int MaxBar, int limit, int period, 
            double series, int bar, int&reset )

Es sollte klar sein, dass die Funktionen JJMASeries() und JLiteSeries() im gleichen Expert Advisor oder Indikator nicht kompatibel sind! Tatsächlich ist in der Datei JLiteSeries. mqh der gleiche Code JMA mit dem Namen der Funktion JJMASeries() ohne Anpassung platziert worden! Um die Funktion JJMASeries() um JLiteSeries() im Experten oder im Indikator zu ersetzen, ist es genug, die Zeile #include<JJMASeries mqh> um die Zeile #include<JLiteSeries. mqh> zu ersetzen. Alle Aufrufe zu den Funktionen der Datei JLiteSeries. mqh werden als Aufrufe für die Funktionen betrachtet, die identisch zu den Funktionen der Datei JJMASeries.mqh gehen .


Weitere Funktionen sind voll kompatibel innerhalb im gleichen Indikator oder Expert Advisor-Code. In Funktionen ParMASeries () und LRMASeries (), wird der Wert der externen Variablen period mit 501 begrenzt. Wenn die größere Werte gebraucht werden, dann muss man die ersten (nicht nullwertigen) Werte der Puffers ersetzen
dParMA.TempBuffer[][501] und dParMA.TEMPBUFFER[][501] für die Funktion ParMASeries() oder dLRMA. TempBuffer[][501] und dLRMA.TEMPBUFFER[][501] für die Funktion LRMASeries() in Dateien ParMASeries. mqh und LRMASeries. mqh bzw.


Die Funktionen JurXSeries()

Das Beispiel des Aufrufs der Funktion JJMASeries() (Ultra-Linear Glättung des Eingangspreis mit zusätzlicher JMA Glättung):

/*
Für  die Arbeit  des Indikators  müssen  die Daten 
JurXSeries.mqh, 
JJMASeries.mqh, 
PriceSeries.mqh,  
im Verzeichnis: MetaTrader\experts\include\ abgelegt werden 
Heiken Ashi#.mq4
im Verzeichnis: MetaTrader\indicators\
In der Basis  auf diesen  Indikator  liegt  der Glättungsalgorithmus vom Indikator 
JRSX.    Das Endergebnis dieses Algorithmus hat einige Ähnlichkeiten mit 
der doppelten Glättung JMA, aber auf Grund ihrer Einfachheit ist weniger perfekt.
 
*/
//+------------------------------------------------------------------+
//|                                                        JJurX.mq4 | 
//|                           Copyright © 2006,     Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- Darstellung des Indikators im Hauptfenster
#property indicator_chart_window 
//---- die Anzahl der Indikatorpuffers
#property indicator_buffers 1 
//---- die Farbe des Indikators
#property indicator_color1 Gold
//---- Eingabeparameter des Indikators 
extern int JurX_Length  = 5; // die Glättungstiefe JurX 
extern int JJMA_Length  = 4; // die Glättungstiefe JJMA 
// Der Parameter der Glättung JJMA, der sich im Bereich zwischen -100 ... +100 ändert, 
//  beeinflusst auf die Qualität des vorübergehenden Prozess; 
extern int JJMA_Phase   = -100;
extern int Shift        = 0;      // Die Verschiebung des Indikators entlang der Zeitachse 
/* Die Wahl der Preise, nach den der Indikator berechnet wird 
(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.) */
extern int Input_Price_Customs = 0;
//---- Indikatorpuffers
double Ind_Buffer[];
//---- die Variablen mit Gleitkomma  
double Price,JurX,JJurX,Error;
//+------------------------------------------------------------------+
//----+ Eingabe der Funktion JJMASeries 
//----+ Eingabe der Funktion JJMASeriesResize 
//----+ Eingabe der Funktion JJMASeriesAlert  
//----+ Eingabe der Funktion JMA_ErrDescr  
#include <JJMASeries.mqh> 
//+------------------------------------------------------------------+
//----+ Eingabe der Funktion JurXSeries
//----+ Eingabe der Funktion JurXSeriesResize
//----+ Eingabe der Funktion JurXSeriesAlert 
//----+ Eingabe der Funktion JurX_ErrDescr  
#include <JurXSeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Eingabe der Funktion PriceSeries
//----+ Eingabe der Funktion PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+
//| JJurX indicator initialization function                          | 
//+------------------------------------------------------------------+ 
int init() 
{  
//---- Definieren des Zeichenstils vom Chart 
SetIndexStyle (0,DRAW_LINE); 
//---- 1 Indikatorpuffer wurde für die Zählung verwendet 
SetIndexBuffer(0,Ind_Buffer);
//----  Horizontale Verschiebung der Indikator-Linie 
SetIndexShift (0, Shift); 
//---- Die Einstellung der Indikator-Werten, die im Chart unsichtbar werden
SetIndexEmptyValue(0,0); 
//---- Die Namen für Datenfenster und Labels für Unterfenster 
IndicatorShortName ("JJurX( JurX_Length="+JurX_Length+", Shift="+Shift+")"); 
SetIndexLabel (0, "JJurX"); 
//---- Einstellung der Abbildungsgenauigkeit des Indikatorsformats 
IndicatorDigits(Digits);
//----+ Die Änderung der Größe bei Puffervariablen der Funktion JurXSeries, 
//      nJurXnumber=2
//(zwei Aufrufe zur Funktion JurXSeries)
if (JurXSeriesResize(2)!=2)return(-1);
//----+ Die Änderung der Größe bei Puffervariablen der Funktion JJMASeries,
//      nJMAnumber=1
//(Ein Aufruf zur Funktion JJMASeries)
if (JJMASeriesResize(1)!=1)return(-1);
//---- Einstellung der Warnungen für nicht akzeptablen Werte der externen Variablen  
JurXSeriesAlert(0,"JurX_Length",JurX_Length); 
JJMASeriesAlert(0,"JJMA_Length",JJMA_Length); 
JJMASeriesAlert(1,"JJMA_Phase",JJMA_Phase); 
PriceSeriesAlert(Input_Price_Customs);
//---- Das Ende des Initialisierens 
return(0); 
} 
//+------------------------------------------------------------------+
//| JJurX iteration function                                         | 
//+------------------------------------------------------------------+
int start() 
{ 
//---- Die Überprüfung der Anzahl der Bars, damit sie ausreichend für die Berechnung wären
if (Bars-1<JurX_Length+32)return(0);
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
int reset,MaxBar,counted_bars=IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
if (counted_bars<0)return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden 
//(Ohne diese Neuberechnung für counted_bars wird die Funktion JurXSeries  
// nicht korrekt funktionieren!!!)
if (counted_bars>0) counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     Es werden alle neue Bars neuberechnet
int limit=Bars-counted_bars-1; 
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//     aller Bars beginnt
MaxBar=Bars-1; 
 
//----+ Die Hauptloop der Berechnung des Indikators 
for(int bar=limit;bar>=0;bar--)
 {
  //----+ Der Aufruf zu der Funktion PriceSeries für die Erhaltung des Eingangspreises
  //       Series
  Price=PriceSeries(Input_Price_Customs,bar);
  //----+ Ein Aufruf zur Funktion JurXSeries nach der Nummer 0. 
  //Der Parameter nJJurX.Length ändert sich nicht an jedem Bar (nJurXdin=0)
  JurX=JurXSeries(0,0,MaxBar,limit,JurX_Length,Price,bar,reset); 
  //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
  if(reset!=0)return(-1); 
  //----+ Definition des Berechnungsfehlers  vom Parameter JurX
  //----+ Der zweite Aufruf zur Funktion JurXSeries nach der Nummer 1. 
  //Der Parameter nJJurX.Length ändert sich nicht an jedem Bar (nJurXdin=0)
  Error=JurXSeries(1,0,MaxBar,limit,JurX_Length,100,bar,reset); 
  //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
  if(reset!=0)return(-1);
  if(Error==0)Error=100;
  JurX*=100/Error;
  //----+ Ein Aufruf zur Funktion JJMASeries nach der Nummer 0. 
  //      Die Parameter nJMA.Phase und nJMA.Length ändern sich nicht an jedem Bar 
  //      (nJMA.din=0)
  JJurX=JJMASeries(0,0,MaxBar,limit,JJMA_Phase,JJMA_Length,JurX,bar,reset);
  //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
  if(reset!=0)return(-1);
  Ind_Buffer[bar]=JJurX;                 
 }
//---- Das Ende der Berechnung der Indikator-Werte
return(0); 
} 
//+-------------------------------------------------------------------------+

In diesem Beispiel sollte die Tatsache beachtet werden, dass die Funktion JurXSeries() sowohl den Eingangspreis auch die Konstante zur Mittelwertbildung führt! Wenn das erhaltende Mittelungsergebnis durch den konstanten Wert geteilt wird, werden wir den Glättungsfehler erhalten. Um ein genaueres Ergebnis der Glättung der Preisreihe zu erhalten, ist es notwendig, das Glättungsergebnis durch diesen Fehlerwert zu teilen. Das wurde eben in unserem Fall getan. In beiden weiteren Fällen werden Zähler und Nenner separat geglättet, so gibt es keine Notwendigkeit, den obigen Vorgang zu wiederholen. Ein solcher Fehler bei anderen Glättungsfunktionen tritt nicht auf.

Das Beispiel des Aufrufs der Funktionen JJMASeries() und JurXSeries() (Analog des Indikators CCI mit zusätzlicher JMA Glättung):

/*
Für  die Arbeit  des Indikators  müssen  die Daten 
JJMASeries.mqh
JurSeries.mqh 
PriceSeries.mqh 
im Verzeichnis: MetaTrader\experts\include\ abgelegt werden 
Heiken Ashi#.mq4
im Verzeichnis: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+   
//|                                                        JCCIX.mq4 |
//|                               Copyright © 2006, Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+    
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- Darstellung des Indikators im getrennten Fenster
#property indicator_separate_window
//---- die Anzahl der Indikatorpuffers
#property indicator_buffers  1
//---- die Farben des Indikators
#property indicator_color1  BlueViolet
//---- Die Parameter der horizontalen Ebenen des Indikators
#property indicator_level1  0.5
#property indicator_level2 -0.5
#property indicator_level3  0.0
#property indicator_levelcolor MediumBlue
#property indicator_levelstyle 4
//---- Eingabeparameter des Indikators 
extern int  JJMA.Length = 8;  // die Glättungstiefe JJMA des Eingangspreises
// die Glättungstiefe JurX des erhaltenden Indikators 
extern int  JurX.Length = 8;
// Der Parameter, der sich im Bereich zwischen -100 ... +100 ändert,  
// beeinflusst auf die Qualität der vorübergehenden Glättungsprozesse 
extern int  JJMA.Phase = 100;
 /* Die Wahl der Preise, nach den der Indikator berechnet wird 
(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.) */
extern int Input_Price_Customs = 0;
//---- Indikatorpuffers
double Ind_Buffer1[];
//---- Die ganze Konstanten 
int    w;
//+------------------------------------------------------------------+
//----+ Eingabe der Funktion JJMASeries 
//----+ Eingabe der Funktion JJMASeriesResize 
//----+ Eingabe der Funktion JJMASeriesAlert  
//----+ Eingabe der Funktion JMA_ErrDescr  
#include <JJMASeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Eingabe der Funktion JurXSeries
//----+ Eingabe der Funktion JurXSeriesResize
//----+ Eingabe der Funktion JurXSeriesAlert 
//----+ Eingabe der Funktion JurX_ErrDescr  
#include <JurXSeries.mqh> 
//+------------------------------------------------------------------+  
//----+ Eingabe der Funktion PriceSeries
//----+ Eingabe der Funktion PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+ 
//| JCCIX initialization function                                    |
//+------------------------------------------------------------------+
int init()
 {
//---- Die Darstellungsarten des Indikators
   SetIndexStyle(0,DRAW_LINE);
//---- 1 Indikatorpuffer wurde für die Zählung verwendet. 
   SetIndexBuffer(0,Ind_Buffer1);
//---- Die Einstellung der Indikator-Werten, die im Chart unsichtbar werden
   SetIndexEmptyValue(0,0); 
//---- Die Namen für Datenfenster und Labels für Unterfenster
   SetIndexLabel(0,"JCCIX");
   IndicatorShortName("JCCIX(JJMA.Length="+JJMA.Length+", JurX.Length"+
                      JurX.Length+")");
//---- Einstellung der Genauigkeit der Format (Die Anzahl der Zeichen nach dem dezimalen Komma) 
//die Indikatorswerte zu visualisieren  
   IndicatorDigits(2);
//----+ Die Änderung der Größe bei Puffervariablen der Funktion JurXSeries, 
//      nJurXnumber=2
//(zwei Aufrufe zur Funktion JurXSeries)
   if (JurXSeriesResize(2)!=2)return(-1);
//----+ Die Änderung der Größe bei Puffervariablen der Funktion JJMASeries, 
//      nJMAnumber=1
//(Ein Aufruf zur Funktion JJMASeries)
   if (JJMASeriesResize(1)!=1)return(-1);
//---- Einstellung der Warnungen für nicht akzeptablen Werte der externen Variablen
   JurXSeriesAlert (0,"JurX.Length",JurX.Length);
   JJMASeriesAlert (0,"JJMA.Length",JJMA.Length);
   JJMASeriesAlert (1,"JJMA.Phase",JJMA.Phase);
   PriceSeriesAlert(Input_Price_Customs);
//---- Die Bestimmung der Nummer des Bars, von der der Indikator 
//     entsteht  
   SetIndexDrawBegin(0,JurX.Length+31);
//---- Die Initialisierung der Koeffizienten, um Indikator zu berechnen 
   if (JurX.Length>5) w=JurX.Length-1; else w=5;
//---- Das Ende des Initialisierens 
   return(0);
  }
//+------------------------------------------------------------------+
//|  JCommodity Channel IndexX                                       |
//+------------------------------------------------------------------+
int start()
  {
//---- Eingabe der Variablen mit Gleitkomma    
double price,Jprice,JCCIX,UPCCI,DNCCI,JUPCCIX,JDNCCIX; 
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
int reset,MaxBar,MaxBarJ,limit,counted_bars=IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
if (counted_bars<0)return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden 
//---- (Ohne diese Neuberechnung für counted_bars werden die Funktionen JJMASeries 
//und JurXSeries nicht korrekt funktionieren!!!)
if (counted_bars>0) counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung   
//Es wurden alle neue Bars neuberechnet
limit=Bars-counted_bars-1; 
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung   
//alle Bars beginnt
MaxBar=Bars-1; MaxBarJ=MaxBar-30;
//---- Die Korrektur des berechneten Anfangsbars in der Loop
if(limit>=MaxBar)limit=MaxBar;
 
for(int bar=limit; bar>=0; bar--)
 { 
   //----+ Der Aufruf zu der Funktion PriceSeries für die Erhaltung des Eingangspreises 
   //       Series
   price=PriceSeries(Input_Price_Customs, bar);
   //+---------------------------------------------------------------
   //----+ Ein Aufruf zur Funktion JJMASeries nach der Nummer 0 
   //----+ Die Parameter nJMA.Phase und nJMA.Length ändern sich nicht an jedem 
   //      Bar (nJMA.din=0)
   //+---------------------------------------------------------------+   
   Jprice=JJMASeries(0,0,MaxBar,limit,JJMA.Phase,JJMA.Length,price,
                     bar,reset);
   //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
   if(reset!=0)return(-1);
   //+---------------------------------------------------------------+    
   UPCCI=price-Jprice;         
   DNCCI=MathAbs(UPCCI);
   //----+ zwei Aufrufe zur Funktion JurXSeries nach Nummern 0 und 1. 
           Der Parameter nJJurXLength ändert sich nicht 
   //an jedem Bar (nJurXdin=0)
   //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
   JUPCCIX=JurXSeries(0,0,MaxBarJ,limit,JurX.Length,UPCCI,bar,reset); 
   if(reset!=0)return(-1); 
   JDNCCIX=JurXSeries(1,0,MaxBarJ,limit,JurX.Length,DNCCI,bar,reset); 
   if(reset!=0)return(-1); 
   //----+
   if (bar>MaxBarJ-w)JCCIX=0;
   else 
     if (JDNCCIX!=0)
       {
        JCCIX=JUPCCIX/JDNCCIX;
        if(JCCIX>1)JCCIX=1;
        if(JCCIX<-1)JCCIX=-1;
       }
     else JCCIX=0;
   Ind_Buffer1[bar]=JCCIX; 
   //----+
 }
//----
   return(0);
  }
//+-------------------------------------------------------------------+

Die folgende Tatsache sollte beachtet werden: Nach zwei Glättungen mit der Funktion JurXSeries() wird einer erhaltende Wert geprüft, ob der Null nicht gleich ist, weil er ein Nenner ist!

Das Beispiel des Aufrufs der Funktionen JJMASeries() und JurXSeries (Analog des Indikators RSI mit zusätzlicher JMA Glättung):

/*
Für  die Arbeit  müssen  die Daten    
JurXSeries.mqh
JJMASeries.mqh  
PriceSeries.mqh 
im Verzeichnis: MetaTrader\experts\include\ abgelegt werden 
Heiken Ashi#.mq4
im Verzeichnis: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+ 
//|                                                        JJRSX.mq4 |
//|    MQL4 JJRSX: Copyright © 2006,                Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+ 
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- Darstellung des Indikators im getrennten Fenster
#property indicator_separate_window
//---- die Anzahl der Indikatorpuffers
#property indicator_buffers  1
//---- die Farben des Indikators
#property indicator_color1  BlueViolet
//---- Die Parameter der horizontalen Ebenen des Indikators
#property indicator_level1  0.5
#property indicator_level2 -0.5
#property indicator_level3  0.0
#property indicator_levelcolor MediumBlue
#property indicator_levelstyle 4
//---- Eingabeparameter des Indikators 
extern int  Length = 8;  // die Glättungstiefe JurX
// die Glättungstiefe JJMA des erhaltenden Indikators
extern int  Smooth = 3;
// Der Parameter, der sich im Bereich zwischen -100 ... +100 ändert, 
//beeinflusst auf die Qualität der vorübergehenden Glättungsprozesse
extern int  Phase = 100;
/* Die Wahl der Preise, nach den der Indikator berechnet wird 
(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.) */
extern int Input_Price_Customs = 0;
//---- Indikatorpuffers
double Ind_Buffer[];
//---- Die ganze Variable 
int    w;  
//+------------------------------------------------------------------+  
//----+ Eingabe der Funktion JJMASeries 
//----+ Eingabe der Funktion JJMASeriesResize 
//----+ Eingabe der Funktion JJMASeriesAlert  
//----+ Eingabe der Funktion JMA_ErrDescr  
#include <JJMASeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Eingabe der Funktion JurXSeries
//----+ Eingabe der Funktion JurXSeriesResize
//----+ Eingabe der Funktion JurXSeriesAlert 
//----+ Eingabe der Funktion JurX_ErrDescr  
#include <JurXSeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Eingabe der Funktion PriceSeries
//----+ Eingabe der Funktion PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+ 
//| JJRSX initialization function                                    |
//+------------------------------------------------------------------+ 
int init()
  {
//---- Die Darstellungsarten des Indikators
   SetIndexStyle(0,DRAW_LINE);
//---- 1 Indikatorpuffer wurde für die Zählung verwendet. 
   SetIndexBuffer(0,Ind_Buffer);
//---- Die Einstellung der Indikator-Werten, die im Chart unsichtbar werden
   SetIndexEmptyValue(0,0); 
//---- Die Namen für Datenfenster und Labels für Unterfenster
   SetIndexLabel(0,"JRSX");
   IndicatorShortName("JRSX(Length="+Length+", Input_Price_Customs="+
                      Input_Price_Customs+")");
//---- Einstellung der Genauigkeit der Format (Die Anzahl der Zeichen nach dem dezimalen 
//     Komma) die Indikatorswerte zu visualisieren  
   IndicatorDigits(2);
//----+ Die Änderung der Größe bei Puffervariablen der Funktion JurXSeries,
        nJurXnumber=2
//(zwei Aufrufe zur Funktion JurXSeries)
   if (JurXSeriesResize(2)!=2)return(-1);
//----+ Die Änderung der Größe bei Puffervariablen der Funktion JJMASeries,
        nJMAnumber=1
//(Ein Aufruf zur Funktion JJMASeries)
   if (JJMASeriesResize(1)!=1)return(-1);
//---- Einstellung der Warnungen für nicht akzeptablen Werte der externen Variablen
   JurXSeriesAlert (0,"Length",Length);
   JJMASeriesAlert (0,"Smooth",Smooth);
   JJMASeriesAlert (1,"Phase",Phase);
   PriceSeriesAlert(Input_Price_Customs);
//---- Die Bestimmung der Nummer des Bars, von der der Indikator
       entsteht  
   SetIndexDrawBegin(0,Length+31);
//---- Die Korrektur für nicht akzeptablen Werte des Parameters Length
   if(Length<1)Length=1; 
//---- Die Initialisierung der Koeffizienten, um Indikator zu berechnen 
   if (Length>5) w=Length-1; else w=5;
//---- Das Ende des Initialisierens 
return(0);
  }
//+------------------------------------------------------------------+ 
//| JJRSX iteration function                                         |
//+------------------------------------------------------------------+ 
int start()
{
//---- Eingabe der Variablen mit Gleitkomma 
double dPrice,dPriceA,UPJRSX,DNJRSX,JRSX,JJRSX; 
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
int bar,limit,reset,MaxBar,MaxBarJ,counted_bars=IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
if (counted_bars<0)return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden
if (counted_bars>0) counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//Es werden alle Bars neuberechnet
MaxBar=Bars-2; MaxBarJ=MaxBarJ-w-1; 
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//Es werden alle neue Bars neuberechnet
limit=Bars-counted_bars-1; 
//----+ 
if (limit>MaxBar){limit=MaxBar;Ind_Buffer[MaxBar]=0.0;}
 
for(bar=limit;bar>=0;bar--)
  {
   //----+ zwei Aufrufe zur Funktion PriceSeries für die Erhaltung des Unterschieds 
   //      bei Eingangspreisen dPrice
   dPrice = PriceSeries(Input_Price_Customs, bar)-
                        PriceSeries(Input_Price_Customs, bar+1);
   //----+  
   dPriceA=MathAbs(dPrice);
   //----+ zwei Aufrufe zur Funktion JurXSeries nach Nummern 0 und 1. 
   //      Der Parameter nJJurXLength 
   //ändert sich nicht an jedem Bar (nJurXdin=0) 
   //Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
   UPJRSX=JurXSeries(0,0,MaxBar,limit,Length,dPrice, bar,reset); 
   if(reset!=0)return(-1);
   DNJRSX=JurXSeries(1,0,MaxBar,limit,Length,dPriceA,bar,reset);
   if(reset!=0)return(-1); 
   //----+
   if (bar>MaxBar-w)JRSX=0;
   else if (DNJRSX!=0){JRSX=UPJRSX/DNJRSX;
   if(JRSX>1)JRSX=1;
   if(JRSX<-1)JRSX=-1;}else JRSX=0;
   //+---------------------------------------------------------------+ 
   //----+ Ein Aufruf zur Funktion JJMASeries nach der Nummer 0 
   //----+ Die Parameter nJMA.Phase und nJMA.Length ändern sich nicht an jedem 
   //      Bar (nJMA.din=0)
   //+---------------------------------------------------------------+   
   JJRSX=JJMASeries(0,0,MaxBarJ,limit,Phase,Smooth,JRSX,bar,reset);
   //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
   if(reset!=0)return(-1);
   //+---------------------------------------------------------------+  
   Ind_Buffer[bar]=JJRSX;  
}
//---- Das Ende der Berechnung der Indikator-Werte
return(0);
}
//+------------------------------------------------------------------+



Funktion T3Series()

Das Beispiel des Aufrufs der Funktion T3Series() (3 Bollinger-Bänder mit zusätzlicher Glättung T3):
/*
Für  die Arbeit  des Indikators  müssen  die Daten 
T3Series.mqh 
PriceSeries.mqh 
im Verzeichnis: MetaTrader\experts\include\ abgelegt werden 
Heiken Ashi#.mq4
im Verzeichnis: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+ 
//|                                          T3.6Bollinger Bands.mq4 | 
//|                        Copyright © 2006,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+ 
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- Darstellung des Indikators im Hauptfenster
#property indicator_chart_window 
//---- die Anzahl der Indikatorpuffers
#property indicator_buffers 7
//---- die Farben des Indikators
#property indicator_color1 Gray 
#property indicator_color2 Red
#property indicator_color3 Blue 
#property indicator_color4 Lime
#property indicator_color5 Blue
#property indicator_color6 Red
#property indicator_color7 Gray 
//---- Die Liniensarten des Indikators
#property indicator_style1 4
#property indicator_style2 2
#property indicator_style3 4
#property indicator_style4 4
#property indicator_style5 4
#property indicator_style6 2
#property indicator_style7 4
//---- Eingabeparameter des Indikators 
// Die Periode  der Mittelwertbildung J2Bollinger Bands
extern int        Bands_Period = 100;
extern double Bands_Deviations = 2.0; // Devitation 
extern int         MA_method = 0;   // Die Methode der Mittelwertbildung
// die Glättungstiefe des erhaltenden Moving Avereges
extern int         MA_Smooth = 20;
// die Glättungstiefe des erhaltenden Bollinger Bands
extern int        Bands_Smooth = 20;
// Der Parameter der Glättung, der sich im Bereich zwischen -100 ... +100 ändert, 
//  beeinflusst auf die Qualität des vorübergehenden Prozess; 
extern int    Smooth_Curvature = 100;
// Die Verschiebung des Indikators entlang der Zeitachse 
extern int         Bands_Shift = 0;
//Die Wahl der Preise, nachdem der Indikator berechnet wird 
/*(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 High, 12-Heiken Ashi Low, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.)*/
extern int Input_Price_Customs = 0;
//---- Indikatorpuffers
double UpperBuffer3  [];
double UpperBuffer2  [];
double UpperBuffer1  [];
double T3MovingBuffer[];
double LowerBuffer1  [];
double LowerBuffer2  [];
double LowerBuffer3  [];
double Series_buffer [];
//+------------------------------------------------------------------+ 
//----+ Eingabe der Funktion T3Series 
//----+ Eingabe der Funktion T3SeriesResize 
//----+ Eingabe der Funktion T3SeriesAlert 
//----+ Eingabe der Funktion T3_ErrDescr  
#include <T3Series.mqh> 
//+------------------------------------------------------------------+ 
//----+ Eingabe der Funktion PriceSeries
//----+ Eingabe der Funktion PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+  
//| T3.6Bollinger Bands initialization function        | 
//+------------------------------------------------------------------+  
int init()
  {
//---- Definieren des Zeichenstils vom Chart 
   SetIndexStyle(0,DRAW_LINE); 
   SetIndexStyle(1,DRAW_LINE);
   SetIndexStyle(2,DRAW_LINE);
   SetIndexStyle(3,DRAW_LINE); 
   SetIndexStyle(4,DRAW_LINE);
   SetIndexStyle(5,DRAW_LINE); 
   SetIndexStyle(6,DRAW_LINE);
//---- 4 Indikatorpuffers wurden für die Zählung verwendet  
   IndicatorBuffers(8);
   SetIndexBuffer(0,UpperBuffer3 );
   SetIndexBuffer(1,UpperBuffer2 );
   SetIndexBuffer(2,UpperBuffer1 );
   SetIndexBuffer(3,T3MovingBuffer);
   SetIndexBuffer(4,LowerBuffer1 );
   SetIndexBuffer(5,LowerBuffer2 );
   SetIndexBuffer(6,LowerBuffer3 );
   SetIndexBuffer(7,Series_buffer);
//---- Die Einstellung der Indikator-Werten, die im Chart unsichtbar werden
   SetIndexEmptyValue(0,0);
   SetIndexEmptyValue(1,0);
   SetIndexEmptyValue(2,0);
   SetIndexEmptyValue(3,0);
   SetIndexEmptyValue(4,0);
   SetIndexEmptyValue(5,0);
   SetIndexEmptyValue(6,0);
//---- Die Bestimmung der Nummer des Bars, von der der Indikator
//     entsteht  
   int drawbegin=100+Bands_Shift;
   SetIndexDrawBegin(0,drawbegin);
   SetIndexDrawBegin(1,drawbegin);
   SetIndexDrawBegin(2,drawbegin);
   SetIndexDrawBegin(3,drawbegin);
   SetIndexDrawBegin(4,drawbegin);
   SetIndexDrawBegin(5,drawbegin);
   SetIndexDrawBegin(6,drawbegin);
//---- Horizontale Verschiebung der Indikator-Linien  
   SetIndexShift (0, Bands_Shift); 
   SetIndexShift (1, Bands_Shift); 
   SetIndexShift (2, Bands_Shift); 
   SetIndexShift (3, Bands_Shift); 
   SetIndexShift (4, Bands_Shift); 
   SetIndexShift (5, Bands_Shift); 
   SetIndexShift (6, Bands_Shift); 
//---- Die Namen für Datenfenster und Labels für Unterfenster
   IndicatorShortName ("T3.4Bollinger Bands( Period="+Bands_Period+
        ", Deviations="+Bands_Deviations+")"); 
   SetIndexLabel (0, "Upper3 Bands");
   SetIndexLabel (1, "Upper2 Bands");
   SetIndexLabel (2, "Upper1 Bands"); 
   SetIndexLabel (4, "Lower1 Bands"); 
   SetIndexLabel (5, "Lower2 Bands"); 
   SetIndexLabel (6, "Lower3 Bands"); 
   string Moving;
   switch(MA_method)
       {
        case  0: Moving= "T3SMA";break;
        case  1: Moving= "T3EMA";break;
        case  2: Moving="T3SSMA";break;
        case  3: Moving="T3LWMA";break;
        default: Moving="T3SMA";
       }
   SetIndexLabel (3, "Moving Avereges "+Moving+" ("+Bands_Period+")");
//---- Einstellung der Abbildungsgenauigkeit des Indikatorsformats 
   IndicatorDigits(Digits);
//----+ Die Änderung der Größe bei Puffervariablen der Funktion T3Series, 
//nT3.number=7(7 Aufrufe zur Funktion T3Series)
   if (Bands_Smooth<=1){if (T3SeriesResize(1)!=1)return(-1);}
   else if (T3SeriesResize(7)!=7)return(-1);
//---- Einstellung der Warnungen für nicht akzeptablen Werte der externen Variablen
   T3SeriesAlert(0,"MA_Smooth",MA_Smooth);
   T3SeriesAlert(0,"Bands_Period",Bands_Period);
   PriceSeriesAlert(Input_Price_Customs);
   if((MA_method<0)||(MA_method>3))
        Alert("Der Parameter MA_method muss von 0 bis 3 sein" 
        + " Sie haben nicht akzeptabel eingegeben " 
       +MA_method+ " wird 0 verwendet");
//---- Die Korrektur für nicht akzeptablen Werte des Parameters Bands_Period
   if(Bands_Period<1)Bands_Period=1; 
//---- Das Ende des Initialisierens 
   return(0);
  }
//+------------------------------------------------------------------+  
//| T3.6Bollinger Bands iteration function         | 
//+------------------------------------------------------------------+  
int start()
  {
//---- Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die Berechnung wären
if(Bars-1<=Bands_Period) return(0);
//---- Eingabe der Variablen mit Gleitkomma  
double deviation1,deviation2,deviation3,Temp_Series,sum,midline,
       priceswing,Resalt;
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
int reset,MaxBar,MaxBarBB,MaxBarBB1,bar,kk,counted_bars=IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
if (counted_bars<0)return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden 
// (Ohne diese Neuberechnung für counted_bars wird die Funktion T3Series
// nicht korrekt funktionieren!!!)
if (counted_bars>0) counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung 
//Es werden alle neue Bars neuberechnet
int limit=Bars-counted_bars-1;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//Es werden alle Bars neuberechnet
MaxBar=Bars-1-Bands_Period; MaxBarBB=MaxBar-30-Bands_Period; 
MaxBarBB1=MaxBarBB-1;
//----+ Die Ladung der Eingangspreisen beim Puffer für die Berechnung       
for(bar=limit;bar>=0;bar--)
    Series_buffer[bar]=PriceSeries(Input_Price_Customs,bar);
//---- Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die Berechnung Bollinger Bands wären 
//---- Initialisieren der Null        
if (limit>MaxBar)
     {
      for(bar=limit;bar>=MaxBar;bar--)T3MovingBuffer[bar]=0;
      limit=MaxBar;
     }
//----+ Die Loop der Berechnung Moving Avereges
for(bar=limit;bar>=0;bar--)
     {
      //----+ Die Formel für die Berechnung Moving Avereges
      Temp_Series=iMAOnArray(Series_buffer,0,Bands_Period,0,
                             MA_method, bar);
      //----+ Glättung des erhaltenden Moving Avereges
      //----+ Ein Aufruf zur Funktion T3Series nach der Nummer 0. 
      // Die Parameter nT3.Curvature und nT3.Length ändern sich nicht an jedem 
      // Bar (nT3.din=0)
      Resalt=T3Series(0,0,MaxBar,limit,Smooth_Curvature,MA_Smooth,
                      Temp_Series,bar,reset);
      //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
      if(reset!=0)return(-1); 
      T3MovingBuffer[bar]=Resalt; 
     }     
//---- Die Berechnung Bollinger Bands 
//---- Initialisieren der Null      
if (limit>MaxBarBB)
     {
      for(bar=limit;bar>=MaxBarBB;bar--)
       {
        UpperBuffer2[bar]=0;
        UpperBuffer1[bar]=0;
        LowerBuffer1[bar]=0;
        LowerBuffer2[bar]=0;
       }
      limit=MaxBarBB;
     }
for(bar=limit;bar>=0;bar--)
   {       
     sum=0.0;
     midline=T3MovingBuffer[bar];
     kk=bar+Bands_Period-1;
     while(kk>=bar)
      {
       priceswing=PriceSeries(Input_Price_Customs,kk)-midline;
       sum+=priceswing*priceswing;
       kk--;
      }
     deviation2=Bands_Deviations*MathSqrt(sum/Bands_Period);     
     deviation1=0.5*deviation2;
     deviation3=1.5*deviation2;
     if (Bands_Smooth>1)
      {
       //----+ Die Berechnung und T3 die Glättung Bollinger Bands      
       //----+ ------------------------------------------------------+        
       //----+ 7 parallele Aufrufe zur Funktion T3Series 
       //      nach Nummern 1, 2, 3, 4, 5, 6. 
       //----+ Die Parameter nT3.Length ändern sich nicht an jedem Bar 
       //      (nT3.din=0)
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(1,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline+deviation3,bar,reset);
       //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
       if(reset!=0)return(-1); 
       UpperBuffer3[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(2,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline+deviation2,bar,reset);
       //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
       if(reset!=0)return(-1); 
       UpperBuffer2[bar]=Resalt; 
       //----+ ------------------------------------------------------+       
       Resalt=T3Series(3,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline+deviation1,bar,reset);
       //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
       if(reset!=0)return(-1); 
       UpperBuffer1[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(4,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline-deviation1,bar,reset);
       //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
       if(reset!=0)return(-1); 
       LowerBuffer1[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(5,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline-deviation2,bar,reset);
       //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
       if(reset!=0)return(-1); 
       LowerBuffer2[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(6,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline-deviation3,bar,reset);
       //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
       if(reset!=0)return(-1); 
       LowerBuffer3[bar]=Resalt;        
       //----+ ------------------------------------------------------+ 
      }
     else 
      {
       //----+ Die Berechnung Bollinger Bands ohne T3 Glättung 
       UpperBuffer3[bar]=midline+deviation3; 
       UpperBuffer2[bar]=midline+deviation2;
       UpperBuffer1[bar]=midline+deviation1;
       LowerBuffer1[bar]=midline-deviation1;
       LowerBuffer2[bar]=midline-deviation2;
       LowerBuffer3[bar]=midline-deviation3;
      }
      
   }
//---- Das Ende der Berechnung der Indikator-Werte
   return(0);
  }
//+-------------------------------------------------------------------+



Funktion ParMASeries()

Das Beispiel des Aufrufs der Funktion ParMASeries() (ParMA Muving mit zusätzlicher Glättung JMA):

/*
Der gleitende Mittelwert ParMA, der auf Basis der parabolischen 
Regression mit Bändern berechnet ist 
 
Für  die Arbeit  des Indikators  müssen  die Daten 
JJMASeries.mqh 
ParMASeries.mqh 
PriceSeries.mqh 
im Verzeichnis: MetaTrader\experts\include\ abgelegt werden 
Heiken Ashi#.mq4
im Verzeichnis: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+ 
//|                                                       JParMA.mq4 |
//|                       ParMA MQL4 CODE: Copyright © 2006, alexjou |
//|             JParMA Indicator: Copyright © 2006, Nikolay Kositsin |
//+------------------------------------------------------------------+ 
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- Darstellung des Indikators im Hauptfenster
#property indicator_chart_window
//---- die Anzahl der Indikatorpuffers
#property indicator_buffers 1
//---- die Farbe des Indikators 
#property indicator_color1 Red
//---- Eingabeparameter des Indikators 
extern int MA_Period  = 8; // Die Periode ParMA
extern int Length = 3;   // Die Glättungstiefe 
// Der Parameter, der sich im Bereich zwischen -100 ... +100 ändert, 
//beeinflusst auf die Qualität des vorübergehenden Prozess; 
extern int Phase  = 100;
extern int Shift  = 0;   // Die Verschiebung des Indikators entlang der Zeitachse 
//Die Wahl der Preise, nachdem der Indikator berechnet wird 
/*(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 High, 12-Heiken Ashi Low, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- Indikatorpuffers
double IndBuffer[];
//---- die Variablen mit Gleitkomma 
double JResalt, Price, Resalt;
//+------------------------------------------------------------------+  
//----+ Eingabe der Funktion JJMASeries 
//----+ Eingabe der Funktion JJMASeriesResize 
//----+ Eingabe der Funktion JJMASeriesAlert  
//----+ Eingabe der Funktion JMA_ErrDescr  
#include <JJMASeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Eingabe der Funktion ParMAMASeries 
//----+ Eingabe der Funktion ParMASeriesResize 
//----+ Eingabe der Funktion ParMASeriesAlert 
//----+ Eingabe der Funktion ParMA_ErrDescr 
#include <ParMASeries.mqh> 
//+------------------------------------------------------------------+  
//----+ Eingabe der Funktion PriceSeries
//----+ Eingabe der Funktion PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+   
//| JParMA initialization function                                   |
//+------------------------------------------------------------------+ 
int init()
 {
  //---- Einstellung der Abbildungsgenauigkeit des Indikatorsformats 
  IndicatorDigits(Digits);
  //---- Definieren des Zeichenstils vom Chart 
  SetIndexStyle(0, DRAW_LINE);
  //---- 1 Indikatorpuffer wurde für die Zählung verwendet 
  SetIndexBuffer(0, IndBuffer);
  //----  Horizontale Verschiebung der Indikator-Linie 
  SetIndexShift (0, Shift); 
  //---- Die Einstellung der Indikator-Werten, die im Chart unsichtbar
  //     werden
  SetIndexEmptyValue(0, 0.0); 
  //---- Die Namen für Datenfenster und Labels für Unterfenster 
  IndicatorShortName ("JParMA( Length="+Length+", Phase="+Phase+", Shift="+Shift+")");   
  SetIndexLabel(0, "JParMA Line");
  //---- Die Bestimmung der Nummer des Bars, von der der Indikator
         entsteht 
  SetIndexDrawBegin(0, MA_Period);
  //----+ Die Änderung der Größe bei Puffervariablen der Funktion JJMASeries, 
  //nJMAnumber=1(Ein Aufruf zur Funktion JJMASeries)
  if (JJMASeriesResize(1)!=1)return(-1);
  //----+ Die Änderung der Größe bei Puffervariablen der Funktion ParMASeries, 
  //nParMAnumber=1(Ein Aufruf zur Funktion ParMASeries)
  if (ParMASeriesResize(1)!=1)return(-1);
  //---- Einstellung der Warnungen für nicht akzeptablen Werte der externen Variablen
  JJMASeriesAlert (0,"Length",Length);
  JJMASeriesAlert (1,"Phase", Phase );
  ParMASeriesAlert(0,"MA_Period",MA_Period);
  PriceSeriesAlert(Input_Price_Customs);
  return(0);
 }
//+------------------------------------------------------------------+ 
//| JParMA iteration function                                        |
//+------------------------------------------------------------------+ 
int start()
 {
 //---- Die Überprüfung der Anzahl der Bars , damit sie ausreichend für die Berechnung wären
if (Bars-1<MA_Period)return(0);
//----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars
int reset,MaxBar,MaxBarP,bar,Limit,counted_bars=IndicatorCounted();
//---- Überprüfung auf mögliche Fehler
if (counted_bars<0)return(-1);
//---- das letzte berechnete Bar muss neuberechnet werden 
if (counted_bars>0) counted_bars--;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//Es werden alle Bars neuberechnet
MaxBar=Bars-1; MaxBarP=MaxBar-MA_Period;
//---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung  
//Es werden alle neue Bars neuberechnet 
Limit=Bars-counted_bars-1; 
 
//---- Die Berechnung des Indikators
for (bar=Limit; bar>=0; bar--)
   { 
    //----+ 
     Price=PriceSeries(Input_Price_Customs,bar);
     //----+ Die Erhaltung des Anfangsindikators
     //----+ Ein Aufruf zur Funktion ParMASeries nach der Nummer 0
     Resalt=ParMASeries(0,MaxBar,Limit,MA_Period,Price,bar,reset); 
     //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
     if(reset!=0)return(-1);
     //----+ JMA die Glättung des erhaltenden Indikators, 
     //der Parameter nJMA.MaxBar wurde um MA_Period verringert 
     //----+ Ein Aufruf zur Funktion JJMASeries зnach der Nummer 0, 
     // Die Parameter nJMA.Phase und nJMA.Length ändern sich nicht an jedem Bar
     // (nJMA.din=0)
     JResalt=JJMASeries(0,0,MaxBarP,Limit,Phase,Length,Resalt,bar,reset);
     //----+  Überprüfung auf die Abwesenheit des Fehlers in der vorherigen Operation
     if(reset!=0)return(-1);
     IndBuffer[bar]=JResalt;
   }
 //----
  return(0);
 }
 //+-------------------------------------------------------------------+
An allen Indikatoren wird die Funktion PriceSeries() statt dem normalerweise angewendeten Array von der Zeitanordnung Close[] verwendet, bei deren Anwendung kein Problem auftreten soll:
double  PriceSeries(int Input_Price_Customs, int bar)

Der Eingabeparameter Input_Price_Customs kann sich von 0 bis 14 ändern. Abhängig vom Wert dieses Parameters liefert die Funktion die Preiswerte für das aktuelle Chart nach der Nummer des Bars, der als zweite Parameter angewendet wird: 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 High, 12-Heiken Ashi Low, 13-Heiken Ashi Open, 14-Heiken Ashi Close. Wenn es notwendig ist, kann man in der Funktion andere algebraische Daten schreiben, um die Eingangspreise basierend auf Arrays der Zeitreihenanordnungen zu definieren. Die Indikatoren mit der Verwendung der Funktion PriceSeries() sind sehr bequem bei der Optimierung und dem Test der Experten.


Fazit

Im Archiv NK_library.zip sind über 100 Indikatoren, die mit der Verwendung dieser Algorithmen geschrieben wurden. Diese Beispiele sind mehr als genug, um die erwähnten Funktionen zu verwenden, und dadurch andere Indikatoren zu schreiben. Alle Indikatoren aus dem Archiv mit diesen Versionen der Glättungsfunktionen funktionieren mit Experten ohne Fehler. Außer der Indikatoren mit den Namen, deren Name-ende mit HTF beendet. Diese Indikatoren wegen ihrer Berechnungsweise können mit Experten nicht zusammen verwendet werden! Die Indikatoren aus dem Archiv muss im Ordner des Client-Terminals: \MetaTrader\EXPERTS\indicators gespeichert werden. Die Funktionen werden im Archiv des Ordners INCLUDE sein. Den ganzen Inhalt dieses Ordners muss im Ordner des Client-Terminals: \MetaTrader\EXPERTS\INCLUDE gespeichert werden.