![Anlegen eines mehrwährungsfähigen Indikators unter Verwendung zahlreicher Indikatorzwischenspeicher](https://c.mql5.com/i/articles/overlay.png)
Anlegen eines mehrwährungsfähigen Indikators unter Verwendung zahlreicher Indikatorzwischenspeicher
Einleitung
Es begann alles damit, als ich in dem Artikel Theoretische Grundlagen zum Aufbau von Cluster Indikatoren für Devisenhandel zum ersten Mal etwas von Clusterindikatoren gehört habe. Das hat mich damals sehr interessiert und so habe ich beschlossen, etwas Ähnliches in Sachen Kursanalyse für mehrere Währungen zu programmieren. Zunächst habe ich unter der Code-Bezeichnung MultiCurrencyIndex eine eigene Variante des Indikators umgesetzt, in dem auf der Grundlage der berechneten Werte der Währungsindices die Berechnung der klassischen Indikatoren (RSI, MACD, CCI) erfolgt ist.
Und jetzt werde ich Ihnen schildern, wie ich diesen Indikator auf die neue Plattform MetaTrader 5 in Verbindung mit MQL5 übertragen habe, außer dass ich statt des CCI den Stochastischen Oszillator (Stochastik-Indikator) berechnen werde, da dieser (meiner Ansicht nach) zukunftsträchtiger ist.
Beginnen wir mit einigen Begriffsbestimmungen:
Der US Dollar Index - Ein anhand der mir freundlicherweise von Neutron zur Verfügung gestellten Formel berechneter Wert der Art „double“.
,
mit USD/YYY = alle unmittelbaren Quotierungen der Art USD/CHF; XXX/USD = alle gegenläufigen wie EUR/USD.
Die übrigen Währungsindices werden aus den Schlusswerten (Close) der Währungspaare berechnet, die USD beinhalten.
Die Hauptlinien - zwei unmittelbar zum aktuellen Diagramm gehörende die Rechendaten abbildende Linien. In dem EURUSD-Diagramm sind es beispielsweise die Linien für die Währungen EUR und USD.
Hilfslinien - die übrigen berechneten Indikatorlinien, die nicht zu dem aktuellen Diagramm gehören. Für dasselbe EURUSD-Diagramm sind das zum Beispiel die Linien für die Währungen GBP, CHF, JPY, CAD, AUD und NZD.
Close - der Wert des Schlusskurses des Balkens des aktuellen Zeitraums (der Art „double“) für das benötigte Währungspaar.
Also, fangen wir an.
Die Aufgabenstellung
Zunächst brauchen wir eine Aufgabenstellung.
- Synchronisierung der Diagramme der aktivierten Währungspaare des aktuellen Zeitraums.
- Zugriff auf die Schlusskurse (Close) von sieben Währungspaaren: EURUSD, GBPUSD, USDCHF, USDJPY, USDCAD, AUDUSD und NZDUSD sowie deren Zwischenspeicherung in den für Hilfsberechnungen vorgesehenen Indikatorpuffern.
- Berechnung des US Dollar Index auf dem aktuellen Balken auf der Grundlage der in Punkt (2) gewonnenen Daten.
- Berechnung der übrigen Währungsindices in Kenntnis des US Dollar Index für den aktuellen Balken.
- Durchführung der genannten Berechnungen (Punkt 3 und 4) in der für die gewählte Verlaufslänge erforderlichen Häufigkeit.
- Berechnung der folgenden Werte für jeden der gewählten Währungsindices je nach Art des Indikators:
- Relativer Stärke Indikator (Relative Strength Index, RSI);
- Indikator für das Zusammen-/Auseinanderlaufen des gleitenden Durchschnitts (Moving Average Convergence / Divergence, MACD);
- Stochastik (Stochastik Oszillator);
- diese Aufstellung kann fortlaufend erweitert werden.
Dafür benötigen wir:
31 Indikatorpuffer:
- 0 - 7 jeweils einschließlich - Zwischenspeicher zur Abbildung der Ergebnislinien;
- 8 - 14 einschließlich - Zwischenspeicher für die Hauptwährungspaare, die USD beinhalten;
- 15 - 22 einschließlich - Zwischenspeicher für die Währungsindices;
- 23 - 30 einschließlich - Zwischenspeicher für die Zwischenergebnisse des Stochastik Oszillators der Art „close/close“ ohne Glättung.
Zur Auswahl der Indikatorart führen wir den geeigneten Aufzählungstyp enum ein:
enum Indicator_Type { Use_RSI_on_indexes = 1, // RSI of the index Use_MACD_on_indexes = 2, // MACD from the index Use_Stochastic_Main_on_indexes = 3 // Stochastic on the index };Als Nächstes geben wir mithilfe des Eingabebefehls „input“ im Einstellungen-Fenster eine Aufstellung der Indikatoren zur Auswahl durch den Anwender aus.
input Indicator_Type ind_type=Use_RSI_on_indexes; // type of the indicator from the index
Es besteht die Möglichkeit, unter der Registerkarte „Inputs“ eine anwenderfreundlichere Art zur Wiedergabe der Bezeichnungen der Eingangsparameter einzustellen. Dazu wird der Zeilenkommentar verwendet, der in derselben Zeile hinter der Beschreibung des Eingangsparameters stehen muss. So können den Eingangsparametern für den Anwender verständlichere Bezeichnungen zur Seite gestellt werden.
Dieselben Regeln gelten für den Aufzählungsbefehl enum. Das heißt, wenn der mnemonischen Bezeichnung wie in unserem Beispiel ein Kommentar zur Seite gestellt wird, wird anstelle der mnemonischen Bezeichnung der Inhalt dieses Kommentars verwendet. Das verleiht zusätzliche Flexibilität beim Schreiben von Programmen mit verständlichen Beschreibungen der Eingangsparameter.
Die Entwickler haben versucht, geeignete Mittel bereitzustellen, damit der Endanwender eines MQL5-Programms die „menschliche“ Bezeichnung der Parameter angezeigt bekommt und nicht, was im Programmcode geschrieben steht. Ausführlichere Angaben können hier nachgelesen werden.
Abbildung 1. Auswahl der Art des Indikators
Wir stellen dem Anwender eine Auswahl der erforderlichen Währungen zur Abbildung des Indikators sowie deren Farben zur Verfügung:
input bool USD=true; input bool EUR=true; input bool GBP=true; input bool JPY=true; input bool CHF=true; input bool CAD=true; input bool AUD=true; input bool NZD=true; input color Color_USD = Green; // USD line color input color Color_EUR = DarkBlue; // EUR line color input color Color_GBP = Red; // GBP line color input color Color_CHF = Chocolate; // CHF line color input color Color_JPY = Maroon; // JPY line color input color Color_AUD = DarkOrange; // AUD line color input color Color_CAD = Purple; // CAD line color input color Color_NZD = Teal; // NZD line color
Abbildung 2. Auswahl der Farbe für die Indikatorlinien
Einige weitere einstellbare Parameter:
input string rem000 = ""; // depending on the type of the indicator input string rem0000 = ""; // requires a value : input int rsi_period = 9; // period RSI input int MACD_fast = 5; // period MACD_fast input int MACD_slow = 34; // period MACD_slow input int stoch_period_k = 8; // period Stochastic %K input int stoch_period_sma = 5; // period of smoothing for Stochastics %K input int shiftbars = 500; // number of bars for calculating the indicator
Abbildung 3. Indikatorparameter
Die Beschränkung auf 500 Balken zur Berechnung des Indikators ist künstlich, reicht jedoch zur Wiedergabe des Grundgedankens der Indexberechnungen aus. Dabei ist zu bedenken, dass jeder Indikatorpuffer Speicherplatz benötigt, und dass der Speicherplatz auf dem Rechner möglicherweise nicht ausreicht, wenn dieser Variablen (in Millionen Balken) zu viel Platz eingeräumt wird.
Indikatorpuffer:
double EURUSD[], // quotes GBPUSD[], USDCHF[], USDJPY[], AUDUSD[], USDCAD[], NZDUSD[]; double USDx[], // indexes EURx[], GBPx[], JPYx[], CHFx[], CADx[], AUDx[], NZDx[]; double USDplot[], // results of currency lines EURplot[], GBPplot[], JPYplot[], CHFplot[], CADplot[], AUDplot[], NZDplot[]; double USDStoch[], // buffers of intermediate data schotastics by the close/close type without smoothing EURStoch[], GBPStoch[], JPYStoch[], CHFStoch[], CADStoch[], AUDStoch[], NZDStoch[];Darüber hinaus benötigen wir einige globale (auf der Ebene des Indikators) Variablen:
int i,ii; int y_pos=0; // Y coordinate variable for the informatory objects datetime arrTime[7]; // Array with the last known time of a zero valued bar (needed for synchronization) int bars_tf[7]; // To check the number of available bars in different currency pairs int countVal=0; // Number of executable Rates int index=0; datetime tmp_time[1]; // Intermediate array for the time of the bar
Damit sind wir bei der recht umfangreichen Funktion OnInit angelangt, in der wir die Indikatorpuffer ihren Zwecken entsprechend verteilen.
Da die anfänglichen Berechnungen den US Dollar Index durchlaufen, wird für USD die Möglichkeit eingerichtet, die Abbildung dieser Währung in den Indikatorpuffern lediglich auszuschalten.
So sieht das aus:
if(USD) { countVal++; SetIndexBuffer(0,USDplot,INDICATOR_DATA); // array for rendering PlotIndexSetString(0,PLOT_LABEL,"USDplot"); // name of the indicator line (when selected with a mouse) PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,shiftbars); // from which we begin rendering PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE); // drawing style (line) PlotIndexSetInteger(0,PLOT_LINE_COLOR,Color_USD); // color of line rendering if(StringFind(Symbol(),"USD",0)!=-1) {PlotIndexSetInteger(0,PLOT_LINE_WIDTH,wid_main);} // if the symbol name contains USD // then draw a line of appropriate width else {PlotIndexSetInteger(0,PLOT_LINE_STYLE,style_slave);} ArraySetAsSeries(USDplot,true); // indexation of array as a timeseries ArrayInitialize(USDplot,EMPTY_VALUE); // zero values f_draw("USD",Color_USD); // rendering in the indicator information window } SetIndexBuffer(15,USDx,INDICATOR_CALCULATIONS); // array of dollar index for calculations // (is not displayed in the indicator as a line) ArraySetAsSeries(USDx,true); // indexation of an array as a time series ArrayInitialize(USDx,EMPTY_VALUE); // zero values if(ind_type==Use_Stochastic_Main_on_indexes) { SetIndexBuffer(23,USDstoch,INDICATOR_CALCULATIONS); // if the destination of the indicator as a Use_Stochastic_Main_on_indexes, // then this intermediate array is needed ArraySetAsSeries(USDstoch,true); // indexation of array as a time series ArrayInitialize(USDstoch,EMPTY_VALUE); // zero values }Für die Währung EUR sieht der Code in der Funktion OnInit folgendermaßen aus:
if(USD) { countVal++; SetIndexBuffer(0,USDplot,INDICATOR_DATA); // array for rendering PlotIndexSetString(0,PLOT_LABEL,"USDplot"); // name of the indicator line (when selected with a mouse) PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,shiftbars); // from which we begin rendering PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE); // drawing style (line) PlotIndexSetInteger(0,PLOT_LINE_COLOR,Color_USD); // color of line rendering if(StringFind(Symbol(),"USD",0)!=-1) {PlotIndexSetInteger(0,PLOT_LINE_WIDTH,wid_main);} // if the symbol name contains USD // then draw a line of appropriate width else {PlotIndexSetInteger(0,PLOT_LINE_STYLE,style_slave);} ArraySetAsSeries(USDplot,true); // indexation of array as a timeseries ArrayInitialize(USDplot,EMPTY_VALUE); // zero values f_draw("USD",Color_USD); // rendering in the indicator information window } SetIndexBuffer(15,USDx,INDICATOR_CALCULATIONS); // array of dollar index for calculations // (is not displayed in the indicator as a line) ArraySetAsSeries(USDx,true); // indexation of an array as a time series ArrayInitialize(USDx,EMPTY_VALUE); // zero values if(ind_type==Use_Stochastic_Main_on_indexes) { SetIndexBuffer(23,USDstoch,INDICATOR_CALCULATIONS); // if the destination of the indicator as a Use_Stochastic_Main_on_indexes, // then this intermediate array is needed ArraySetAsSeries(USDstoch,true); // indexation of array as a time series ArrayInitialize(USDstoch,EMPTY_VALUE); // zero values } if(EUR) { countVal++; SetIndexBuffer(1,EURplot,INDICATOR_DATA); // array for rendering PlotIndexSetString(1,PLOT_LABEL,"EURplot"); // name of the indicator line (when pointed to with a mouse) PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,shiftbars); // which we begin rendering from PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE); // drawing style (lines) PlotIndexSetInteger(1,PLOT_LINE_COLOR,Color_EUR); // the color of rendering lines if(StringFind(Symbol(),"EUR",0)!=-1) {PlotIndexSetInteger(1,PLOT_LINE_WIDTH,wid_main);} // if the symbol name contains EUR // then we draw a line of the appropriate width else {PlotIndexSetInteger(1,PLOT_LINE_STYLE,style_slave);} // if the symbol name does NOT contain EUR, // then we draw a line of an appropriate style (on the crosses) ArraySetAsSeries(EURplot,true); // indexation of the array as a time series ArrayInitialize(EURplot,EMPTY_VALUE); // zero values SetIndexBuffer(8,EURUSD,INDICATOR_CALCULATIONS); // data of Close currency pair EURUSD ArraySetAsSeries(EURUSD,true); // indexation of the array as a time series ArrayInitialize(EURUSD,EMPTY_VALUE); // zero values SetIndexBuffer(16,EURx,INDICATOR_CALCULATIONS); // array of the EURO index for calculations // (not displayed on the indicator as a line) ArraySetAsSeries(EURx,true); ArrayInitialize(EURx,EMPTY_VALUE); if(ind_type==Use_Stochastic_Main_on_indexes) { SetIndexBuffer(24,EURstoch,INDICATOR_CALCULATIONS); // if the indicator destination as a Use_Stochastic_Main_on_indexes, // then this intermediate array is needed ArraySetAsSeries(EURstoch,true); // indexation of the array as a time series ArrayInitialize(EURstoch,EMPTY_VALUE); // zero values } f_draw("EUR",Color_EUR); // rendering in the indicator information window }Ganz ähnlich wie bei dem EUR sieht der Code bei anderen Währungen aus, etwa bei GBP, JPY, CHF, CAD, AUD und NZD, wobei die Kennziffern der Zwischenspeicher entsprechend verschoben werden. Den Programmcode zu diesen Währungen finden Sie in der Datei mit dem Indikator im Anhang zu diesem Beitrag.
Damit ist die Bereitstellung des Indikators abgeschlossen.
Jetzt benötigen wir einige benutzerdefinierte Funktionen:
- Zur Berechnung des RSI anhand des benutzerdefinierten Zwischenspeichers
- Zur Berechnung des MACD
- Zur Berechnung des SMA anhand des benutzerdefinierten Zwischenspeichers
- Zur Berechnung des Stochastik Oszillators der Art „close/close“ ohne Glättung
- Zur Abbildung der Objekte (informativ)
- Für den Kommentar in der unteren rechten Ecke des Indikators (bezüglich des Indikatorzustands)
- Zur Bereitstellung der Währungspaare der aktivierten Zeiträume
Ich werde jeden von ihnen kurz vorstellen:
- Berechnung des RSI anhand des benutzerdefinierten Zwischenspeichers
Eingangsparameter:
double f_RSI(double &buf_in[], int period,int shift),
mit buf_in[] für ein Datenfeld (Array) der Art „double“ (wie Zeitreihen), period für den Zeitraum des Indikators RSI; und shift als der Balken des Index, für den wir den Indikator berechnen. Es wird ein Wert der Art „double“ ausgegeben.
- Berechnung des MACD
Eingangsparameter:
double f_MACD(double &buf_in[], int period_fast,int period_slow,int shift),
mit buf_in[] für ein Datenfeld (Array) der Art „double“ (wie Zeitreihen); period_fast für den Zeitraum des schnell gleitenden Durchschnitts (fast МА); period_slow entsprechend für den Zeitraum des langsam gleitenden Durchschnitts (slow МА); und shift als der Balken des Index, für den wir den Indikator berechnen. Es wird ein Wert der Art „double“ ausgegeben.
- Berechnung des SMA
Eingangsparameter:
double SimpleMA(const int position,const int period,const double &price[]),
mit position als der Balken des Index, für den wir den Indikator berechnen; period für den Zeitraum des Indikators SMA; und price[] für ein Datenfeld (Array) vom Typ „double“ (wie Zeitreihen). Es wird ein Wert der Art „double“ ausgegeben.
- Zur Berechnung des Stochastik Oszillators der Art „close/close“ ohne Glättung
Eingangsparameter:
double f_Stoch(double &price[], int period_k, int shift),
mit price[] für ein Datenfeld der Art „double“ (wie Zeitreihen); period_fast für den Zeitraum der %K-Linie des Indikators; und shift als der Balken des Index, für den wir den Indikator berechnen. Es wird ein Wert der Art „double“ ausgegeben.
- Abbildung der Objekte
Eingangsparameter:
int f_draw(string name, color _color)
mit name für Objektbezeichnung und _color für Objektfarbe. Die Funktion dient lediglich zur Information. In der oberen rechten Ecke des Indikatorfensters beginnend gibt sie die Bezeichnungen der aktivierten Währungen aus. Die Farbe des Währungstextes entspricht derjenigen der Linie des zu ihr gehörenden Indikators.
- Kommentar in der unteren rechten Ecke des Indikators
Eingangsparameter:
int f_comment(string text)
text = in der unteren rechten Ecke des Indikators zu platzierender Text. Eine Art Fortschrittsleiste bezüglich der Arbeit des Indikators.
Und zu guter Letzt die abschließende und gleichzeitig eine der wichtigsten Funktionen, nämlich:
- Die Bereitstellung der Währungspaare der aktivierten Zeiträume
Ohne Eingangsparameter.
In MetaTrader 5 wird der Kursverlauf in Form der Minutendaten des Zeitraums (Timeframe, TF) zu jedem Kürzel gespeichert. Deshalb werden beim Start der Anwendung auf dem Ausgabegerät (Terminal) vor Beginn der Arbeit mit dem Programm zunächst alle erforderlichen (aktivierten) Diagramme auf der Grundlage eben dieser Minutendaten des Zeitraums erstellt. Diese Erstellung findet auch bei einem Wechsel des Zeitraums des aktuellen Diagramms statt, oder bei dem Versuch, aus dem Code des MQL5-Programms auf das Diagramm für diesen Zeitraum zuzugreifen.
Deshalb:
- muss beim ersten Aufruf der Anwendung auf dem Ausgabegerät (Terminal) eine Zeit lang gewartet werden, solange die erforderlichen Zeiträume der aktivierten Währungspaare angelegt werden (das geschieht möglicherweise im Hintergrund, sodass der Anwender es nicht sieht).
- müssen die Nullbalken bei allen aktivierten Währungen zur exakten Wiedergabe des Indikators synchronisiert werden. Das heißt, wenn es auf dem aktuellen Balken zu einer Kursänderung (Tick) kommt, durch die ein neuer Balken eröffnet wird (zum Beispiel ein Stundenbalken), muss gewartet werden, bis dieselben Kursänderungen bei den anderen Währungspaaren eintreten, die darauf ihrerseits jeweils einen neuen Balken eröffnen (eine neue Stunde). Erst danach wird mit der Berechnung des Indikators für den neuen Balken begonnen.
Der erste Teil dieser Aufgabe wird mithilfe der im Lieferumfang enthaltenen Funktion Balken (Bars) umgesetzt, die die Anzahl der Balken im Verlauf für den dem Kürzel entsprechenden Zeitraum ausgibt. Es genügt, die unten vorgestellte Variante dieser Funktion zu verwenden.
int Bars( string symbol_name, // symbol name ENUM_TIMEFRAMES timeframe // period );
In einem eigens dazu deklarierten Datenfeld wird die Anzahl der verfügbaren Balken für alle Währungspaare erfasst. Wir prüfen jeden Wert auf die erforderliche Mindestanzahl an Kursverlaufsdaten (die Variable „Anzahl der Balken zur Berechnung des Indikators“ in den Indikatoreinstellungen). Liegt die Anzahl der verfügbaren Balken in Kursverlauf irgendeines Instrumentes unter dem Wert dieser Variablen, müssen wir davon ausgehen, dass die Erstellung nicht erfolgreich war, und fragen die Anzahl der verfügbaren Daten erneut ab. Sobald die Menge der verfügbaren Verlaufsdaten zu allen Währungspaaren größer ist, als vom Anwender verlangt, gilt dieser Teil der Bereitstellung als erfolgreich ausgeführt.
Der zweite Teil der Synchronisierungsaufgabe wird mithilfe der Funktion CopyTime ausgeführt.
Wir kopieren die Eröffnungszeit des Nullbalkens jedes aktivierten Instruments (Kürzels) in ein eigens für diese Zwecke bestimmtes Datenfeld. Wenn alle Elemente dieses Datenfeldes identisch und ungleich Null sind, ist davon auszugehen, dass unser Nullbalken synchronisiert ist, die Berechnung kann also beginnen. Ausführlichere Informationen dazu bietet der Programmcode des angehängten Indikators.
Damit beenden wir die Beschreibung der Zusatzfunktionen und gehen über zur Umsetzung der Funktion OnCalculate. Da es sich um einen mehrwährungsfähigen Indikator handelt, wird eine zweite Variante für den Aufruf dieser Funktion benötigt.
int OnCalculate(const int rates_total, // size of incoming time series const int prev_calculated, // processing of bars on the previous request const datetime& time[], // Time const double& open[], // Open const double& high[], // High const double& low[], // Low const double& close[], // Close const long& tick_volume[], // Tick Volume const long& volume[], // Real Volume const int& spread[] // Spread );
Wir bestimmen die Anzahl der für die Berechnung erforderlichen Balken:
int limit=shiftbars; if(prev_calculated>0) {limit=1;} else {limit=shiftbars;}
Wir synchronisieren die Diagramme der Währungspaare:
init_tf();
Des Weiteren kopieren wir mithilfe der Funktion CopyClose die Schlussdaten aller benötigten Währungspaare in die eigens dafür angemeldeten Indikatorpuffer. (Ausführlicheres zum Zugriff auf die Daten anderer Zeiträume des aktuellen und/oder eines anderen Instrumentes (Kürzels) kann in der Hilfe nachgelesen werden)
Wenn die Funktion die Daten aus irgendeinem Grund nicht kopiert und die Antwort -1 ausgegeben hat, erscheint im Kommentar eine Fehlermeldung zu dem Währungspaar und wir warten auf das Eintreten einer neuen Kursänderung bei dem aktuellen Kürzel.
if (EUR){copied=CopyClose("EURUSD",PERIOD_CURRENT,0,shiftbars,EURUSD); if (copied==-1){f_comment("Wait...EURUSD");return(0);}} if (GBP){copied=CopyClose("GBPUSD",PERIOD_CURRENT,0,shiftbars,GBPUSD); if (copied==-1){f_comment("Wait...GBPUSD");return(0);}} if (CHF){copied=CopyClose("USDCHF",PERIOD_CURRENT,0,shiftbars,USDCHF); if (copied==-1){f_comment("Wait...USDCHF");return(0);}} if (JPY){copied=CopyClose("USDJPY",PERIOD_CURRENT,0,shiftbars,USDJPY); if (copied==-1){f_comment("Wait...USDJPY");return(0);}} if (AUD){copied=CopyClose("AUDUSD",PERIOD_CURRENT,0,shiftbars,AUDUSD); if (copied==-1){f_comment("Wait...AUDUSD");return(0);}} if (CAD){copied=CopyClose("USDCAD",PERIOD_CURRENT,0,shiftbars,USDCAD); if (copied==-1){f_comment("Wait...USDCAD");return(0);}} if (NZD){copied=CopyClose("NZDUSD",PERIOD_CURRENT,0,shiftbars,NZDUSD); if (copied==-1){f_comment("Wait...NZDUSD");return(0);}}
Weiterhin nehmen wir in dem Zyklus (von 0 bis zur Obergrenze) vor:
- Die Berechnung des US Dollar Index;
- Die Berechnung der Indices anderer Währungen auf der Grundlage der Schlussdaten (Close) und des US Dollar Index für den aktuellen Balken.
for (i=limit-1;i>=0;i--) { //calculation of USD index USDx[i]=1.0; if (EUR){USDx[i]+=EURUSD[i];} if (GBP){USDx[i]+=GBPUSD[i];} if (CHF){USDx[i]+=1/USDCHF[i];} if (JPY){USDx[i]+=1/USDJPY[i];} if (CAD){USDx[i]+=1/USDCAD[i];} if (AUD){USDx[i]+=AUDUSD[i];} if (NZD){USDx[i]+=NZDUSD[i];} USDx[i]=1/USDx[i]; //calculation of other currency values if (EUR){EURx[i]=EURUSD[i]*USDx[i];} if (GBP){GBPx[i]=GBPUSD[i]*USDx[i];} if (CHF){CHFx[i]=USDx[i]/USDCHF[i];} if (JPY){JPYx[i]=USDx[i]/USDJPY[i];} if (CAD){CADx[i]=USDx[i]/USDCAD[i];} if (AUD){AUDx[i]=AUDUSD[i]*USDx[i];} if (NZD){NZDx[i]=NZDUSD[i]*USDx[i];} }
Die Daten speichern wir in den entsprechenden Indikatorpuffern. Wir prüfen, welche Art Indikator von dem Anwender bei der Bereitstellung gewählt wurde, und nehmen auf dieser Grundlage die entsprechenden Berechnungen vor.
Wenn die Anzeige des RSI nach Indices gewünscht wurde, ist der folgende Code auszuführen:
if (ind_type==Use_RSI_on_indexes) { if (limit>1){ii=limit - rsi_period - 1;} else{ii=limit - 1;} for(i=ii;i>=0;i--) { if (USD){USDplot[i]=f_RSI(USDx,rsi_period,i);} if (EUR){EURplot[i]=f_RSI(EURx,rsi_period,i);} if (GBP){GBPplot[i]=f_RSI(GBPx,rsi_period,i);} if (CHF){CHFplot[i]=f_RSI(CHFx,rsi_period,i);} if (JPY){JPYplot[i]=f_RSI(JPYx,rsi_period,i);} if (CAD){CADplot[i]=f_RSI(CADx,rsi_period,i);} if (AUD){AUDplot[i]=f_RSI(AUDx,rsi_period,i);} if (NZD){NZDplot[i]=f_RSI(NZDx,rsi_period,i);} } }
Soll der MACD nach Indices angezeigt werden, folgt (richtig, bisher wurde er nur auf der Grundlage des SimpleMA umgesetzt, die Umsetzung auf der Grundlage des EMA erfolgt später):
if (ind_type==Use_MACD_on_indexes) { if (limit>1){ii=limit - MACD_slow - 1;} else{ii=limit - 1;} for(i=ii;i>=0;i--) { if (USD){USDplot[i]=f_MACD(USDx,MACD_fast,MACD_slow,i);} if (EUR){EURplot[i]=f_MACD(EURx,MACD_fast,MACD_slow,i);} if (GBP){GBPplot[i]=f_MACD(GBPx,MACD_fast,MACD_slow,i);} if (CHF){CHFplot[i]=f_MACD(CHFx,MACD_fast,MACD_slow,i);} if (JPY){JPYplot[i]=f_MACD(JPYx,MACD_fast,MACD_slow,i);} if (CAD){CADplot[i]=f_MACD(CADx,MACD_fast,MACD_slow,i);} if (AUD){AUDplot[i]=f_MACD(AUDx,MACD_fast,MACD_slow,i);} if (NZD){NZDplot[i]=f_MACD(NZDx,MACD_fast,MACD_slow,i);} } }
Im Fall des Stochastik Oszillators muss zunächst die %K-Linie berechnet und anschließend mithilfe der Methode SimpleMA geglättet werden. Die geglättete Ergebnislinie wird in dem Diagramm abgebildet.
if (ind_type==Use_Stochastic_Main_on_indexes) { if (limit>1){ii=limit - stoch_period_k - 1;} else{ii=limit - 1;} for(i=ii;i>=0;i--) { if (USD){USDstoch[i]=f_Stoch(USDx,rsi_period,i);} if (EUR){EURstoch[i]=f_stoch(EURx,stoch_period_k,i);} if (GBP){GBPstoch[i]=f_stoch(GBPx,stoch_period_k,i);} if (CHF){CHFstoch[i]=f_stoch(CHFx,stoch_period_k,i);} if (JPY){JPYstoch[i]=f_stoch(JPYx,stoch_period_k,i);} if (CAD){CADstoch[i]=f_stoch(CADx,stoch_period_k,i);} if (AUD){AUDstoch[i]=f_stoch(AUDx,stoch_period_k,i);} if (NZD){NZDstoch[i]=f_stoch(NZDx,stoch_period_k,i);} } if (limit>1){ii=limit - stoch_period_sma - 1;} else{ii=limit - 1;} for(i=ii;i>=0;i--) { if (USD){USDplot[i]=SimpleMA(i,stoch_period_sma,USDstoch);} if (EUR){EURplot[i]=SimpleMA(i,stoch_period_sma,EURstoch);} if (GBP){GBPplot[i]=SimpleMA(i,stoch_period_sma,GBPstoch);} if (CHF){CHFplot[i]=SimpleMA(i,stoch_period_sma,CHFstoch);} if (JPY){JPYplot[i]=SimpleMA(i,stoch_period_sma,JPYstoch);} if (CAD){CADplot[i]=SimpleMA(i,stoch_period_sma,CADstoch);} if (AUD){AUDplot[i]=SimpleMA(i,stoch_period_sma,AUDstoch);} if (NZD){NZDplot[i]=SimpleMA(i,stoch_period_sma,NZDstoch);} } }
Damit sind die Indikatorberechnungen abgeschlossen. Die Abbildungen 4 -6 zeigen Beispiele unterschiedlicher Arten von Indikatoren.
Abbildung 4. RSI nach Indices
Abbildung 5. MACD nach Währungsindices
Abbildung 6. Stochastik Oszillator nach Währungsindices
Fazit
Bei der Umsetzung des Indikators MultiCurrencyIndex habe ich die unbegrenzte Anzahl an Indikatorpuffern in MQL5 ausgenutzt, was den Programmcode erheblich vereinfacht hat. Dieser Beitrag zeigt ein Beispiel für diesen Ansatz. Für zuverlässige Indikatoranzeigen wurde der Algorithmus zur Synchronisierung der unterschiedlichen Instrumente in Bezug auf den Nullbalken dargestellt. Ebenso wurde einer der möglichen Algorithmen für den Zugriff auf die Daten anderer Instrumente bezüglich des Kürzels, an das der Indikator angehängt ist, vorgeführt.
Da das Ziel des Beitrags war, die Möglichkeit der Arbeit mit einer immensen Anzahl von Indikatorpuffern vorzuführen, sind die vorgestellten Funktionen zur Berechnung von Indikatoren anhand benutzerdefinierter Datenfelder nicht die optimalsten, um die Leser nicht zu überfrachten, reichen jedoch zur Ausführung der erforderlichen Berechnungen aus.
Es spricht vieles „für“ und „gegen“ die Cluster-Analyse des Devisenmarktes. Auf diesem Ansatz beruhende Handelssysteme sind frei verfügbar und werden in unterschiedlichen Foren diskutiert, darunter auch in der MQL4.Community. Deshalb werden die Grundsätze des Handels mithilfe dieses Indikators in dem hier vorliegenden Artikel nicht behandelt.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/83
![Virtual Order Manager zum Verwalten von Ordern innerhalb der positionszentrischen Umgebung von MetaTrader 5](https://c.mql5.com/2/0/virtual__1.png)
![Übersetzung von MQL4 in MQL5](https://c.mql5.com/2/0/logo__4.png)
![Ein Beispiel für ein Handelssystem auf der Grundlage des Indikators Heiken-Ashi](https://c.mql5.com/2/0/Heikin_Ashi_MQL5.png)
![MetaTrader 5: Handelsprognosen und Umsatzzahlen per E-Mail in Blogs, sozialen Netzen und auf thematischen Webseiten veröffentlichen](https://c.mql5.com/2/0/social-network.png)
![MQL5 - Sprache von Handelsstrategien, eingebaut ins Kundenterminal MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.