English Русский 中文 Español 日本語 Português 한국어 Français Italiano Türkçe
Wie programmiert man einen Indikator auf der Grundlage eines anderen Indikators?

Wie programmiert man einen Indikator auf der Grundlage eines anderen Indikators?

MetaTrader 5Beispiele | 12 Januar 2016, 14:48
4 602 0
Dmitry Fedoseev
Dmitry Fedoseev

Einleitung

In MQL5 können wir, außer einen neuen benutzerdefinierten Indikator aus dem Nichts zu entwickeln, wie in dem Artikel „MQL5: Erstellen Ihres eigenen Indikators“ beschrieben wird, auf der Grundlage eines anderen, in das Ausgabegerät integrierten oder selbst entwickelten Indikators einen eigenen programmieren. Es gibt zwei Möglichkeiten: die erste besteht darin, einen vorhandenen Indikator zu verbessern, neue Berechnungen und grafische Darstellungen hinzuzufügen (das geht nur bei benutzerdefinierten Indikatoren mit offenem Quellcode); die zweite darin, mithilfe Funktionen iCustom() oder IndicatorCreate() einen in das Ausgabegerät integrierten bzw. einen bereits vorhandenen benutzerdefinierten Indikator zu verwenden.

Die erste Möglichkeit. Eine grafische Darstellungsmöglichkeit hinzufügen

Schauen wir uns diese Möglichkeit zur Erstellung eines Indikators am Beispiel der Verbesserung des Indikators True_Strength_Index_ver3 aus dem Artikel „Anwenden von Indikatoren auf Indikatoren“ einmal genauer an. Wir fügen dem Indikator eine Signallinie mit der Möglichkeit zur Auswahl der Methode und des Zeitraums der Glättung hinzu. Der gesamte Vorgang umfasst 8 Schritte:

1. Erstellen einer Kopie der Datei

Wir öffnen den Indikator True_Strength_Index_ver3 in MetaEditor und speichern ihn unter einem neuen Namen, beispielsweise TSIs. Die neue Datei muss im Verzeichnis MQL5/Indicators des Stammordners des Ausgabegerätes gespeichert werden.

2. Ändern der Indikatoreigenschaften

Wir suchen die Eigenschaften indicator_buffers und indicator_plots im Programmcode des Indikators. Die Eigenschaft indicator_buffers bestimmt die Gesamtzahl aller in dem Indikator verwendeten Puffer, die Eigenschaft indicator_plots dagegen die Anzahl der Puffer, die in dem Diagramm abgebildet werden. Momentan werden in dem Indikator acht Puffer verwendet, von denen einer in dem Diagramm angezeigt wird. Wir müssen einen weiteren Puffer hinzufügen, der in dem Diagramm abgebildet werden soll. Dazu setzen wir die Werte indicator_buffers und indicator_plots jeweils um eine Position hoch.

#property indicator_buffers 8 
#property indicator_plots 2

3. Festlegen der Eigenschaften der Anzeige eines neuen Puffers

Jetzt legen wir die Eigenschaften für die Anzeige des neuen Puffers fest. Dazu verwenden wir den bereits vorhandenen Code dieses Indikators. Mit der Maus markieren und kopieren wir den gesamten Code, der die Anzeigeeigenschaften für die erste Linie des Indikators festlegt.

//---- plot TSI
#property indicator_label1 "TSI"
#property indicator_type1 DRAW_LINE
#property indicator_color1 Blue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1

Dann fügen wir ihn unterhalb der Eigenschaften für die erste Linie ein und bearbeiten ihn.

//---- plot TSI Signal
#property indicator_label2 "TSISignal" // Line name that is displayed in a pop up help when the mouse cursor is put over the line
#property indicator_type2 DRAW_LINE    // Type of buffer 
#property indicator_color2 Red         // Color of the line
#property indicator_style2 STYLE_SOLID // Style
#property indicator_width2 1           // Thickness of the line

Zunächst einmal ändern wir die laufende Nummer der Eigenschaften von 1 auf 2, da es sich um den zweiten Puffer handelt. Wir ändern die Eigenschaft indicator_label2 in TSISignal, das ist die Bezeichnung der Linie, die beim Überfahren der Linie mit dem Mauszeiger in einem Dialogfenster erscheint, und die auch im Datenfenster angezeigt wird. Die Eigenschaft indicator_type2 muss unverändert beibehalten werden, der Stand des Puffers ist als Linie anzuzeigen. Die Eigenschaft indicator_color2 ändern wir in Red; die neue Linie erscheint in roter Farbe. Die Eigenschaft indicator_style2 bleibt gleich; die Signallinie ist wie die Hauptlinie ununterbrochen. Die Eigenschaft indicator_width2 muss ebenfalls unverändert bleiben; die neue Linie hat eine Stärke von 1 Pixel.

4. Deklarieren externer Variablen

Die externen Variablen, die mithilfe des Indikators geändert werden können (Linien, die mit dem Wort „input“ beginnen), befinden sich im Programmcode unterhalb der Linieneinstellungen. Die Signallinie muss ebenfalls über eigene Parameter verfügen: Zeitraum und Art der Glättung.

Wir deklarieren die externe Variable des Typs int mit dem Wert 5 und nennen Sie sie „sp“ (smoothing period = Glättungszeitraum) sowie eine „sm“ (smoothing method = Glättungsmethode) genannte Variable vom Typ ENUM_MA_METHOD mit dem Wert MODE_EMA (die Signallinie weist standardmäßig den Glättungszeitraum 5 und die exponentielle Glättung als Methode auf). Jetzt sieht der Abschnitt des Codes, der die externen Variablen enthält, folgendermaßen aus:

input int r=25;
input int s=13;
input int sp=5;
input ENUM_MA_METHOD sm=MODE_EMA;

5. Deklarieren eines Arrays für einen neuen Puffer

Deklarieren wir nun ein Array zur Verwendung durch den Puffer des Indikators. Wir suchen im Code nach der Funktion OnInit() und finden heraus, wo sich in ihr die Aufrufe für die Funktion SetIndexBuffer() befinden, um uns durch die bereits vorhandenen Arrays von Puffern in dem Indikator zu navigieren. In dem Indikator True_Strength_Index_ver3 sind diese Arrays TSIBuffer, MTMBuffer, AbsMTMBuffer, EMA_MTMBuffer, EMA2_MTMBuffer, EMA_AbsMTMBuffer sowie EMA2_AbsMTMBuffer.

Die Funktion SetIndexBuffer() des Arrays TSIBuffer wird mithilfe des Parameters INDICATOR_DATA aufgerufen, was bedeutet, dass der Puffer in einem Diagramm angezeigt wird. Alle anderen Arrays werden mit dem Parameter INDICATOR_CALCULATIONS aufgerufen. Das heißt, dass die Arrays Hilfsmittel sind und für Zwischenberechnungen verwendet werden.

Der neue Puffer sollte in dem Schaubild angezeigt werden, deshalb deklarieren wir ihn zur Aufrechterhaltung der logischen Ordnung sowie zur einfacheren Orientierung im Code, falls später weitere Überarbeitungen des Indikators erfolgen, nach der Auszeichnung des Puffers TSIBuffer.

Somit deklarieren wir zunächst zwei Arrays für die in dem Diagramm abzubildenden Puffer und anschließend die Arrays für die Puffer, die für Zwischenberechnungen verwendet werden.

//--- indicator buffers
double TSIBuffer[];
double TSISigBuffer[]; // Array for new buffer of the signal line
double MTMBuffer[];
double AbsMTMBuffer[];
double EMA_MTMBuffer[];
double EMA2_MTMBuffer[];
double EMA_AbsMTMBuffer[];
double EMA2_AbsMTMBuffer[]; 

6. Ein Array mit einem Puffer verknüpfen

Jetzt ist ein ziemlich wichtiger Moment, der erhöhte Aufmerksamkeit und Genauigkeit erfordert: die Verknüpfung eines Arrays mit einem Indikatorpuffer. Die Verknüpfung erfolgt mithilfe der Funktion SetIndexBuffer(). Der erste Parameter des Funktionsaufrufs ist die Kennziffer des Arrays, der zweite seine Bezeichnung und der dritte die Kennung, die den Verwendungszweck des Puffers angibt. Die Puffer befinden sich unter der Registerkarte „Farben“ (Colors) des Fensters mit den Indikatoreigenschaften geordnet nach Kennziffern (erster Parameter) und werden in derselben Reihenfolge in dem Diagramm abgebildet, beginnend mit Puffer 0, dann 1 darüber usw.

Die Funktion SetIndexBuffer() muss nicht der Reihe nach für die Puffer mit den Kennziffern 0, 1, 2... aufgerufen werden, trotzdem sollten wir die Aufrufabfolge für die Funktion SetIndexBuffer() einhalten. Der Aufruf des Arrays TSISigBuffer erfolgt, nachdem wir die Funktion für das Array TSIBuffer aufgerufen haben. Der Puffer für die Hauptlinie (das Array TSIBuffer) hat die Kennziffer 0, das bedeutet, dass der nächste Puffer (das Array TSISigBuffer) die Kennziffer 1 haben muss.

Der dritte Parameter beim Aufrufen der Funktion SetIndexBuffer() für das Array TSISigBuffer ist die Konstante INDICATOR_DATA (der Puffer wird in einem Diagramm abgebildet).

SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,TSISigBuffer,INDICATOR_DATA);

Die übrigen Puffer müssen mit neuen Kennziffern versehen werden, damit die Funktion SetIndexBuffer() mit einem entsprechend heraufgesetzten Wert für den ersten Parameter aufgerufen wird.

SetIndexBuffer(0,TSIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,TSISigBuffer,INDICATOR_DATA);
SetIndexBuffer(2,MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,AbsMTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(4,EMA_MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(5,EMA2_MTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(6,EMA_AbsMTMBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(7,EMA2_AbsMTMBuffer,INDICATOR_CALCULATIONS);

Gerade in diesem Fall wird empfohlen, die Aufrufabfolge der Funktion SetIndexBufer() im Code passend zu den heraufgesetzten Kennziffern einzuhalten. Denn so sind im Falle weiterer Verbesserungen weniger Aufmerksamkeit und Arbeit erforderlich.

Jetzt haben wir acht Puffer, von denen zwei im Diagramm abgebildet werden. Wir müssen uns vergewissern, dass in den Eigenschaften der Indikatoren indicator_buffers und indicator_plots dieselben Werte angegeben sind (Schritt 2).

7. Berechnung der Werte der Signallinie

Die Signallinie bildet einen aus den Daten der Hauptlinie des Indikators ermittelten gleitenden Durchschnittswert ab. Wir müssen dafür keinerlei Berechnungen anstellen; im Lieferumfang des Ausgabegerätes ist eine Sammlung zur Berechnung gleitender Durchschnittswerte für eine Fülle von Angaben enthalten (Datei MovingAverages.mqh). Sie ist übrigens bereits im Indikatorcode angelegt (Zeile 14):

#include <MovingAverages.mqh>

Was bleibt, ist ihre Funktionen zu nutzen.

In der Funktion OnCalculate() suchen wir einen Punkt, an dem die Berechnungen der Hauptlinie des Indikators abgeschlossen sind (das Array TSIBuffer). Wir verwenden die Suchfunktion und wählen dort beispielsweise die Bezeichnung des Arrays TSIBuffer in dem Teil des Programmcodes aus, in dem sie deklariert ist (Abb. 1). Anschließend führen wir die Befehlskette „Hauptmenü“ (Main Menu) - „Bearbeiten“ (Edit) - „Suchen und ersetzen“ (Find and replace) - „Suchen“ (Find) aus oder verwenden die Tastenkombination CStrg+F (Ctrl+F). 


Abb. 1. Markierte Arraybezeichnung.

Das Wort „TSIBuffer“ ist bereits in das Feld „Suchen“ des sich öffnenden Fensters „Suche“ eingegeben. In dem Kasten zur Auswahl der „Richtung“ wählen wir „Aufsteigend“. In dem geöffneten Fenster der „Suche“ gehen wir jetzt mit dem Mauszeiger direkt hinter die Funktion OnCalculate(), betätigen einmal die Schaltfläche „Weiter suchen“ und finden umgehend die Stelle, an der die Berechnungen für das Array TSIBuffer beendet sind. Die Berechnungen erfolgen in dem Zyklus „for“. Wir fügen den Code für die Berechnung der Signallinie unmittelbar hinter diesem Zyklus ein (Abb. 2).


Letzte Fundstelle einer Berechnung des Wertes für den Puffer TSIBuffer (roter Pfeil). Der Zyklus, in dem die Berechnungen ausgeführt werden, ist durch einen roten Rahmen gekennzeichnet.
Abb. 2. Letzte Fundstelle einer Berechnung des Wertes für den Puffer TSIBuffer (roter Pfeil). Der Zyklus, in dem die Berechnungen ausgeführt werden, ist durch einen roten Rahmen gekennzeichnet.

Die Funktionen zur Berechnung der vier Hauptarten gleitender Durchschnittswerte sind in der Bibliothek MovingAverages.mqh enthalten:

  • für einfache - SimpleMAOnBuffer(),
  • für exponentielle - ExponentialMAOnBuffer(),
  • für linear gewichtete - LinearWeightedMAOnBuffer(),
  • für geglättete - SmoothedMAOnBuffer().

All diese Funktionen weisen denselben Parameterbestand auf: 

const int rates_total, const int prev_calculated, const int begin, const int period, const double& price[],double& buffer[]

Der Parameter price[] der Funktion bestimmt ein Array mit den Ausgangsdaten, anhand derer die Berechnung des gleitenden Durchschnittswerts erfolgt. Bei dem Parameter buffer handelt es sich um das Array, in dem die Werte für den gleitenden Durchschnitt gespeichert werden. Die Parameter rates_total und prev_calculated entsprechen den Parametern rates_total und prev_calculated der Funktion onCalculate(), durch sie werden der Umfang des Arrays price[] und die Anzahl der bereits verarbeiteten Elemente des Arrays bestimmt. Bei dem Parameter begin handelt es sich um die Kennziffer eines Arrayelementes, das den Beginn der relevanten Daten anzeigt. 

In Anbetracht der Besonderheiten der Algorithmen zur Berechnung der gleitenden Durchschnittswerte in der Bibliothek MovingAverages.mqh (diese Eigenschaften sind für das Thema dieses Beitrages von keinerlei Relevanz) müssen wir bei der Einstellung des begin-Parameters äußerst vorsichtig vorgehen.

Dieser Parameter darf auf gar keinen Fall auf ein Element des Arrays eingestellt werden, das vor demjenigen liegt, ab dem die Werte der Ausgangsdaten beginnen (das Array TSIBuffer). Es ist zulässig eine späteres Element anzugeben, wenn dies nicht zu Fehlern in den Berechnungen führt

Zur Festlegung eines geeigneten Wertes für begin achten Sie auf die Parameter des for-Zyklus‘, in dem die Werte für das Array TSIBuffer berechnet werden - der Zyklus beginnt ab der Variablen start. Wir müssen den Wert ermitteln, den die start-Variable bei der ersten Berechnung des Indikators hatte (mit dem Wert prev_calculated gleich 0). Der Wert der Variablen „start“ wird unmittelbar vor dem Zyklus berechnet, wenn gilt prev_calculated = 0; die Berechnung erfolgt unter Verwendung folgender Formel:

start=begin+r+s-1;

Der an die Funktion zur Berechnung der gleitenden Durchschnittswerte weitergegebene Wert der Variablen begin muss diesem Wert entsprechen.

Nach dem Zyklus zur Berechnung des Arrays TSIBuffer deklarieren wir die Variable begin2 und schreiben ihr den Wert begin+r+s-1 zu.

int begin2=begin+r+s-1; 

Um die Möglichkeit zur Verwendung unterschiedlicher Glättungsfunktionen je nach dem Wert des externen Parameter „sm“ zu schaffen, verwenden wir den Operator switch. Dabei programmieren wir für jeden möglichen Wert der Variablen sm den Aufruf der entsprechenden Funktion.

switch(sm)
  {
   case MODE_EMA:
      ExponentialMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_LWMA:
      LinearWeightedMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_SMA:
      SimpleMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
   case MODE_SMMA:
      SmoothedMAOnBuffer(rates_total,prev_calculated,begin2,sp,TSIBuffer,TSISigBuffer);
      break;
  }

Danach können wir den Indikator bereits mit der Signallinie sehen. Wir betätigen die Schaltfläche „Erstellen“, öffnen das entsprechende Ausgabegerät und verknüpfen den Indikator mit einem Diagramm (Abb. 3).



Abb. 3. Indikator TSIs: blaue Hauptlinie; rot - neue Signallinie.

8. Entfernen des Anfangs der der Abbildung des Indikators

Geht man in einem Diagramm mit dem Indikator bis zum äußersten linken Rand, dann zeigt sich, dass der Indikator auch in dem Bereich, für den gar keine Werte berechnet wurden, Linien zieht. Das sieht nicht schön aus (Abb. 4).



Abb. 4. Abbildung des Indikators in dem Bereich, in dem keine Berechnung durchgeführt wurde. 

Mithilfe der Funktion PlotIndexSetInteger(), die über die Kennung PLOT_DRAW_BEGIN aufgerufen wird, legen wir die Anzahl der ersten Balken fest, in denen der Puffer nicht abgebildet wird. Der Aufruf der Funktion hat aus der Funktion OnInit() des Indikators zu erfolgen. Wir fügen den Aufruf der Funktion ganz am Ende von OnInit(), jedoch selbstredend noch vor dem Aufruf von return(0) an.

PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,r+s+sp);

Nach erneuter Betätigung der Schaltfläche „Erstellen“ erhalten wir den korrekten Anfang der Abbildung des Indikators (Abb. 5).  



Abb. 5. Korrekter Anfang der Abbildung des Indikators. 

Die zweite Möglichkeit. Erstellen eines neuen Indikators auf der Grundlage eines vorhandenen


Wir betrachten diese Möglichkeit anhand des Beispiels der Erstellung eines Indikators für die Konvergenz und Divergenz der Haupt- und der Signallinie des Indikators TSIs. Der Indikator wird in Form eines Histogramms abgebildet und zwei Farben aufweisen, wie die Indikatoren AO und AC. Steigt der Wert des Indikators wird das Diagramm grün gefärbt; sinkt er, erhält das Diagramm die Farbe Rot. Wie in der Einleitung bereits angesprochen können wir die Funktionen iCustom() oder IndicatorCreate() verwenden, um uns auf einen anderen Indikator zuzugreifen. Werfen wir zunächst einen Blick auf die Erstellung eines neuen Indikators unter Verwendung der Funktion iCustom().

Erstellen eines Indikators mithilfe der Funktion iCustom()


1. Erstellen eines neuen Indikators

Lassen Sie uns einen neuen Indikator anlegen! Zur Erstellung eines neuen Indikators in MetaEditor müssen wir die Befehlsfolge „Hauptmenü“ (Main Menu) - „Datei“ (File) - „Neu“ (New) - „Benutzerdefinierter Indikator“ (Custom Indicator) ausführen oder die Tastenkombination „Ctrl+N“ betätigen. In das Feld „Name“ des sich öffnenden Fensters geben wir die Bezeichnung für den neuen Indikator ein: TSIsCDiCust, dann betätigen wir die Schaltfläche „Hinzufügen“ (Add). Wir fügen einen externen Parameter gleich welchen Namens hinzu, um im Code einen Teil für externe Parameter zu reservieren, damit es später einfacher wird, alle externen Parameter aus dem Indikator TSIs hineinzukopieren (Abb. 6).


Erster Schritt zur Erstellung eines benutzerdefinierten Indikators im Assistenten.
Abb. 6. Erster Schritt zur Erstellung eines benutzerdefinierten Indikators im Assistenten.

Wir betätigen die Schaltfläche „Weiter“ (Next).

Im nächsten Fenster geben wir an, dass der Indikator in einem neuen Fenster abgebildet wird. „Minimum“ und „Maximum“ werden noch nicht festgelegt. Nach Betätigung der Schaltfläche „Hinzufügen“ (Add) erscheint ein neuer Puffer im Pufferverzeichnis des Indikators; wir geben seine Bezeichnung, TSIsCD, (diese erscheint beim Überfahren der Indikatorlinie mit dem Mauszeiger in einem Dialogfenster sowie im Datenfenster) und seine Art, mehrfarbiges Histogramm (Color Histogram), ein.

Anschließend erscheinen im Feld „Farbe“ (Color) mehrere Farbbeispiele. Wir geben für das erste Beispiel die Farbe Green an und „Red“ für das zweite, die übrigen bleiben unverändert. Wir fügen zwei weitere Puffer mit den Bezeichnungen Tsi und TsiSignal hinzu, sie dienen zum Empfang und zur Speicherung der Werte des Indikators TSIs (Abb. 7).


Zweiter Schritt zur Erstellung eines benutzerdefinierten Indikators im Assistenten. 
Abb. 7. Zweiter Schritt zur Erstellung eines benutzerdefinierten Indikators im Assistenten.

Nach Betätigung der Schaltfläche „Fertig“ (Finish) wird das Template des neuen Indikators in dem Bearbeitungsprogramm MetaEditor geöffnet.

2. Bearbeiten der Eigenschaften des Indikators und seines Puffers

In Schritt 1 haben wir 3 Puffer festgelegt; trotzdem ist der Wert für #property indicator_buffers gleich 4. Das liegt daran, dass ein mehrfarbiges Histogramm zwei Puffer verwendet, einen, der in dem Diagramm abgebildet wird und für die Werte eines Indikators gedacht ist, sowie einen zweiten, der zur Festlegung der Darstellungsfarbe des ersten Puffers dient. Der Wert #property indicator_buffers bleibt unverändert. Der Wert #property indicator_plots dagegen wird in 1 geändert - im Diagramm soll lediglich ein Puffer abgebildet werden.

Die Puffer Tsi und TsiSignal sollen im Diagramm nicht abgebildet werden, deshalb werden ihre Eigenschaften komplett gelöscht (alle auf 2 und 3 endenden Indikatoreigenschaften).

//--- plot Tsi
#property indicator_label2 "Tsi"
#property indicator_type2 DRAW_LINE
#property indicator_color2 Red
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
//--- plot TsiSignal
#property indicator_label3 "TsiSignal"
#property indicator_type3 DRAW_LINE
#property indicator_color3 Red
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
In der Funktion OnInit() finden wir den Aufruf für die Funktion SetIndexBuffer() für diese Puffer (die Bezeichnungen der Arrays lauten TsiBuffer bzw. TsiSignalBuffer), wir ändern den Wert des dritten Parameters von INDICATOR_DATA in INDICATOR_CALCULATIONS.
SetIndexBuffer(2,TsiBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,TsiSignalBuffer,INDICATOR_CALCULATIONS);

Wir bearbeiten die Eigenschaft indicator_color1 und lassen lediglich die beiden ersten Farben übrig. 

#property indicator_color1 Green,Red

3. Auszeichnung externer Parameter

Im MetaEditor öffnen wir den Indikator TSIs und kopieren dort alle externen Variablen, um die aktuelle externe Variable Input1 durch sie zu ersetzen.

//--- input parameters
input int r=25;
input int s=13;
input int sp=5;                 // Smoothing period
input ENUM_MA_METHOD sm=MODE_EMA; // Smoothing type

4. Auszeichnung einer Variablen für den Handle des Indikators und Aufruf des Indikators

Im öffentlichen Bereich des Indikators deklarieren wir eine Variable des Typs int und nennen sie „Handle“. Wir rufen die Funktion iCustom() ganz unten in OnInit() auf. Die Funktion gibt den Handle des erstellten Indikators aus; wir benötigen ihn zum Abrufen der Werte des Indikators. Den von der Funktion ausgegebenen Wert weisen wir der Variablen „Handle“ zu.

Die beiden ersten Parameter der Funktion iCustom() legen ein Symbol und einen Zeitrahmen fest, entsprechend deren Daten die Berechnung des Indikators erfolgt. Geben wir jetzt ein Symbol und einen Zeitrahmen an, mit denen der Indikator verknüpft wird: Symbol und PERIOD_CURRENT. Der dritte Parameter ist die Bezeichnung eines benutzerdefinierten Indikators, in diesem Fall ist das TSIs. Im Weiteren werden alle externen Parameter des aufgerufenen Indikators aufgeführt:

Handle=iCustom(_Symbol,PERIOD_CURRENT,"TSIs",r,s,sp,sm);

5. Vorbereitung der Funktion OnCalculate()

Weiter geht‘s mit der Funktion OnCalculate(). Der Indikator TSIs wird anhand eines Datenpuffers berechnet, folglich verwenden wir die erste Form der Funktion OnCalculate(). Wir ändern die in dem Template angelegte zweite Form der Funktion OnCalculate() in die erste.

int OnCalculate(const int rates_total,         // size of the price[] array
                const int prev_calculated,   // bars processed during the previous call
                const int begin,             // from where the significant data begin
                const double &price[]        // array for calculation
                )
  {
   return(rates_total);
  }

Die weitere Bearbeitung des Indikators erfolgt im Rahmen dieser Funktion.

6. Festlegen der Grenzen der Berechnung des Indikators

Höchsten Vorrang und Bedeutung bei der Entwicklung eines Indikators kommen der Festlegung der Bereichsgrenzen der zu berechnenden Balken. Beim Auslösen des Indikators muss die Berechnung des Anzeigewertes für jeden Balken erfolgen, bei seinem weiteren Betrieb lediglich für einen, der gebildet wird. Der Zeitpunkt für die Auslösung des Indikators kann mithilfe des Wertes der Variablen prev_calculated festgelegt werden. Ist dieser Wert gleich Null, so erfolgt die erste Ausführung der Funktion OnCalculate() unmittelbar nach dem Auslösen des Indikators.

Bei der ersten Ausführung der Funktion OnCalculate() muss die Kennziffer des ersten Balkens, ab dem die Berechnungen beginnen sollen, festgelegt werden. Dieser Wert wird bestimmt durch die Anzahl der zur Berechnung des Indikatorwertes erforderlichen Balken (die Vergabe der Kennziffern erfolgt von links nach rechts).

Die Steigung der Indikatorlinie wird durch zwei Balken bestimmt, das bedeutet, dass wir einen weiteren vorhergehenden Balken benötigen. Die Kennziffer des Balkens, ab dem die aussagekräftigen Daten des price[]-Arrays beginnen, ist bekannt, es ist der Wert der Variable begin; das heißt, wir beginnen mit der Berechnung der Balken ab dem Balken start=begin+1.

Anschließend wird im weiteren Arbeitsverlauf des Indikators die Kennziffer des Balkens, ab dem die Berechnung beginnt, entsprechend dem Wert der Variablen prev_calculated ausgeführt, diese Variable enthält die Anzahl der bereits berechneten Balken. Somit müssen wir, um die Kennziffer des letzten Balkens zu erfahren, für den die Berechnungen ausgeführt wurden, von prev_calculated lediglich 1 subtrahieren.

Der letzte der bereits berechneten Balken wird erneut berechnet, da er ein formbestimmender Balken sein kann. Die Berechnungsgrenze wird durch die Größe des Arrays price[], die Variable rates_total bestimmt. Die Kennziffer des letzten Balkens, für den die Berechnungen ausgeführt werden, ist gleich rates_total-1 (d. h. sie ist um eine Einheit kleiner als die Gesamtgröße des Arrays).

Da der Indikator für seine Berechnungen die Daten eines anderen Indikators nutzt, müssen wir diese Daten beziehen. Um Daten von einem anderen Indikator zu beziehen, bedienen wir uns der Funktion CopyBuffer(). Im ersten Parameter der Funktion ist der „Handle“ des Indikators anzugeben, dessen Daten kopiert werden sollen (Der Handle wird in Schritt 4 bezogen); im zweiten Parameter geben wir die Kennziffer des kopierten Puffers an (der erforderliche Wert kann anhand der Registerkarte „Farbe“ (Color) in den Eigenschaften des kopierten Indikators bestimmt werden, die Zählung beginnt bei Null).

Der dritte Parameter ist die Kennziffer des Balkens, ab dem kopiert wird, in diesem Fall erfolgt die Vergabe der Kennziffern von rechts nach links, sodass der äußerste rechte Balken die Null erhält. Der vierte Parameter gibt die Anzahl der zu kopierenden Elemente des Arrays wieder. Bei der Festlegung der zu kopierenden Elemente ist genauso vorsichtig vorzugehen wie bei der Bestimmung des Bereichs der zu berechnenden Balken. Denn das hat Auswirkungen auf die Leistungsfähigkeit des Indikators. Die Kennziffer des Balkens, ab dem die Berechnung des Indikators beginnt, ist bereits eingestellt, somit wird die Anzahl der zu kopierenden Elemente in der Form rates_total-start berechnet. Wenn der Indikator im Arbeitsablauf nur für einen formbildenden Balken berechnet wird, wird auch nur ein Element des Arrays kopiert.

Wenn die Funktion CopyBuffer() bei dem Versuch, die Daten zu kopieren, als Ergebnis -1 ausgibt, so bedeutet das, dass die Daten nicht kopiert werden konnten, weswegen die Ausführung der Berechnungen keinen Sinn macht. Dieser Fehler muss unbedingt behoben werden. Ganz am Anfang von CopyBuffer() deklarieren wir eine statische Variable des Typs bool und nennen sie „Error“ (Fehler). Tritt bei der Berechnung des Indikators ein Fehler auf, insbesondere ein Fehler beim Kopieren der Indikatordaten, wird dieser Variablen der Wert „true“ zugewiesen und die Ausführung der Funktion OnCalculate() beendet.

Bei der nächsten Kursänderung wird der gesamte Indikator neu berechnet, wenn aus dem Wert der Variablen „Error“ ersichtlich wird, dass bei der vorherigen Ausführung der Funktion OnCalculate() ein Fehler vorgelegen hat. Demzufolge hat der Anfang der Funktion OnCalculate() folgendes Aussehen:

   static bool error=true; 
   int start;
   if(prev_calculated==0) // First execution of the OnCalculate() function after the indicator start
     {
      error=true; // Set the value True for the indicator to be calculated for all bars
     }
   if(error) // If value of error=true, then it is the first execution of the function after 
             // the start of the indicator, or there was an error of copying of data at the previous start
     {
      start=begin+1;
      error=false;
     }
   else
     {
      start=prev_calculated-1;
     }

   if(CopyBuffer(Handle,0,0,rates_total-start,TsiBuffer)==-1) // Copying data of main line of the indicator
     {
      error=true; // Failed to copy data, set the value True for the error variable to recalculate the whole 
                 // indicator at the next call of OnCalculate()
      return(0);  // End working of the function
     }
   if(CopyBuffer(Handle,1,0,rates_total-start,TsiSignalBuffer)==-1) // Copy data of the signal line of the indicator
     {
      error=true; // Failed to copy data, set the value true for the error variable to recalculate the whole
                 // indicator at the next call of the OnCalculate() function
      return(0);  // End working of the function
     }

Die Grenzen der Indikatorberechnung sind festgelegt, jetzt erstellen wir einen Zyklus von Berechnungen innerhalb dieses Balkenbereichs.

for(int i=start;i<rates_total;i++)
  {

  }

Zunächst berechnen wir den Wert des Indikators (der Programmcode befindet sich innerhalb des gerade erstellten Zyklus‘).

TsiCDBuffer[i]=TsiBuffer[i]-TsiSignalBuffer[i];

Jetzt kommt das Interessanteste: das Färben des Puffers. Oben, in Schritt 1, haben wir die Verwendung eines mehrfarbigen Histogramms zur Abbildung des Puffers des Indikators festgelegt. Für grafische Darstellungen dieser Art werden zwei Puffer benötigt, einer für den Wert des Indikators und ein weiterer für die Farbe. Die Farbauswahl befindet sich in der Eigenschaft indicator_color1. Wird für ein Element des Puffers der Wert 0 eingestellt, so wird der Indikator in grüner Farbe abgebildet; wird der Wert 1 gewählt, ist der Indikator rot (entsprechend ihrer jeweiligen Position im Verzeichnis indicator_color1; die Nummerierung beginnt bei Null).

Es ist nicht auszuschließen, dass die Indikatorwerte in zwei benachbarten Balken gleich sind, in diesem Fall ist der Indikator in der vorstehend aufgeführten Farbe anzuzeigen (da wir nur zwei Farben festgelegt haben, je eine für aufsteigende und absteigende Bewegungen). Dementsprechend kopieren wir zu Beginn der Berechnungen den Wert des Puffers TsiCDColors aus dem vorhergehenden Balken: 

TsiCDColors[i]=TsiCDColors[i-1];

Bei aufsteigenden Bewegungen erhält der Indikator die Farbe Green:

if(TsiCDBuffer[i]>TsiCDBuffer[i-1])TsiCDColors[i]=0;

Bei absteigenden Bewegungen erhält der Indikator die Farbe Red:

if(TsiCDBuffer[i]<TsiCDBuffer[i-1])TsiCDColors[i]=1;

Damit ist die Arbeit an dem Indikator fast abgeschlossen, es bleibt nur noch, den Anfang der grafischen Darstellung des Indikators festzulegen.

7. Abschluss der Arbeit an dem Indikator 

Obwohl zur Festlegung der Berechnung des Indikators die Variable begin verwendet wurde, bedeutet das noch lange nicht, dass die Indikatordaten, an dem durch die begin-Variable festgelegten Balken beginnen. Wenn der Algorithmus eines benutzerdefinierten Indikators nicht bekannt ist, ist es praktisch unmöglich, die Anzahl der vom Indikator für die Berechnungen benötigten Balken zu ermitteln, weshalb dieser Schritt entweder übersprungen oder ein auf Erfahrung beruhender Wert festgelegt werden kann. Wir dagegen kennen den Algorithmus für den Indikator TSIs, und so können wir den Anfang seiner grafischen Abbildung exakt bestimmen. Wir fügen den Aufruf der Funktion PlotIndexSetInteger() mit der Kennung PLOT_DRAW_BEGIN zu der Funktion OnInit() hinzu. 

PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,r+s+sp);

Der Indikator TSIs gibt die Werte auf zwei Dezimalstellen genau wieder; wir stellen für die Funktion IndicatorSetInteger() mit der Kennung INDICATOR_DIGITS dieselbe Genauigkeit ein:

IndicatorSetInteger(INDICATOR_DIGITS,2);

Wir Erstellen den Indikator und verknüpfen ihn mit dem Diagramm (Abb. 8).

 
Abb. 8. Der Indikator TSIsCDiCust.

Erstellen eines Indikators mithilfe der Funktion IndicatorCreate() 


Die Erstellung eines Indikators mithilfe der Funktion IndicatorCreate() ist vollkommen identisch mit seiner Erstellung anhand der Funktion iCustom() mit Ausnahme von Schritt 4, wo anstelle von iCustom() die Funktion IndicatorCreate() verwendet wird.

1. Wir speichern eine Kopie des Indikators TSIsCDiCust unter dem Namen TSIsCDiCreate.

2. Wir ermitteln, an welcher Stelle des Codes die Funktion iCustom() aufgerufen wird. Ab jetzt wird statt iCustom() die Funktion IndicatorCreate() aufgerufen. Wie bei iCustom() legen die beiden ersten Parameter der Funktion IndicatorCreate() ein Symbol und einen Zeitrahmen fest, entsprechend deren Daten der Indikator berechnet wird. Der dritte Parameter ist die Kennung der Indikatorart, bei einem benutzerdefinierten Indikator lautet sie IND_CUSTOM. Die Parameter des erstellten Indikators werden mithilfe des Strukturarrays MqlParam an die Funktion weitergegeben.

MqlParam enthält vier Variablen, drei davon sind Variablen für Werte unterschiedlicher Arten: double_value, integer_value und string_value; eine weitere ist type, sie legt die Art der zu verwendenden Variable fest. Der Indikator TSIs weist vier externe Parameter auf. Da es sich bei dem Indikator um einen benutzerdefinierten handelt, bestimmt das erste Element des Arrays den Namen des benutzerdefinierten Indikators, folglich muss das Array also fünf Elemente beinhalten. Wir deklarieren das Strukturarray (der Programmcode befindet sich an der Stelle, an der die Funktion iCustom() aufgerufen wurde):

MqlParam Params[5];

Wir füllen das Array mit Werten:

   Params[0].type=TYPE_STRING;
   Params[0].string_value="TSIs"; // Specify name of the called custom indicator in the first parameter
   
   Params[1].type=TYPE_INT;
   Params[1].integer_value=r;
   
   Params[2].type=TYPE_INT;
   Params[2].integer_value=s;   
   
   Params[3].type=TYPE_INT;
   Params[3].integer_value=sp;      
   
   Params[4].type=TYPE_INT;
   Params[4].integer_value=sm;  

Mit den ersten drei Parametern, die an die Funktion IndicatorCreate() weitergegeben werden, haben wir oben bereits befasst. Der vierte Parameter übermittelt den Umfang des Arrays mit den Parametern; und der letzte ist das Parameterarray selbst:

Handle=IndicatorCreate(_Symbol,PERIOD_CURRENT,IND_CUSTOM,5,Params);

Bleibt uns nur noch die Betätigung der Schaltfläche Erstellen (Compile) sowie die Überprüfung des Indikators an dem Ausgabegerät.

Fazit

Lassen Sie uns kurz die wichtigen Punkte wiederholen, die bei der Erstellung eines Indikators auf der Grundlage eines anderen Indikators zu beachten sind.

Bei der Überarbeitung eines Indikators müssen die Gesamtzahl der Puffer sowie die Anzahl der abzubildenden Puffer (die Eigenschaften indicator_buffers und indicator_plots) korrekt angegeben; sowie die Eigenschaften der neuen Puffer (die Eigenschaften indicator_label, indicator_type, indicator_color, indicator_style und indicator_width) festgelegt werden. Beim Aufruf der Funktion SetIndexBufer() für die neuen Puffer müssen der richtige Wert für den dritten Parameter (INDICATOR_DATA oder INDICATOR_CALCULATIONS); sowie die Werte des ersten Parameters (die Kennziffer des Puffers) korrekt angegeben und gegebenenfalls eine Neuvergabe der Kennziffern vorgenommen werden.

Bei der Erstellung eines neuen Indikators mithilfe eines anderen benutzerdefinierten Indikators müssen die Parameter unbedingt korrekt an die Funktion iCustom() weitergegeben; bzw. bei Verwendung der Funktion IndicatorCreate() die Parameterstruktur gefüllt werden. An dieser Stelle ist außerdem auf die korrekte Angabe der Parameter bei dem Aufruf der Funktion SetIndexBuffer() zu achten; und vor allem, darf nicht vergessen werden, den Aufruf der Funktion SetIndexBuffer() für die neuen Puffer auszuführen.

Bei jeder Beschäftigung mit Indikatoren ist besondere Aufmerksamkeit darauf zu verwenden, einen Bereich für die Berechnung der Balken festzulegen unter Verwendung der Werte der Variablen prev_calculated, rates_total und begin. Das Bearbeitungsprogramm MetaEditor hilft Ihnen im Umgang mit allen sonstigen Fehlern, die beim Programmieren auftreten können (die bei der Erstellung erscheinenden Fehlermeldungen werden unter der Registerkarte „Fehler“ (Errors) angezeigt).

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/127

Beigefügte Dateien |
tsis.mq5 (7.59 KB)
tsiscdicreate.mq5 (3.46 KB)
tsiscdicust.mq5 (3.11 KB)
20 Handelssignale in MQL5 20 Handelssignale in MQL5
In diesem Beitrag erfahren Sie, wie Sie die für das Funktionieren eines Handelssystems erforderlichen Handelssignale erhalten. Die Beispiele zur Erzeugung von 20 Handelssignalen werden hier als einzelne benutzerdefinierte Funktionen aufgeführt, die beim Anlegen von Expert Advisors verwendet werden können. Zu Ihrer Bequemlichkeit werden alle in dem Beitrag verwendeten Funktionen in einer einzigen mqh-Include-Datei zusammengefasst, die leicht mit einem künftigen Expert Advisor verknüpft werden kann.
Geldverwaltungsfunktionen in einem Expert Advisor Geldverwaltungsfunktionen in einem Expert Advisor
Die Entwicklung von Handelsstrategien konzentriert sich in erster Linie auf die Suche nach Mustern für den Marktein- und -austritt sowie auf die Aufrechterhaltung von Positionen. Wenn wir in der Lage sind, einige Muster in Regeln für den automatisierten Handel zu gießen, steht der Händler vor der Frage der Berechnung der Menge der Positionen, der Größe der Margen sowie der Aufrechterhaltung eines soliden Bestandes an verpfändbaren Mitteln zur Sicherung offener Positionen im automatisierten Handel. In diesem Beitrag verwenden wir die Programmiersprache MQL5 zur Konstruktion einfacher Beispiele für die Durchführung dieser Berechnungen.
Der Prototyp eines automatischen Handelssystems Der Prototyp eines automatischen Handelssystems
In diesem Beitrag werden die Grundlagen für die Erstellung von Algorithmen und Elementen für Handelssysteme zusammengefasst und systematisch geordnet. Es geht hier um die Entwicklung eines Algorithmus‘ für ein automatisches Handelssystem (im Weiteren: das Expert-System). Als Beispiel ziehen wir die Klasse CExpertAdvisor heran, sie kann zur schnellen und einfachen Entwicklung von Handelssystemen verwendet werden.
Erstellen einer Anzeigetafel unter Verwendung der Klassen aus der Standardbibliothek und Google Chart API Erstellen einer Anzeigetafel unter Verwendung der Klassen aus der Standardbibliothek und Google Chart API
Die Programmiersprache MQL5 ist in erster Linie auf die Schaffung automatisierter Handelssysteme und komplexer Hilfsmittel für technische Aktienanalysen angelegt. Darüber hinaus ermöglicht es uns jedoch auch die Entwicklung interessanter Informationssysteme zur Verfolgung von Marktlagen und verschafft uns eine Rückkopplung mit dem Händler. Dieser Beitrag beschreibt die Bestandteile der Standardbibliothek von MQL5 und liefert Beispiele für ihre praktische Verwendung, um diese Ziele zu erreichen. Außerdem liefert er ein Beispiel für die Verwendung von Google Chart API zur Erstellung von Diagrammen.