English Русский Español 日本語 Português
preview
Von der Grundstufe bis zur Mittelstufe: Indikator (III)

Von der Grundstufe bis zur Mittelstufe: Indikator (III)

MetaTrader 5Beispiele |
10 2
CODE X
CODE X

Im vorherigen Artikel „Von der Grundstufe zur Mittelstufe: Indikatoren (II)“ haben wir viel gelernt, denn wir haben gezeigt, wie man einen gleitenden Durchschnitt auf sehr einfache, praktische und voll funktionsfähige Weise implementiert. Das Gezeigte kann jedoch nur als kurze Einführung in die Welt der MQL5-Programmierung betrachtet werden, da das Material recht grundlegend, einfach und überschaubar ist. Aber wir können noch viel mehr tun.

Bemühen Sie sich also, die hier vorgestellten Konzepte zu verstehen. Kopieren Sie nicht einfach den Code, und denken Sie nicht, dass, wenn Sie es nicht können, es auch niemand anderes kann. Das Verständnis des Konzepts ist wichtiger als das Verständnis des Codes selbst, denn der Code kann sich ändern, je nachdem, wer ihn schreibt, während das Konzept immer bestehen bleibt. Wir werden mit etwas sehr Einfachem beginnen, denn was Sie sehen werden, kann sehr komplex werden, wenn wir plötzlich bestimmte Funktionen anwenden.


Ein Indikator und mehrere grafische Darstellungen

Wahrscheinlich haben Sie schon einmal gesehen, wie jemand ein System oder ein operatives System programmiert oder sogar versucht, es zu erstellen, um an den Finanzmärkten Geld zu verdienen. Es ist nicht ungewöhnlich, dass viele dieser Systeme verschiedene gleitende Durchschnitte verwenden, die in vielen Fällen in umgekehrter Reihenfolge angewendet werden. Darüber hinaus gibt es Kanalsysteme wie die berühmten Bollinger-Bänder, die auf zwei gleitenden Durchschnitten beruhen: einer stellt das obere Band und der andere das untere Band dar. Aber wir sind nicht hier, um zu erklären, wie ein solches System für den Handel auf dem Markt verwendet werden kann. Unser Ziel ist es, zu zeigen, wie etwas Ähnliches auf einfache und praktische Weise erreicht werden kann.

Im Fall der Bollinger-Bänder, die wir als Beispiel verwenden (aber es könnte auch etwas anderes sein), haben wir zwei Linien (manchmal drei), von denen eine den inneren Durchschnitt des Kanals darstellt. Aber wir wollen es einfach halten und mit zwei Zeilen arbeiten, damit es leichter zu verstehen ist, wie man eine beliebige Anzahl von Zeilen implementiert. Für den Anfang verwenden wir den unten stehenden Code.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buffer[];
11. //+------------------------------------------------------------------+
12. int OnInit()
13. {
14.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
15. 
16.    return INIT_SUCCEEDED;
17. };
18. //+------------------------------------------------------------------+
19. int OnCalculate(const int rates_total, const int prev_calculated, const datetime &Time[], const double &Open[], const double &High[], const double &Low[], const double &Close[], const long &TickVolume[], const long &Volume[], const int &Spread[])
20. {
21.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
22.        gl_buffer[c] = High[c];
23. 
24.    return rates_total;
25. };
26. //+------------------------------------------------------------------+

Code 01

Ich glaube nicht, dass es notwendig ist, zu zeigen, was dieser Code tut, wenn er auf einem Chart gestartet und ausgeführt wird, da er in den beiden vorhergehenden Artikeln ausführlich erklärt wurde. Wir müssen uns nur ansehen, was in der Ereignisbehandlungsfunktion, in diesem Fall in der Funktion OnCalculate, geschieht. Sie sehen, dass wir hier ausdrücklich den Maximalwert verwenden. Mit anderen Worten, wir erhalten eine grafische Darstellung, die dem Höchststand jedes Balkens folgt, da wir keine Glättungsberechnungen durchführen. Und ja, die Berechnungen des gleitenden Durchschnitts zielen genau darauf ab, die Kurve zu glätten, die auf dem Bildschirm grafisch dargestellt wird, indem ein Durchschnitt aus mehreren in der Berechnung verwendeten Werten gebildet wird. Dies erfordert jedoch die Erläuterung von mathematischem Material, was den Rahmen dieses Artikels sprengen würde.

Nun gut, dieser Indikator, der in Code 01 gezeigt wird, funktioniert perfekt. Bitte beachten Sie, dass wir die erweiterte Version der Funktion OnCalculate verwenden. Der Grund dafür wird jetzt deutlich werden. Nun habe ich eine Frage an Sie: Wie können wir dem Chart eine zweite grafische Linie hinzufügen? Ziel ist es, z. B. die Tiefststände eines jeden Balkens anzuzeigen. Man könnte meinen, dass es ausreicht, einen neuen Indikator zu erstellen und Zeile 22 des Codes so zu ändern, dass Low anstelle von High verwendet wird. Und das stimmt. Diese Idee ist keineswegs falsch – sie funktioniert.

Dies würde jedoch die Sache verkomplizieren, da Sie dann zwei verschiedene Indikatoren im Chart hätten. Ein kleiner Punkt: Jeder Indikator würde nur eine grafische Darstellungslinie verarbeiten. Es gibt jedoch eine bessere Möglichkeit, diese beiden Indikatoren in einem einzigen Code zusammenzufassen. Zu zeigen, wie das geht, ist das Ziel dieses Themas. Ich weiß, dass es auf den ersten Blick kompliziert erscheinen mag, aber wenn Sie verstehen, was hier gezeigt wird, werden Sie in der Lage sein, jeden Indikator mit mehreren grafischen Darstellungslinien zu erstellen. Vergessen Sie nicht, dass es sich hier um die einfachste Methode handelt, dies zu tun. Später werden wir, wenn Sie es wünschen, eine fortgeschrittenere Form erforschen.

Wir werden also Code 01 ändern, um eine zweite grafische Darstellungslinie zu erstellen. Wir werden dies Schritt für Schritt tun, damit jeder mitverfolgen und verstehen kann, wie es abläuft.

Als Erstes muss ein neuer Puffer erstellt werden, der die neuen grafischen Darstellungsdaten aufnehmen soll. Erinnern Sie sich daran, dass der von uns verwendete DRAW_LINE-Typ einen Puffer für jede Information der grafischen Darstellung benötigt. Daraus ergeben sich die folgenden Konsequenzen:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buff_max[],
11.          gl_buff_min[];
12. //+------------------------------------------------------------------+
                   .
                   .
                   .

Code 02

Code 02 zeigt einen Teil dessen, was wir implementieren werden, da wir dies Schritt für Schritt tun werden – das wird einfacher sein. Bitte beachten Sie, dass wir den Puffernamen in Zeile 10 geändert und in Zeile 11 einen neuen hinzugefügt haben. Auf diese Weise beginnen wir mit der Umsetzung der zweiten grafischen Darstellungslinie. Wir werden mit dem nächsten Schritt schneller fortfahren, um sicherzustellen, dass alles richtig gemacht wird. Danach erhalten wir den folgenden Code:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buff_max[],
11.          gl_buff_min[];
12. //+------------------------------------------------------------------+
13. int OnInit()
14. {
15.    SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
16.    SetIndexBuffer(1, gl_buff_min, INDICATOR_DATA);
17. 
18.    return INIT_SUCCEEDED;
19. };
20. //+------------------------------------------------------------------+
21. int OnCalculate(const int rates_total, const int prev_calculated, const datetime &Time[], const double &Open[], const double &High[], const double &Low[], const double &Close[], const long &TickVolume[], const long &Volume[], const int &Spread[])
22. {
23.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
24.    {
25.       gl_buff_max[c] = High[c];
26.       gl_buff_min[c] = Low[c];
27.    }
28. 
29.    return rates_total;
30. };
31. //+------------------------------------------------------------------+

Code 03

Nun gut, das ist der wichtigste Teil. Dieser Code hat jedoch ein kleines Problem, das wir noch lösen müssen. Doch zunächst müssen wir verstehen, was dieses Problem ist und warum es auftritt. Beachten Sie, dass wir in Zeile 16 einen neuen Index erstellen. Jeder im Indikator verwendete Puffer, den MetaTrader 5 pflegen und überwachen muss, benötigt einen eindeutigen Index. Sobald Zeile 16 definiert ist, kann der Puffer wie in Zeile 26 gezeigt verwendet werden.

Dieser Puffer, der im grafischen Darstellungssystem verwendet wird, kann verschiedene Funktionen erfüllen. Im Moment werden wir nur den Typ verwenden, der Daten für die Darstellung bestimmter Elemente im Chart enthalten soll. Also gut, Code 03 kann kompiliert werden. Bei der Anwendung auf das Chart ergibt sich jedoch folgendes Bild:

Abbildung 01

„Aber was ist hier passiert? Ich verstehe nicht, warum wir nur die grafische Darstellungslinie für die Mindestwerte sehen?“ Der Grund dafür ist, dass wir MetaTrader 5 mitteilen, dass der Indikator nur einen grafischen Darstellungspuffer und dessen Informationen enthält. Sie können dies in den Zeilen 07 und 08 sehen. Da wir eigentlich zwei Puffer und zwei Zeilen haben, müssen wir nur die in den Zeilen 07 und 08 genannten Informationen ändern. In diesem Fall ändern wir den Code wie unten gezeigt:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         2
08. #property indicator_plots           2
09. //+----------------+
10. double   gl_buff_max[],
11.          gl_buff_min[];
12. //+------------------------------------------------------------------+
                   .
                   .
                   .

Code 04

Bitte beachten Sie, dass wir nur die oben genannten Zeilen geändert haben. Wenn der Indikator jedoch auf das Chart angewendet wird, ergibt sich folgendes Bild:

Abbildung 02

„Schon wieder? Jetzt verstehe ich es wirklich nicht mehr. Hätte der Code nicht zwei Zeilen grafisch darstellen müssen? Warum sehe ich nur einen?“ Beruhigen Sie sich, liebe Leser. Haben Sie Geduld. Machen Sie sich keine Sorgen. Der Grund, warum Sie nur eine Zeile sehen, ist, dass auf die zweite Zeile keine Farbe angewendet wird. Um dies zu verdeutlichen, sehen Sie sich an, wie der Indikator konfiguriert ist:

Animation 01

Bitte beachten Sie, dass es für die zweite Zeile keine Farbe gibt. Selbst wenn man versucht, ihm einen Farbwert zuzuweisen, erscheint er nicht. Um dieses Problem zu lösen, müssen Sie den Compiler anweisen, die zweite Zeile zu reservieren und zu erstellen. Zu diesem Zweck müssen Sie den Code erneut ändern, wie unten gezeigt:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrRed
06. //+----------------+
07. #property indicator_type2           DRAW_LINE
08. #property indicator_color2          clrGreen
09. //+----------------+
10. #property indicator_buffers         2
11. #property indicator_plots           2
12. //+----------------+
13. double   gl_buff_max[],
14.          gl_buff_min[];
15. //+------------------------------------------------------------------+
                   .
                   .
                   .

Code 05

Schauen wir uns an, was dem Code hinzugefügt wurde, den Sie hier in Code 05 sehen können. Um es visueller zu gestalten, haben wir verschiedene Farben verwendet. Wenn Sie den Indikator also auf einem Chart platzieren, können Sie dies sehen:

Abbildung 03

Sehen Sie, wie einfach es ist, verschiedene grafische Darstellungslinien in ein und demselben Indikator zu implementieren? Alles, was Sie tun müssen, ist, nach und nach Elemente hinzuzufügen, wobei Sie wissen, was Sie tun. Da wir hier keine Berechnungen durchführen, werden sich die Linien nie überschneiden. Das wäre in etwa dasselbe, als wenn wir Bandindikatoren einsetzen würden. Der Unterschied besteht darin, dass eine Linie Werte von einem Band und die andere von einem anderen Band erhält, wodurch etwas Ähnliches wie die berühmten Bollinger-Bänder entsteht. Das ist ein sehr interessantes Thema, nicht wahr?

Ich glaube, dass Sie jetzt in der Lage sein werden, verschiedene Arten und Stile von Indikatoren zu erstellen, die allein auf diesem Wissen basieren. Aber bevor wir uns näher mit diesem Thema befassen – denn dieser Teil der Programmierung ist sehr interessant – möchten Sie nicht den Indikator in Abbildung 03 so verändern, dass die Linien farbig sind? „Es sieht schwierig aus“. Aber ist es wirklich schwierig, oder wissen Sie immer noch nicht, wie Sie vorgehen sollen? Schauen wir mal. Deshalb werden wir uns einem neuen Thema zuwenden.


Farbige Linien in der grafischen Darstellung

Ein Punkt, der die Aufmerksamkeit der Menschen auf sich zieht und sie am meisten erregt, ist ein Indikator mit Linien, die ihre Farbe ändern. Bis jetzt haben wir ein sehr einfaches System geschaffen, bei dem entweder die eine oder die andere Farbe verwendet werden kann – aber was ist mit dem Wechsel der Farben? „Es scheint sehr kompliziert zu sein, vor allem für jemanden wie mich, der gerade erst anfängt, die MQL5-Programmierung zu lernen“. Ich verstehe Sie, liebe Leserin, lieber Leser. Aber die Tatsache, dass Sie gerade erst anfangen, bedeutet nicht, dass Sie sich nicht für das interessieren können, was hier gezeigt wird. Und NEIN, es ist nicht schwierig, einen Indikator zu erstellen, dessen Linien grafisch in mehreren Farben dargestellt werden – es ist nur ein bisschen anders.

Um Ihnen eine Vorstellung davon zu geben, wovon wir sprechen, nehmen wir den Code, der im vorherigen Thema implementiert wurde. Um das Ergebnis von Bild 03 anzuzeigen, sollte es etwas ähnliches enthalten wie das, was wir unten sehen:

//+------------------------------------------------------------------+
#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#property indicator_type1           DRAW_LINE
#property indicator_color1          clrRed
//+----------------+
#property indicator_type2           DRAW_LINE
#property indicator_color2          clrGreen
//+----------------+
#property indicator_buffers         2
#property indicator_plots           2
//+----------------+
double   gl_buff_max[],
         gl_buff_min[];
//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
   SetIndexBuffer(1, gl_buff_min, INDICATOR_DATA);

   return INIT_SUCCEEDED;
};
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const datetime &Time[], const double &Open[], const double &High[], const double &Low[], const double &Close[], const long &TickVolume[], const long &Volume[], const int &Spread[])
{
   for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
   {
      gl_buff_max[c] = High[c];
      gl_buff_min[c] = Low[c];
   }

   return rates_total;
};
//+------------------------------------------------------------------+

Code 06

Code 06 ist das Ergebnis aller Änderungen, die an Code 01 vorgenommen wurden, und ermöglicht es uns, zwei Linien in das Chart einzuzeichnen. Um diese Linien nun mehrfarbig zu machen, müssen wir nur die folgenden Schritte ausführen.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_COLOR_LINE
05. #property indicator_color1          clrMaroon, clrTomato, clrBlue
06. //+----------------+
07. #property indicator_type2           DRAW_COLOR_LINE
08. #property indicator_color2          clrGreen, clrPaleGreen
09. //+----------------+
                   .
                   .
                   .

Code 07

Vergleichen wir nun den Code 06 mit dem Code 07. Bitte beachten Sie, dass wir den Typ des Objekts, das in der grafischen Darstellung verwendet wird, von DRAW_LINE auf DRAW_COLOR_LINE geändert haben. Danach können wir in der Eigenschaft Farbe für jede der Linien mehr als eine Farbe angeben. Die Anzahl der Farben ist völlig willkürlich und kann laut der MQL5-Dokumentation maximal 64 Werte haben. In der Tat, in einer Zeile haben wir drei Farben erklärt, und in der anderen – zwei. Sie können jedoch alle Farben Ihrer Wahl verwenden. Aber das ist nicht genug. Wir müssen noch ein paar Dinge für MetaTrader 5 implementieren, damit wir verstehen, was wir tun wollen.

Und jetzt passen Sie auf. Bei der Verwendung eines mehrfarbigen grafischen Systems benötigen wir einen zusätzlichen Puffer, wie in der Abbildung unten zu sehen ist, die in der Dokumentation zu finden ist.

Abbildung 04

Wie Sie sehen, benötigen alle diese hervorgehobenen Punkte einen Farbpuffer. Ohne diesen Puffer kann der MetaTrader 5 nicht wissen, welche Farbe er verwenden soll. Die nächste Änderung, die wir vornehmen müssen, betrifft daher die Pufferdeklaration. Dies ist in dem nachstehenden Codefragment zu sehen:

                   .
                   .
                   .
09. //+----------------+
10. #property indicator_buffers         4
11. #property indicator_plots           2
12. //+----------------+
13. double   gl_buff_max[],
14.          gl_buff_min[],
15.          gl_color_max[],
16.          gl_color_min[];
17. //+------------------------------------------------------------------+
                   .
                   .
                   .

Code 08

In Codefragment 08 definieren wir unsere Puffer. Bitte beachten Sie, dass wir in Zeile 10 angeben, dass wir vier Puffer benötigen, aber warum genau vier, wenn wir nur zwei Linien grafisch darstellen wollen? Der Grund dafür ist, dass wir einen Puffer für die dargestellten Werte und einen weiteren Puffer für jede Farbe benötigen. Stellen Sie sich eine kleine Struktur mit zwei Werten vor. Obwohl MetaTrader 5 dafür keine Struktur verwendet, müssen wir uns das so vorstellen. Und da der MetaTrader 5 keine Strukturen für eine solche Modellierung verwendet, benötigen wir zwei Puffer. Da wir aber zwei Linien zeichnen müssen, benötigen wir letztlich vier Puffer. Sie werden ab Zeile 30 deklariert, wie in Codefragment 08 zu sehen.

Großartig, jetzt fehlt nur noch der letzte Schritt. Wir demonstrieren dies in dem folgenden Ausschnitt:

                   .
                   .
                   .
17. //+------------------------------------------------------------------+
18. int OnInit()
19. {
20.     SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
21.     SetIndexBuffer(1, gl_color_max, INDICATOR_COLOR_INDEX);
22.     SetIndexBuffer(2, gl_buff_min, INDICATOR_DATA);
23.     SetIndexBuffer(3, gl_color_min, INDICATOR_COLOR_INDEX);
24. 
25.     return INIT_SUCCEEDED;
26. };
27. //+------------------------------------------------------------------+
28. int OnCalculate(const int rates_total, const int prev_calculated, const datetime &Time[], const double &Open[], const double &High[], const double &Low[], const double &Close[], const long &TickVolume[], const long &Volume[], const int &Spread[])
29. {
30.     double  mhs = 0,
31.             mhi = 0,
32.             ml = 0;
33.     const double desv = 0.01;
34. 
35.     for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
36.     {
37.         gl_color_max[c] = (mhi > High[c] ? 0 : (mhs < High[c] ? 1 : 2));
38.         mhs = mhi = gl_buff_max[c] = High[c];
39.         mhs += (mhs * desv);
40.         mhi -= (mhi * desv);
41.         gl_color_min[c] = (ml < Low[c] ? 0 : 1);
42.         ml = gl_buff_min[c] = Low[c];
43.     }
44. 
45.     return rates_total;
46. };
47. //+------------------------------------------------------------------+

Code 09

Bevor wir erklären, was wir im Code-Snippet 09 tun, sehen wir uns das Ergebnis dieses Indikators an, wenn er auf den Chart eines beliebigen Instruments angewendet wird. Dies ist auf dem nachstehenden Bild zu sehen:

Abbildung 05

Was wir sehen, dient nur zur Veranschaulichung, da dieser Indikator nur aus pädagogischen Gründen erstellt wurde. Es ist jedoch offensichtlich, dass der Code für die Initialisierungsphase des Indikators kaum verändert wurde – lediglich die Zeilen 21 und 23 wurden hinzugefügt. Es ist jedoch wichtig, dass Sie verstehen, was jede dieser neuen Linien bewirkt. Zunächst ist zu beachten, dass jeder Puffer einen eigenen Bezeichner hat. Es spielt keine Rolle, was wir in ihnen zu speichern beabsichtigen; jeder muss ihren eigenen Bezeichner haben, sonst kommt MetaTrader 5 bei ihrer Verwendung durcheinander.

In diesem Fall ist es sehr wichtig, alles in einer bestimmten Reihenfolge zu deklarieren. Das heißt, bevor wir den nächsten Datenpuffer deklarieren, müssen wir alle Datenpuffer deklarieren, die in einer bestimmten grafischen Darstellungslinie verwendet werden. Dazu gehört hier auch der Farbpuffer. Wenn wir Daten oder Farbpuffer in einer unlogischen Reihenfolge deklarieren, werden Sie nicht das gewünschte Ergebnis erzielen. Seien Sie daher vorsichtig, wenn Sie hier Elemente deklarieren. Die Reihenfolge der Dinge beeinflusst das Endergebnis. Nach der Initialisierung können wir uns auf die Prozedur konzentrieren, die das von MetaTrader 5 ausgelöste Calculate-Ereignis behandeln wird.

Beachten Sie, dass wir in diesem Fall einige Berechnungen und Prüfungen durchführen. Dies liegt daran, dass wir MetaTrader 5 mitteilen müssen, welche der im Code 07 definierten Farben beim Zeichnen der Linie auf dem Bildschirm verwendet werden soll. „Aber Moment, ich verstehe nicht, wie das geht. Hier haben wir nur Zahlen, während es im Code 07 Farbwerte gab. Woher weiß MetaTrader 5, welche Farbe er verwenden soll?“

Nun, mein lieber Leser, an dieser Stelle ist es wichtig zu verstehen, was bereits in einem anderen Artikel erklärt wurde: was Arrays sind. Was wir in Code 07 haben, sind Farbarrays. Jede Farbe befindet sich an einem bestimmten Array-Index. Daher verwenden wir in den Zeilen 21 und 23 die Enumeration INDICATOR_COLOR_INDEX. Wir geben nicht an, welche Farbe verwendet werden soll, sondern den Index der Farbe in einem bestimmten Feld. Aber welches Feld? Wenn wir zwei Arrays im Code 07 haben, wie wird MetaTrader 5 wissen, welches zu verwenden ist?

Hier kommt ein weiteres, kürzlich diskutiertes Thema ins Spiel. Mit anderen Worten: Die Reihenfolge der Komponenten wirkt sich auf das Endergebnis aus. Da wir diese Art der grafischen Darstellung üblicherweise in einer singulären Form verwenden (d.h. ein Indikator, eine Linie), verwendet MetaTrader 5 das Farbschema, das direkt mit dem Bezeichner des dargestellten Typs verbunden ist. Ich weiß, das mag verwirrend erscheinen, aber beachten Sie, dass in den Zeilen 04 und 05 ein Bezeichnerwert steht – in diesem Fall die Zahl eins. In den Zeilen 07 und 08 haben wir einen weiteren Bezeichner – die Zahl zwei. Wenn wir also einen Wert mit einem Indikator verknüpfen, der grafisch dargestellt werden soll, wird der Compiler diesen Bezeichner verwenden, um zu wissen, welches Farbschema anzuwenden ist.

Zur Veranschaulichung haben wir in jeder Deklaration in Code 07 eine andere Anzahl von Farben definiert, damit Sie dies beim Üben mit echtem Code nachvollziehen können.

Obwohl dieser Teil etwas verwirrend ist – gerade weil wir alles statisch verwenden und mehr als eine grafische Darstellungslinie gleichzeitig platzieren – werden Sie in der Praxis feststellen, dass es eigentlich recht einfach ist, zu verstehen, wie man solche Elemente deklariert und verwendet.

Wenn der Nutzer das Farbschema ändern möchte, wird er in jedem Fall auf eine ähnliche Schnittstelle wie diese zugreifen:

Abbildung 06

Beachten Sie, dass der Nutzer dank der Deklarationen in den Zeilen 05 und 08 des Codes 07 in der Lage ist, mehr als eine Farbe zu konfigurieren. Daher ist es ratsam, die Schnittstelle so klar und einfach wie möglich zu gestalten. Andernfalls kann der Code zwar für bestimmte Arten von Operationen recht nützlich sein, aber der Nutzer wird keine guten Erfahrungen mit ihm machen.

Die Codes finden Sie im Anhang, damit Sie lernen können, wie Sie mit solchen Situationen umgehen. Doch bevor ich den heutigen Artikel abschließe, möchte ich noch einen anderen Indikator besprechen, der irgendwo zwischen diesen beiden Konzepten liegt, je nachdem, wie wir ihn anwenden – es könnte ein Bandindikator oder sogar ein Indikator für das Kreuzen des gleitenden Durchschnitts sein. Um jedoch Verwirrung zu vermeiden, werden wir dies in einem neuen Thema behandeln.


Der Indikator DRAW_FILLING

Dieser Indikator ist recht interessant, da er je nach Umsetzung zu einem Indikator mit gleitendem Durchschnittsübergang oder sogar zu einem Bandindikator werden kann. Programmieranfänger finden es jedoch oft verwirrend, gerade wegen der Art und Weise, wie es deklariert werden muss. Um Ihnen zu verdeutlichen, wie einfach es ist, diese Art von Indikator zu deklarieren und zu verwenden, nehmen wir den Code 06, der zu Beginn des Artikels bereitgestellt wird, als Ausgangspunkt. Von dort aus wird es viel einfacher zu verstehen, was wir mit dem Indikator DRAW_FILLING erreichen wollen.

Wir nehmen den Code 06 als Ausgangspunkt und ändern ihn, um den Indikator DRAW_FILLING zu verstehen. Im Wesentlichen wird Code 06 wie folgt aussehen:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_FILLING
05. #property indicator_color1          clrRed, clrGreen
06. //+----------------+
07. #property indicator_buffers         2
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buff_max[],
11.          gl_buff_min[];
12. //+------------------------------------------------------------------+
13. int OnInit()
14. {
15.     SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
16.     SetIndexBuffer(1, gl_buff_min, INDICATOR_DATA);
17. 
18.     return INIT_SUCCEEDED;
19. };
20. //+------------------------------------------------------------------+
21. int OnCalculate(const int rates_total, const int prev_calculated, const datetime &Time[], const double &Open[], const double &High[], const double &Low[], const double &Close[], const long &TickVolume[], const long &Volume[], const int &Spread[])
22. {
23.     for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
24.     {
25.         gl_buff_max[c] = Open[c];
26.         gl_buff_min[c] = Close[c];
27.     }
28. 
29.     return rates_total;
30. };
31. //+------------------------------------------------------------------+

Code 10

„Interessant. Meines Wissens hat der Code 06 nur wenige Änderungen erfahren. Aber ich habe einige Zweifel in Bezug auf einige Aspekte, zum Beispiel: Warum verwenden wir in der Prozedur, die das Calculate-Ereignis behandelt, die Eröffnungs- und Schlusskurse?“ Dies geschieht, um eine Umkehrung oder ein Überkreuzen der Höchst- und Mindestwerte, wie sie in Code 10 genannt werden, auszulösen. Bitte beachten Sie, liebe Leserinnen und Leser: Von Zeit zu Zeit haben wir eine Verkaufsleiste und von Zeit zu Zeit eine Kaufleiste.

Stellen Sie sich nun vor, dass dieser DRAW_FILLING-Indikator wie ein Stoff ist, der auf beiden Seiten bedruckt ist. Wenn sich die Werte in den in den Zeilen 15 und 16 definierten Puffern kreuzen, kommt es zu einer Umkehrung, die den MetaTrader 5 veranlasst, die eine oder andere Seite des Stoffes anzuzeigen. Die Informationen, die auf dem Stoff angezeigt oder gedruckt werden sollen, werden in Zeile 05 angegeben. So können wir die Fläche in der einen oder anderen Farbe einfärben. Wenn es keine Kreuzung oder Umkehrung gäbe, würden wir nur eine der in Zeile 05 definierten Drucke oder Farben sehen.

Wir müssen jedoch ein kleines Detail beachten: Trotz der extremen Einfachheit von Code 10 sieht er, wenn er auf ein Chart angewandt wird, wie in der folgenden Abbildung dargestellt aus:

Abbildung 07

Es sieht nicht sehr ansprechend aus und kann je nach Art der berechneten und grafisch dargestellten Informationen sogar ziemlich verwirrend sein. In Zeile 05 hat der Nutzer jedoch die Möglichkeit, einige Daten zu konfigurieren, wie in der folgenden Abbildung dargestellt:

Abbildung 08

Das heißt, je nach Art der geplanten Arbeit kann dieser Indikator vom Typ DRAW_FILLING recht interessant sein. Allerdings wird dieser Indikator gerade aus dem Grund, der in Abbildung 07 zu erkennen ist, meist nicht direkt im Haupt-Chart, sondern in einem separaten Fenster angezeigt. Dann könnte jemand anfangen zu denken: „Mein Freund, alles wird sehr kompliziert. Ich habe gerade erst gelernt, wie man einen farbigen Indikator erstellt, und jetzt fangen Sie an, darüber zu reden, wie man ihn in einem anderen Fenster platziert? Sie präsentieren so viele Informationen, dass ich fleißig lernen muss“.

Keine Sorge, es ist nicht so entmutigend, wie es scheint. In der Tat bietet MQL5, das für die Programmierung in MetaTrader 5 entwickelt wurde, viele interessante und praktische Funktionen.

Dazu gehört auch die Möglichkeit, einen Indikator in einem separaten Fenster zu platzieren. Dieses Fenster wäre jedoch weiterhin mit dem Haupt-Chart verknüpft. Eine der einfachsten Möglichkeiten, dies zu erreichen, besteht darin, den Compiler anzuweisen, den Indikatorcode so zu generieren, dass MetaTrader 5 bei Anwendung auf ein Chart versteht, dass ein neues Fenster oder Unterfenster geöffnet werden muss. Dies geschieht durch Hinzufügen einer einzigen Zeile zum Code des Indikators. Der zuvor gezeigte Code 10 sieht also wie folgt aus:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_separate_window
05. //+----------------+
06. #property indicator_type1           DRAW_FILLING
07. #property indicator_color1          clrRed, clrGreen
08. //+----------------+
09. #property indicator_buffers         2
10. #property indicator_plots           1
11. //+----------------+
12. double   gl_buff_max[],
13.          gl_buff_min[];
14. //+------------------------------------------------------------------+
15. int OnInit()
16. {
17.     SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
18.     SetIndexBuffer(1, gl_buff_min, INDICATOR_DATA);
19. 
20.     return INIT_SUCCEEDED;
21. };
22. //+------------------------------------------------------------------+
23. int OnCalculate(const int rates_total, const int prev_calculated, const datetime &Time[], const double &Open[], const double &High[], const double &Low[], const double &Close[], const long &TickVolume[], const long &Volume[], const int &Spread[])
24. {
25.     for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
26.     {
27.         gl_buff_max[c] = Open[c];
28.         gl_buff_min[c] = Close[c];
29.     }
30. 
31.     return rates_total;
32. };
33. //+------------------------------------------------------------------+

Code 11

Bitte beachten Sie, dass der einzige Unterschied zwischen Code 10 und Code 11 genau in der Zeile 04 liegt, die in Code 10 fehlt, aber in Code 11 vorhanden ist. Nachdem Sie diesen Code kompiliert haben, können Sie MetaTrader 5 bitten, ihn dem Chart hinzuzufügen. Das Ergebnis ist, dass Bild 07, das vorher ziemlich verwirrend war, jetzt wie folgt aussieht:

Abbildung 09

Abbildung 09 ist sicherlich viel einfacher, auch wenn sie einige Nutzer bei der Interpretation dieses Charts zunächst verwirren könnte.


Abschließende Gedanken

In diesem Artikel haben wir gezeigt, wie man mit zwei verschiedenen Arten von Indikatoren arbeiten kann, die auf unterschiedliche Weise angepasst werden können. Ziel ist es, eine Anwendung zu erstellen, die den eigenen Bedürfnissen entspricht. Trotz der scheinbar einfachen Materie glaube ich, dass man mit Kreativität und Neugierde verstehen kann, dass dieser Inhalt auf andere Arten von Indikatoren ausgedehnt werden kann: DRAW_SECTION, DRAW_HISTOGRAM, DRAW_ARROW, DRAW_ZIGZAG, DRAW_BARS und DRAW_CANDLES. Sie alle funktionieren ähnlich wie die in diesem Artikel vorgestellten, obwohl wir nur zwei – oder drei, wenn wir den Typ DRAW_COLOR_LINE mitzählen – behandelt haben. Aber das ist nur ein kleines Detail.

Es ist wirklich wichtig, dass Sie üben und verstehen, dass alles, was auf einem Chart angezeigt wird, egal wie komplex es erscheinen mag, in seinem Aufbau recht einfach ist. Im Wesentlichen müssen Sie dem Compiler nur mitteilen, wie der Indikator erstellt werden soll, indem Sie eine vollständig statische Implementierung verwenden. Die Erstellung statischer Indikatoren ist einfach und macht sogar Spaß, aber der eigentliche Spaß liegt in den dynamischen Indikatoren. Wir werden das sehr bald untersuchen. In der Zwischenzeit können Sie studieren und anwenden, was wir in diesem Artikel gesehen haben, denn wir werden diese Art der Umsetzung bald viel spannender und interessanter machen.

Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/15828

Beigefügte Dateien |
Anexo.zip (3.03 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (2)
Nguyen Tuấn Anh
Nguyen Tuấn Anh | 11 Feb. 2026 in 15:25
Sehr geehrte Damen und Herren.
Ichversuche, einen benutzerdefinierten Indikator auf Basis von iBand zu erstellen.
Nach langem Suchen habe ich beschlossen, hier zu posten, vielleicht kann mir jemand helfen.
Hier ist der vollständige Indikator.
//Das ist MQL5\Indikatoren\Anhnt\iBand_Display.mq5
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   3

//--- Handlung Mitte
#property indicator_label1  "Middle"
#property indicator_type1   DRAW_LINE

//--- Plot Obere
#property indicator_label2  "Upper"
#property indicator_type2   DRAW_LINE

//--- plot Lower
#property indicator_label3  "Lower"
#property indicator_type3   DRAW_LINE

//==================================================
// Eingabeparameter
//==================================================
input int      InpBBPeriod      = 14;
input ENUM_APPLIED_PRICE inp_Applied_Price   = PRICE_MEDIAN;
input double   InpBBDeviation   = 2.0;
input int      InpBBShift       = 0;

input color    InpMiddleColor   = clrYellow;
input color    InpUpperColor    = clrYellow;
input color    InpLowerColor    = clrYellow;

input int      InpMiddleWidth   = 2;
input int      InpUpperWidth    = 2;
input int      InpLowerWidth    = 2;

input bool inp_BB_Show_Upper   = true;
input bool inp_BB_Show_Middle  = true;
input bool inp_BB_Show_Lower   = true;

input ENUM_LINE_STYLE InpMiddleStyle = STYLE_DOT;
input ENUM_LINE_STYLE InpUpperStyle  = STYLE_DOT;
input ENUM_LINE_STYLE InpLowerStyle  = STYLE_DOT;
//==================================================
#include <Anhnt/Configuration/NamingConfiguration.mqh>
//==================================================
// Indikatorpuffer
//==================================================
double MiddleBuffer[];
double UpperBuffer[];
double LowerBuffer[];

//==================================================
// Globale Variablen
//==================================================
int g_bb_handle = INVALID_HANDLE;

//https://www.mql5.com/de/docs/indicators/ibands
//--- wir behalten die Anzahl der Werte im Bollinger Bands Indikator bei

//+------------------------------------------------------------------+
int OnInit()
{
   //==================================================
   // Puffer einstellen
   //==================================================
   SetIndexBuffer(BASE_LINE,  MiddleBuffer, INDICATOR_DATA);
   SetIndexBuffer(UPPER_BAND, UpperBuffer,  INDICATOR_DATA);
   SetIndexBuffer(LOWER_BAND, LowerBuffer,  INDICATOR_DATA);

   ArraySetAsSeries(MiddleBuffer, true);
   ArraySetAsSeries(UpperBuffer,  true);
   ArraySetAsSeries(LowerBuffer,  true);   

   //================================================== 
   // INPUT-Werte auf Plots anwenden (laufzeitsicherer Weg)
   //==================================================
   PlotIndexSetInteger(BASE_LINE,  PLOT_LINE_COLOR, InpMiddleColor);
   PlotIndexSetInteger(UPPER_BAND, PLOT_LINE_COLOR, InpUpperColor);
   PlotIndexSetInteger(LOWER_BAND, PLOT_LINE_COLOR, InpLowerColor);

   PlotIndexSetInteger(BASE_LINE,  PLOT_LINE_STYLE, InpMiddleStyle);
   PlotIndexSetInteger(UPPER_BAND, PLOT_LINE_STYLE, InpUpperStyle);
   PlotIndexSetInteger(LOWER_BAND, PLOT_LINE_STYLE, InpLowerStyle);

   PlotIndexSetInteger(BASE_LINE,  PLOT_LINE_WIDTH, InpMiddleWidth);
   PlotIndexSetInteger(UPPER_BAND, PLOT_LINE_WIDTH, InpUpperWidth);
   PlotIndexSetInteger(LOWER_BAND, PLOT_LINE_WIDTH, InpLowerWidth);   

   PlotIndexSetInteger(
         BASE_LINE,
         PLOT_DRAW_TYPE,
         inp_BB_Show_Middle ? DRAW_LINE : DRAW_NONE
   );

   PlotIndexSetInteger(
         UPPER_BAND,
         PLOT_DRAW_TYPE,
         inp_BB_Show_Upper ? DRAW_LINE : DRAW_NONE
   );

   PlotIndexSetInteger(
         LOWER_BAND,
         PLOT_DRAW_TYPE,
         inp_BB_Show_Lower ? DRAW_LINE : DRAW_NONE
   );
   string name = SMT_PREFIX + SMT_BB_NAME +
                 "(" + (string)InpBBPeriod + "," +
                 DoubleToString(InpBBDeviation, 1) + ")";  
   
                                   
   IndicatorSetString(INDICATOR_SHORTNAME, name);
   //==================================================
   // iBands-Handle erstellen
   //==================================================
   g_bb_handle = iBands(
      _Symbol,
      _Period,
      InpBBPeriod,
      InpBBShift,
      InpBBDeviation,
      inp_Applied_Price
   );
   if(g_bb_handle == INVALID_HANDLE)
   {
      Print("iBand_Display INIT FAILED. Unable to create iBands handle. GetLastError = ", GetLastError());
      return INIT_FAILED;
   }
      
   Print("iBand_Display INIT SUCCESS");
   return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
int OnCalculate(
   const int rates_total,
   const int prev_calculated,
   const datetime &time[],
   const double &open[],
   const double &high[],
   const double &low[],
   const double &close[],
   const long &tick_volume[],
   const long &volume[],
   const int &spread[]
)
{
   //https://www.mql5.com/de/docs/indicators/ibands&amp;nbsp;  
   //--- warten, bis iBands bereit ist
   int calculated = BarsCalculated(g_bb_handle);
   if(calculated <= InpBBPeriod)
      return 0;   
      // Print("DEBUG from OnCalculate After Waiting BarsCalculated | Symbol=", _Symbol,
      // " | Zeitraum=", _Zeitraum,
      // " | BarsCalculated(iBands)=", calculated); 
   //--- Dieser Block wird ausgeführt, wenn der Indikator zum ersten Mal an ein Diagramm angehängt wird
   if(prev_calculated == 0)
   {
      ArrayInitialize(MiddleBuffer, EMPTY_VALUE);
      ArrayInitialize(UpperBuffer,  EMPTY_VALUE);
      ArrayInitialize(LowerBuffer,  EMPTY_VALUE);

      int to_copy = MathMin(calculated, rates_total);

      // Alle verfügbaren Daten auf einmal kopieren
      CopyBuffer(g_bb_handle, BASE_LINE,  0, to_copy, MiddleBuffer);
      CopyBuffer(g_bb_handle, UPPER_BAND, 0, to_copy, UpperBuffer);
      CopyBuffer(g_bb_handle, LOWER_BAND, 0, to_copy, LowerBuffer);
      // Print("DEBUG von OnCalculate First Initial | Symbol=", _Symbol,
      // " | Zeitraum=", _Zeitraum,
      // " | BarsCalculated(iBands)=", calculated);
      return rates_total;    
   }   
   //--- Dieser Block wird bei jedem neuen geöffneten Balken ausgeführt
   if(prev_calculated != rates_total && prev_calculated != 0)
   {
      //==================================================
   // NEXT RUNS:
   // Nur den neuesten Balken (Index 0) aktualisieren.
   // Verschieben Sie Arrays NICHT manuell (die Serie übernimmt das).
   //==================================================
      double tmp[1];
      if(CopyBuffer(g_bb_handle, BASE_LINE, 0, 1, tmp) > 0)
      MiddleBuffer[0] = tmp[0];

      if(CopyBuffer(g_bb_handle, UPPER_BAND, 0, 1, tmp) > 0)
         UpperBuffer[0] = tmp[0];

      if(CopyBuffer(g_bb_handle, LOWER_BAND, 0, 1, tmp) > 0)
         LowerBuffer[0] = tmp[0];
      return rates_total;      
   }  
   return rates_total;
}
//+------------------------------------------------------------------+

bool FillArraysFromBuffers(
   double &base_values  [],   // MiddleBuffer
   double &upper_values [],   // ObererPuffer
   double &lower_values [],   // UntererPuffer
   int shift,                 // shift = 0 → echtzeit
   int ind_handle,
   int amount
)
{
   // ANMERKUNG:
   // Derzeit nicht verwendet.
   // Wie geplant für zukünftige Helfer / EA-Logik aufbewahrt.

   ResetLastError();
   if(CopyBuffer(ind_handle, BASE_LINE,  -shift, amount, base_values) < 0)
      return false;
   if(CopyBuffer(ind_handle, UPPER_BAND, -shift, amount, upper_values) < 0)
      return false;
   if(CopyBuffer(ind_handle, LOWER_BAND, -shift, amount, lower_values) < 0)
      return false;
   return true;
}
Sehr einfach möchte ich nur ermöglichen, dass der Benutzer einzelne Linien wie BASE_LINE,UPPER_BAND,LOWER_BAND und Custom Farbe nuranzeigen oder ausblenden .
Problem 1 ist:
Sie können in Bild anhängen sehen, ich weiß nicht, warum ich grün unter Chart haben.
CODE X
CODE X | 12 Feb. 2026 in 11:11
Nguyen Tuấn Anh # :
Karos.
Ich möchte einen persönlichen Indikator auf Basis des iBand erstellen.
Depois de muita pesquisa, decidi postar aqui, talvez alguém possa me ajudar.
Aqui está o indicador completo. Ganz einfach, ich möchte, dass der Benutzer einzelne Linien, wie BASE_LINE, UPPER_BAND, LOWER_BAND und nur eine persönliche Linie anzeigen kann .
O problema 1 é:
Como você pode ver na imagem em anexo, não sei por que há uma área verde embaixo do gráfico.
Diese grünen Linien sind die Lautstärkeanzeige. Um sie zu deaktivieren, müssen Sie die Diagrammeigenschaften öffnen und den Lautstärke-Indikator ausschalten. Oder setzen Sie einfach die Volumenfarbe auf CL_NONE, damit diese grünen Linien verschwinden.
Marktsimulation: (Teil 11): Sockets (V) Marktsimulation: (Teil 11): Sockets (V)
Wir beginnen mit der Implementierung der Verbindung zwischen Excel und MetaTrader 5, aber zunächst müssen wir einige wichtige Punkte verstehen. Auf diese Weise müssen Sie sich nicht den Kopf darüber zerbrechen, warum etwas funktioniert oder nicht funktioniert. Und bevor Sie die Stirn runzeln bei der Aussicht auf die Integration von Python und Excel, lassen Sie uns sehen, wie wir (bis zu einem gewissen Grad) MetaTrader 5 durch Excel mit xlwings steuern können. Was wir hier zeigen, wird sich in erster Linie auf die Bildungsziele konzentrieren. Denken Sie aber nicht, dass wir nur das tun können, was hier behandelt wird.
Quantitative Analyse von Trends: Sammeln von Statistiken in Python Quantitative Analyse von Trends: Sammeln von Statistiken in Python
Was ist eine quantitative Trendanalyse auf dem Devisenmarkt? Wir sammeln Statistiken über Trends, deren Ausmaß und Verteilung über das Währungspaar EURUSD. Wie Sie mit Hilfe der quantitativen Trendanalyse einen profitablen Trading Expert Advisor erstellen können.
Algorithmische Handelsstrategien: KI und ihr Weg zu den goldenen Zinnen Algorithmische Handelsstrategien: KI und ihr Weg zu den goldenen Zinnen
In diesem Artikel wird ein Ansatz zur Erstellung von Handelsstrategien für Gold mithilfe von maschinellem Lernen vorgestellt. Betrachtet man den vorgeschlagenen Ansatz zur Analyse und Prognose von Zeitreihen aus verschiedenen Blickwinkeln, so lassen sich seine Vor- und Nachteile im Vergleich zu anderen Methoden zur Erstellung von Handelssystemen, die ausschließlich auf der Analyse und Prognose von Finanzzeitreihen beruhen, feststellen.
Marktsimulation (Teil 14): Sockets (VIII) Marktsimulation (Teil 14): Sockets (VIII)
Viele Programmierer könnten annehmen, dass wir auf Excel verzichten und direkt zu Python übergehen sollten, indem wir einige Pakete verwenden, die es Python ermöglichen, eine Excel-Datei für die spätere Analyse der Ergebnisse zu erzeugen. Wie bereits im vorangegangenen Artikel erwähnt, ist diese Lösung zwar für viele Programmierer die einfachste, wird aber von einigen Nutzern nicht akzeptiert werden. Und in diesem speziellen Fall hat der Nutzer immer Recht. Als Programmierer müssen wir einen Weg finden, damit alles funktioniert.