
Übertragen eines Indikator Code in einen Expert Advisor Code. Allgemeine Strukturelle Regelungen von Expert Advisor und Anzeigefunktionen
Einführung
In dem vorherigen Artikel (Transferring an Indicator Code into an Expert Advisor Code. Indicator Structure) haben wir die allgemeine Struktur eines Indikators analysiert, den Code, der gedacht ist für die Übertragung in einen Expert Advisor Code und beschrieben die Grundgedanken einer vorläufigen Einstellung eines Indikator Codes. Lassen Sie uns nun versuchen den erhaltenen Code in eine benutzerdefinierte Funktion zu verändern, weil das vielleicht die einfachste Art der Darstellung eines Indikators in einem Expert Advisor ist. Eine benutzerdefinierte Funktion kann als mqh-Datei dargestellt werden und ihre Deklaration im Expert Advisor, mit Verwendung der Anweisung #include, erfordert sehr wenig Platz. Das Aufrufen dieser Funktion ist nicht viel schwieriger als das Aufrufen eines spezifischen Indikators. Was wichtiger ist, solche benutzerdefinierten Funktionen können eher universell sein, für ihre weitere Verwendung in jedem Expert Advisor.
Bevor wir anfangen eine solche Funktion zu schreiben, lassen Sie uns analysieren wie diese Funktion mit dem anderen Teil des Expert Advisor interagieren wird, unabhängig von der inneren Struktur der Funktion.
Struktur eines EA mit Benutzerdefiniertem Indikator Aufruf
Lassen Sie uns zunächst den schematischen Aufbau eines EA untersuchen, der Daten von benutzerdefinierten Indikatoren erhält. In diesem EA sind wir vor allem nur an dem Teil interessiert, der Daten von einem benutzerdefinierten Indikator erhält. Bis jetzt werden wir nicht über die Art sprechen, wie der EA diese Daten verarbeitet, diese in Handelssignale überträgt und die Struktur eines ausführenden Teils des EA. Lassen Sie uns als benutzerdefinierten Indikator in diesem EA denjenigen analysieren, der im vorherigen Artikel besprochen wurde. Hier ist ein Beispiel einer Expert Advisor Struktur:
//+------------------------------------------------------------------+ //| ExpertIndPlan0.mqh | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2007, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" //---- EA input parameters extern int period10 = 15; extern int period11 = 15; extern int period12 = 15; //---- EA input parameters extern int period20 = 15; extern int period21 = 15; extern int period22 = 15; //---- Declaring buffers for indicator values double Ind_Buffer1[6]; double Ind_Buffer2[6]; //+------------------------------------------------------------------+ //| Custom Expert initialization function | //+------------------------------------------------------------------+ int init() { // Here is the code of EA initialization //---- initialization end return(0); } //+------------------------------------------------------------------+ //| Custom Expert iteration function | //+------------------------------------------------------------------+ int start() { //---- Checking whether the bars number is enough for further calculation if(iBars(Symbol(), 0) < period10 + period11 + period12 + 10) return(0); if(iBars(Symbol(), 0) < period20 + period21 + period22 + 10) return(0); //---- getting indicator values for further calculation for(int bar = 5; bar >= 1; bar--) { Ind_Buffer1[bar] = iCustom("IndicatorPlan", Symbol(), 0, period10, period11, period12, 0, bar); Ind_Buffer2[bar] = iCustom("IndicatorPlan", Symbol(), 0, period20, period21, period22, 0, bar); } // Here is the EA code, forming trade signals // based on the values of indicator buffer cells //---- // here is the EA executive part code, // requesting for placing an order //---- return(0); } //+------------------------------------------------------------------+
In diesem Schema nehmen wir bei jedem Tick von einem Nullpuffer des benutzerdefinierten Indikators IndicatorPlan.mq4 gezählte Werte in zwei Aufrufen und platzieren sie in gemeinsamen Arrays Ind_buffer1[] und Ind_Buffer2[]. Das Schema des Aufrufens eines Indikators wurde mit der Überlegung gemacht, dass wir für weitere Berechnungen nur die fünf letzten Indikatorwerte benötigen, mit Ausnahme des Null-Wertes.
Struktur eines EA mit Benutzerdefiniertem Funktionsaufruf
Während wir eine universelle Anzeigefunktion entwickeln, geeignet für jeden Expert Advisor, sollte sie die erhaltenen Werte an Indikator-Analoga senden, die Indikatorwerte für alle Balken des Charts speichern werden. Natürlich, wir könnten eine Anzeigefunktion entwickeln, die komplett analog wäre zum Aufruf eines Indikators, aber eine solche Funktion zu schreiben würde zu viel Zeit in Anspruch nehmen und der Code wird sehr lang.
Wir können es einfacher machen. Diese Funktion sollte als Eingabe die Parameter eines benutzerdefinierten Indikators und Puffer empfangen, und sie sollte den gleichen Puffer mit einer Anzeigemodus-Emulation zurückgeben, wobei Zellen mit berechneten Indikatorwerten gefüllt werden. Es kann in unserer Funktion einfach gemacht werden durch Deklarieren einer durch Verweis verknüpften externen Variable, entsprechend einem Anzeigepuffer. In der MQL4 Sprache wird es wie dieses aussehen: double& InputBuffer. Die Anzeigefunktion sollte als eine logische deklariert sein, 'true' zurückgeben, wenn eine Berechnung erfolgreich war, und 'false', wenn eine Berechnung erfolglos war aufgrund des Fehlens der richtigen Anzahl an Balken im Chart. Nach diesen Erklärungen sollte die Anzeigefunktion, aufgebaut nach dem Indikatorschema, besprochen im vorherigen Artikel, die folgende Form haben:
bool Get_IndSeries(int Number,string symbol, int timeframe, bool NullBarRecount, int period0, int period1, int period2, double& InputBuffer0[], double& InputBuffer1[], double& InputBuffer2[])
Die Anzeigefunktion hat eine zusätzliche externe variable Zahl, die den Wert von dieser Anzeigefunktion Aufrufnummer übernimmt.
Es ist natürlich, dass, mit Ausnahme des Anzeigepuffer InputBuffer0, die externen Variablen auch Puffer enthalten für Zwischenberechnungen, InputBuffer1 und InputBuffer2, weil es sehr problematisch ist, diese Puffer innerhalb der Funktion unterzubringen. Es ist besser den Anzeigemodus dieser Puffer-Operation innerhalb der Funktion zu emulieren. Es wird keine Probleme verursachen. Lassen Sie uns nun auf die Bedeutung der externen Variable NullBarRecout eingehen. Tatsächlich benötigt die Mehrheit der EAs keine Berechnungen auf der Null-Bar, und während wir den Code für eine universelle Anzeigefunktion schreiben, wird es die Indikatorwerte natürlich auf der Null-Bar berechnen, was die Ausführungszeit erheblich erhöhen kann. Durch die Angabe externer Parameter der Funktion NullBarRecount als 'false', verbieten wir der Funktion Berechnungen auf der Null-Bar, wenn es nicht notwendig ist.
Jetzt können wir das Schema einer EA-Struktur für den Aufruf von Indikatoren in einer Variante mit Aufruffunktionen darstellen:
//+------------------------------------------------------------------+ //| ExpertIndPlan1.mqh | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2007, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" //---- EA input parameters extern int period10 = 15; extern int period11 = 15; extern int period12 = 15; //---- EA input parameters extern int period20 = 15; extern int period21 = 15; extern int period22 = 15; //---- Indicator buffers declaration double Ind_Buffer10[], Ind_Buffer11[], Ind_Buffer12[]; double Ind_Buffer20[], Ind_Buffer21[], Ind_Buffer22[]; //+------------------------------------------------------------------+ //| Get_IndSeries() function | //+------------------------------------------------------------------+ //---- Declaration of the function Get_IndSeries() bool Get_IndSeries(int Number,string symbol, int timeframe, bool NullBarRecount, int period0, int period1, int period2, double& InputBuffer0[], double& InputBuffer1[], double& InputBuffer2[]) { //---- // Here is the code of the function GetIdicator() //---- return(true); } //+------------------------------------------------------------------+ //| Custom Expert initialization function | //+------------------------------------------------------------------+ int init() { //---- // Here is the code of the EA initialization //---- initialization end return(0); } //+------------------------------------------------------------------+ //| Custom Expert iteration function | //+------------------------------------------------------------------+ int start() { //---- Checking whether the bars number is enough for further calculation if(iBars(Symbol(), 0) < period10 + period11 + period12 + 10) return(0); if(iBars(Symbol(), 0) < period20 + period21 + period22 + 10) return(0); //---- getting indicator values for further calculation if(!Get_IndSeries(0,Symbol(), 0, false, period10, period11, period12, Ind_Buffer10, Ind_Buffer11, Ind_Buffer12)) return(0); if(!Get_IndSeries(1, Symbol(), 0, false, period20, period21, period22, Ind_Buffer20, Ind_Buffer21,Ind_Buffer22)) return(0); //---- // Here is the EA code, forming trade signals // based on the values of indicator buffer cells //---- // here is the EA executive part code, // requesting for placing an order //---- return(0); } //+------------------------------------------------------------------+
Allgemeines Schema der Umwandlung eines Indikator-Code in eine Benutzerdefinierte Funktion
Nach diesen Vorarbeiten können wir weitergehen zum Aufbau eines Allgemeinen Schemas einer inneren Struktur einer Anzeigefunktion. Lassen Sie uns als Basis das letzte Anzeigeschema des vorherigen Artikels nehmen. Es sollte keine Schwierigkeiten geben:
1. Nehmen Sie nur die Inhalte der Funktion int start(),
2. Hinzufügen der Deklaration der Funktion Get_IndSeries():
bool Get_IndSeries(string symbol, int timeframe, bool NullBarRecount, int period0, int period1, int period2, double& InputBuffer0, double& InputBuffer1, double& InputBuffer2)
3. Ändern Sie die Namen der Anzeigepuffer innerhalb des codes (Ind_buffer) entsprechend in Puffernamen (InputBuffer) der externen Variablen der Funktion Get_IndSeries(),
4. Hinzufügen der Deklaration der Variable LastCountBar,
5. Prüfen Sie Wahrheit der Variable NullBarRecount:
if(!NullBarRecount) LastCountBar = 1;
6. In allen Zyklen der Anzeigeberechnung ändern Sie Zero in LastCountBar,
7. Machen Sie Änderungen ganz am Anfang des Codes, bei der Prüfung, ob die Anzahl der Balken ausreichend für weitere Berechnungen ist: return(0) in return(false),
8. Am Ende des Codes ändern Sie return(0) in return(true);
Die Anzeigefunktion ist fertig:
//+------------------------------------------------------------------+ //| Get_IndSeries.mqh | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ bool Get_IndSeries(int Number, string symbol,int timeframe, bool NullBarRecount, int period0, int period1, int period2, double& InputBuffer0[], double& InputBuffer1[], double& InputBuffer2[]) { //---- getting the number of all bars of a chart int IBARS = iBars(symbol, timeframe); //---- Checking whether the bars number is enough for further calculation if(IBARS < period0 + period1 + period2) return(false); //---- EMULATION OF INDICATOR BUFFERS if(ArraySize(InputBuffer0) < IBARS) { ArraySetAsSeries(InputBuffer0, false); ArraySetAsSeries(InputBuffer1, false); ArraySetAsSeries(InputBuffer2, false); //---- ArrayResize(InputBuffer0, IBARS); ArrayResize(InputBuffer1, IBARS); ArrayResize(InputBuffer2, IBARS); //---- ArraySetAsSeries(InputBuffer0, true); ArraySetAsSeries(InputBuffer1, true); ArraySetAsSeries(InputBuffer2, true); } //----+ introducing static memory variables static int IndCounted[]; //----+ changing the size of static variables if(ArraySize(IndCounted) < Number + 1) ArrayResize(IndCounted, Number + 1); //----+ introducing an integer variable int LastCountBar; //----+ Checking if the recalculation of the zero bar is allowed if(!NullBarRecount) LastCountBar = 1; else LastCountBar = 0; //----+ Inserting a variable with a floating point double Resalt0, Resalt1, Resalt2; //----+ Inserting integer variables and getting already calculated bars int limit, MaxBar, bar, counted_bars = IndCounted[Number]; //----+ Remembering the number of all bars of a chart (we do not count the zero bar!) IndCounted[Number] = IBARS - 1; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated limit = IBARS - counted_bars - 1; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated MaxBar = IBARS - 1 - (period0 + period1 + period2); //---- initialization of zero if(limit > MaxBar) { limit = MaxBar; for(bar = IBARS - 1; bar >= 0; bar--) { InputBuffer0[bar] = 0.0; InputBuffer1[bar] = 0.0; InputBuffer2[bar] = 0.0; } } //----+ THE FIRST CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= LastCountBar; bar--) { // Here code of the variable Resalt1 calculation // based on the external variable period1 InputBuffer1[bar] = Resalt1; } //----+ THE SECOND CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= LastCountBar; bar--) { // Here code of the variable Resalt2 calculation // based on the values of the buffer Ind_Buffer1[] // and external variable period2 InputBuffer2[bar] = Resalt2; } //----+ THE MAIN CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= LastCountBar; bar--) { // Here code of the variable Resalt0 calculation // based on the values of the buffer Ind_Buffer2[] // and external variable period0 InputBuffer0[bar] = Resalt0; } return(true); } //+------------------------------------------------------------------+
Ich denke, wenn ein Leser MQL4 sehr gut verwendet, wird er nach dem Lesen der oben beschriebenen Vorgänge keine Schwierigkeiten haben, beim Schreiben von Anzeigefunktionen nach dem angegebenen Schema.
Beispiel des Schreibens einer Benutzerspezifischen Anzeigefunktion
Lassen Sie uns nun eine Anzeigefunktion schreiben. Dazu nehmen wir einen möglichst einfachen Indikator:
//+------------------------------------------------------------------+ //| RAVI.mq4 | //| Copyright © 2005, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2005, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" //---- drawing the indicator in a separate window #property indicator_separate_window //---- number of indicator buffers #property indicator_buffers 1 //---- indicator color #property indicator_color1 Red //---- INPUT PARAMETERS OF THE INDICATOR extern int Period1 = 7; extern int Period2 = 65; extern int MA_Metod = 0; extern int PRICE = 0; //---- indicator buffers double ExtBuffer[]; //+------------------------------------------------------------------+ //| RAVI initialization function | //+------------------------------------------------------------------+ int init() { //---- indicator drawing style SetIndexStyle(0, DRAW_LINE); //---- indicator buffers SetIndexBuffer(0,ExtBuffer); //---- indicator name and labels for subwindows IndicatorShortName("RAVI (" + Period1+ ", " + Period2 + ")"); SetIndexLabel(0, "RAVI"); //---- initialization end return(0); } //+------------------------------------------------------------------+ //| RAVI iteration function | //+------------------------------------------------------------------+ int start() { int MinBars = MathMax(Period1, Period2); //---- checking whether the bars number is enough for further calculation if(Bars < MinBars) return(0); //----+ Introducing variables with a floating point double MA1, MA2, result; //----+ Introducing integer variables and getting already calculated bars int MaxBar, bar, limit, counted_bars = IndicatorCounted(); //---- checking for possible errors if(counted_bars < 0) return(-1); //---- the last calculated bar should be recalculated if(counted_bars > 0) counted_bars--; //---- defining the number of the oldest bar, // starting from which all bars will be recalculated MaxBar = Bars - 1 - MinBars; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated limit = Bars - counted_bars - 1; //---- zero initialization if(limit > MaxBar) { for(int ii = Bars - 1; ii >= MaxBar; ii--) ExtBuffer[ii] = 0.0; limit = MaxBar; } //---- main cycle for(bar = 0; bar <= limit; bar++) { MA1 = iMA(NULL, 0, Period1, 0, MA_Metod, PRICE,bar); MA2 = iMA(NULL, 0, Period2, 0, MA_Metod, PRICE,bar); //---- result = ((MA1 - MA2) / MA2)*100; ExtBuffer[bar] = result; } //---- return(0); } //+------------------------------------------------------------------+
Algorithmus festlegen
1. Alle unnötigen Elemente des Indikator-Codes loswerden,
2. Schreiben Sie den Code für die Anzeigepuffer-Emulation für einen einzelnen Puffer ExtBuffer[],
3. Ersetzen Sie die Funktion IndicatorCounted() für die Variable IndCounted,
4. Initialisieren Sie die Variable IndCounted durch die Menge der Chart-Balken minus eins,
5. Ädern Sie vorgegebene variable Balken in den Aufruf der Zeitreihen iBars (Symbol, Zeitrahmen),
6. Löschen Sie die nicht benötigte Überprüfung für counted_bars:
//---- checking possible errors if(counted_bars < 0) return(-1); //---- the last calculated bar must be recalculated if(counted_bars > 0) counted_bars--;
7. Belassen Sie nur die Inhalte der Funktion int start(),
8. Hinzufügen der Deklaration der Funktion Get_RAVISeries():
bool Get_RAVISeries(int Number, string symbol,int timeframe, bool NullBarRecount, int Period1, int Period2, int MA_Metod, int PRICE, double& InputBuffer[])
9. Ersetzen Sie die Anzeigepuffer-Namen innerhalb des Codes (ExtBuffer) entsprechend für Puffer-Namen (InputPuffer) vo externen Variablen der Funktion Get_RAVISeries(),
10. Hinzufügen der Deklaration der Variable LastCountBar,
11. Ändern Sie die statische Variable IndCount in ein Array IndCounted[Number] und fügen Sie einen Code hinzu zum Ändern der Größe von Variablen, abhängig von der Anzahl an Aufrufen der Funktion Get_RAVISeries. mqh:
//----+ changing the size of static variables if(ArraySize(IndCounted) < Number + 1) { ArrayResize(IndCounted, Number + 1); }
12. Prüfen Sie die Wahrheit der Variable NullBarRecount:
if(!NullBarRecount) LastCountBar = 1;
13. In allen Anzeigeberechnungszyklen ändern Sie Null in LastCountBar:
for(bar = limit; bar >= LastCountBar; bar--)
14. Machen Sie eine Änderung am Anfang des Codes, wo geprüft wird ob die Anzahl der Balken ausreichend ist: return(0) in return(false),
15. Am Ende ersetzen Sie return(0) mit return(true).
Nach allen Änderungen des Codes erhalten wir die Anzeigefunktion Get_RAVISeries():
//+------------------------------------------------------------------+ //| Get_RAVISeries.mqh | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ bool Get_RAVISeries(int Number, string symbol,int timeframe, bool NullBarRecount, int Period1, int Period2, int MA_Metod, int PRICE, double& InputBuffer[]) { //---- getting the number of all bars of a chart int IBARS = iBars(symbol, timeframe); //---- Checking whether the bars number is enough for further calculation if(IBARS < MathMax(Period1, Period2)) return(false); //---- EMULATION OF INDICATOR BUFFERS if(ArraySize(InputBuffer) < IBARS) { ArraySetAsSeries(InputBuffer, false); //---- ArrayResize(InputBuffer, IBARS); //---- ArraySetAsSeries(InputBuffer, true); } //----+ inserting static variables of memory static int IndCounted[]; //----+ changing the size of static variables if(ArraySize(IndCounted) < Number + 1) { ArrayResize(IndCounted, Number + 1); } //----+ Introducing an integer variable int LastCountBar; //----+ Checking whether the recalculation of the zero bar is allowed if(!NullBarRecount) LastCountBar = 1; //----+ Introducing floating point variables double MA1,MA2,result; //----+ Introducing integer variables and getting alreadu calculated bars int MaxBar, bar, limit, counted_bars = IndCounted[Number]; //----+ Remembering the amount of all chart bars IndCounted[Number] = IBARS - 1; //---- determining the number of the oldest bar, // starting from which new bars will be recalculated limit = IBARS - counted_bars - 1; // Print(IBARS - counted_bars); //---- determining the number of the oldest bar, // starting from which all bars will be recalculated MaxBar = IBARS - 1 - MathMax(Period1, Period2); //---- zero initialization if(limit > MaxBar) { limit = MaxBar; for(bar = IBARS - 1; bar >= 0; bar--) { InputBuffer[bar] = 0.0; } } //----+ THE FIRST CYCLE OF INDICATOR CALCULATION for(bar = limit; bar >= LastCountBar; bar--) { MA1 = iMA(symbol, timeframe, Period1, 0, MA_Metod, PRICE, bar); MA2 = iMA(symbol, timeframe, Period2, 0, MA_Metod, PRICE, bar); //---- result = ((MA1 - MA2) / MA2)*100; InputBuffer[bar] = result; } //----+ return(true); } //+------------------------------------------------------------------+
Sicher, all dies ist großartig! Kompetent, nicht zu einfach. Aber eine Frage kommt auf - wird diese Anzeigefunktion das gleiche berechnen wie ein benutzerdefinierter Indikator?
Testen der Benutzerdefinierten Anzeigefunktion auf Rechengenauigkeit
Wir müssen prüfen, ob die Funktions-Berechnungsergebnisse gleich sind, wie die der Berechnung eines benutzerdefinierten Indikators. Zu diesem Zweck ist der beste Expert Advisor derjenige, der nicht tradet und nur Werte erhält von dem benutzerdefinierten Indikator RAVI.mq4 und der benutzerdefinierten Funktion Get_RAVISeries(), die Unterschiede findet und danach den Anzeigewert, den Wert der benutzerdefinierten Anzeige und die Differenz zwischen ihnen in eine Protokolldatei sendet. Alles was wir tun müssen, ist den Inhalt der Protokolldatei zu analysieren, um die endgültige Aussage zu machen über die Übereinstimmung der benutzerdefinierten Funktion mit dem Indikator RAVI.mq4:
//+------------------------------------------------------------------+ //| Get_RAVISeriesTest.mq4 | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2007, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" //---- INPUT EA PARAMETERS extern bool NullBarRecount = true; //---- indicator buffers double RAVI_Buffer0[]; double RAVI_Buffer1[]; double RAVI_Buffer2[]; //+------------------------------------------------------------------+ //| Get_RAVISeries() function | //+------------------------------------------------------------------+ #include <Get_RAVISeries.mqh> //+------------------------------------------------------------------+ //| Custom Expert initialization function | //+------------------------------------------------------------------+ int init() { //---- initialization end return(0); } //+------------------------------------------------------------------+ //| Custom Expert iteration function | //+------------------------------------------------------------------+ int start() { //---- double Ind_Velue, Resalt; //---- if(!Get_RAVISeries(0, Symbol(), 0, NullBarRecount, 10, 20, 1, 0, RAVI_Buffer0)) return(0); if(!Get_RAVISeries(1, Symbol(), 240, NullBarRecount, 25, 66, 2, 1, RAVI_Buffer1)) return(0); if(!Get_RAVISeries(2, Symbol(), 1440, NullBarRecount, 30, 70, 3, 3, RAVI_Buffer2)) return(0); //---- getting indicator values for the test 0 Ind_Velue = iCustom(NULL, 0, "RAVI", 10, 20, 1, 0, 0, 2); Resalt = RAVI_Buffer0[2] - Ind_Velue; Print(" " + Ind_Velue + " " + RAVI_Buffer0[2] + " " + Resalt+""); //---- getting indicator values for the test 1 Ind_Velue = iCustom(NULL, 240, "RAVI", 25, 66, 2, 1, 0, 2); Resalt = RAVI_Buffer1[2] - Ind_Velue; Print(" " + Ind_Velue + " " + RAVI_Buffer1[2] + " " + Resalt+"" ); //---- getting indicator values for the test 2 Ind_Velue = iCustom(NULL, 1440, "RAVI", 30, 70, 3, 3, 0, 2); Resalt = RAVI_Buffer2[2] - Ind_Velue; Print(" " + Ind_Velue + " " + RAVI_Buffer2[2] + " " + Resalt + ""); //---- return(0); } //+------------------------------------------------------------------+
In einem Strategietester starten Sie den Expert Advisor Get_RAVISeriesTest. Selbstverständlich muss die kompilierte Datei RAVI.mq4 bereits in dem Ordner expert\indicators sein, und die Dateio GetRAVIseries.mqh in dem Ordner \expert \indicators des MetaTrader Client Terminals. Im Strategietester-Journal und in einer Protokolldatei sehen wir zwei Spalten mit Anzeigewerten und ihr Analogon in der Form einer Funktion. Die dritte Spalte zeigt die Differenz dieser Werte. Alle Werte der letzten Spalte sind gleich Null. Es bedeutet, die Werte sind in beiden Fällen identisch. Wir können feststellen, dass die Aufgabe des Schreibens einer benutzerdefinierten Anzeigefunktion erfolgreich gelöst ist!
Fazit
Es gelang uns also die Aufgabe der Übertragung eines Indikator-Codes aus einem benutzerdefinierten Indikator in einen Expert Advisor Code, durch das Herstellen eines Analogon des Indikators als universelle benutzerdefinierte Funktion, die in jeder mqh-Datei platziert werden und in dem Code von jedem Expert Advisor verwendet werden kann, analog zu einem benutzerdefinierten Indikator.
In dem Nächsten Artikel zu diesem Thema, analysieren wir ein schwierigeres Beispiel des Schreibens von Funktionen dieser Art und die Implementierung eines einfachen Expert Advisor, basieren auf einer solchen Funktion.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1457





- 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.