![Die Übertragung eines Indikatorcodes in einen Expertcode. Die Struktur eines Indikators](https://c.mql5.com/i/articles/overlay.png)
Die Übertragung eines Indikatorcodes in einen Expertcode. Die Struktur eines Indikators
Einleitung
Damit Sie den Beitrag besser verstehen könnten, empfiehlt der Autor dem Leser das folgende Material:
- MetaQuotes Software Corp. Besonderheiten benutzerdefinierter Indikatoren. https://www.mql5.com/de/articles/1497
- Nikolay Kositsin. Mehrmalige Neuberechnungen des nullwertigen Bars in einigen Indikatoren. https://www.mql5.com/de/articles/1411
Bevor wir das Gespräch über das Thema anfangen, welches ich im Titel angedeutet habe, wäre die folgende Frage zur Recht: "Wieso brauchen wir einen Indikatorcode in einen EA-Code zu übertragen, wenn der Expert mit benutzerdefinierten Indikatoren in den meisten Fällen viel einfacher aussieht, als seine Analoge, die alle notwendigen benutzerdefinierten Indikatoren für seine Funktionalität innerhalb des eigenen Codes enthält? Vor allem, wenn wir die Tatsache berücksichtigen, dass die Ergebnisse in beiden Fällen absolut identisch sein werden, wenn der Code korrekt geschrieben wird!"
Meiner Meinung nach ist es nur in zwei Situationen notwendig:
- Wenn die Werte bei EA-Berechnungen nicht verwendet werden, die auf dem nullwertigen Bar berechnet wurden, dann würden wir natürlich gerne auf die unnötigen Neuberechnungen auf dem nullwertigen Bar verzichten und genauso auf dem ersten Bar. Dies ermöglicht die Optimierungszeit eines solchen EAs dreimal zu verkürzen, was bei einem komplizierten und ressource-intensiven Code sehr aktuell ist!
- Die kommerzielle Verwendung eines Expert Advisors mit dem maximalen Schutz seines Codes gegen seine Decompiling.
Im zweiten Fall ist die Situation ganz klar, und die Übertragung des Codes ist durchaus sinnvoll. Während es im ersten Fall ist in den meisten Situationen viel einfacher, den Code der benutzerdefinierten Indikatoren neu zu schreiben, ohne unnötige Berechnungen! Natürlich werden solche Indikatoren nur für Expert Advisors geeignet, und nicht für das Handeln! Also, lassen Sie uns bitte den Artikel von dieser Variante der Problemlösung beginnen.
Beispiele für Indikator-Optimierung
Zunächst einmal würde ich Ihre Aufmerksamkeit auf das folgende Codefragment eines benutzerdefinierten Indikators lenken:
int start() { int limit; int counted_bars = IndicatorCounted(); //---- das letzte berechnete Bar wird neuberechnet if(counted_bars > 0) counted_bars--; limit = Bars - counted_bars - 1; //---- Die Hauptloop for(int i = limit; i >= 0; i--) { //---- ExtBlueBuffer[i] = iMA(NULL, 0, JawsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtRedBuffer[i] = iMA(NULL, 0, TeethPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtLimeBuffer[i] = iMA(NULL, 0, LipsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); } //---- return(0); }
In diesem Fall würde uns die folgende Zeile interessieren:
if(counted_bars > 0) counted_bars--;
Die Bedeutung dieser Prüfung mit Verringerung des Wertes der Variable counted_bars um eins ist die folgende: Wenn ein benutzerdefinierter Indikator diese Zeile nicht enthält, kann er falsche Werte aus seinem Puffer in EA senden, wenn das nullwertige Bar geändert wird. Die Indikatorkurve im EA wird ganz "zerknittert" aussehen!
Aber es sollte hier angemerkt werden, dass einige Glättungsalgorithmen zum Referenzpunkt empfindlich sind, aus dem die Glättung beginnt. Das heißt, um identische Werte zu haben, muss man die Übereinstimmung der ältesten Bars-Nummer in Loops besorgen, sowie in Indikatoren, als auch im Indikatorcode innerhalb des EAs, von dem die Neuberechnung aller Bars beginnt.
Hier ist ein Beispiel, welches diese Methode einer Indikatorcodeoptimierung für die schnellere Funktionalität im EA erklärt. Im Hauptloop des Indikators ersetzen wir 0 um 1, nachdem der Indikator die Neuberechnung seines Wertes auf dem nullwertigen Bar aufhört.
// Anstatt von for(int i = limit; i >= 0; i--) // einfügen for(int i = limit; i >= 1; i--)
Als Ergebnis wird der Quellcode wie folgende aussehen:
int start() { int limit; int counted_bars = IndicatorCounted(); //---- das letzte berechnete Bar wird neuberechnet if(counted_bars > 0) counted_bars--; limit = Bars - counted_bars - 1; //---- Die Hauptloop //nun beendet die Loop auf 1 for(int i = limit; i >= 1; i--) { //---- ExtBlueBuffer[i] = iMA(NULL, 0, JawsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtRedBuffer[i] = iMA(NULL, 0, TeethPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); ExtLimeBuffer[i] = iMA(NULL, 0, LipsPeriod, 0, MODE_SMMA, PRICE_MEDIAN, i); } //---- return(0); }Ich wiederhole die Tatsache, dass das obige Verfahren für EAs ist, die nur auf geschlossenen Bars funktionieren, das heißt, an allen Bars außer den nullwertigen Bars!
Es wird angenommen, dass der Leser die Optimierung des Indikatorencodes gut kennt, damit dieser Indikator nur auf den Ticks der ungerechneten Bars neuberechnet. Meiner Meinung nach sollte man das Programmieren in MQL4 erstmal von diesen Aspekten lernen.
Wenn Sie Ihren EA ernsthaft im realen Handeln verwenden wollen und Ihr Geld vertrauen, dann sollten Sie in Ihrem EA sorgfältig alle Details überprüfen, sowie die Indikatoren, mit denen der EA arbeitet. Außerdem sollten Sie es selbst tun!! Ich denke, es ist viel einfacher und vernünftiger ein paar Tage zu lernen, um ein gründliches Verständnis von der Struktur des Indikators und Methoden der Optimierung ihres Codes zu bekommen, als mit Geduld drei Monate lang an dem optimierten EA sitzen zu bleiben, der die Werte aus einem grob geschrieben Indikator erhält!
Also ich hoffe, es muss jetzt klar sein, dass man ohne schwerwiegende Gründe den Indikatorcode in einen Expertcode nicht übertragen soll. Wenn ein Indikator korrekt und optimal geschrieben ist, wird der EA ohnehin nicht viel langsamer funktionieren. Das ist generell viel einfacher zuerst einen EA-Code mit der Verwendung der benutzerdefinierten Indikatoren zu schreiben und die Einrichtungsarbeiten in dieser Form durchzuführen. Und wenn Ihr EA nach allen diesen wirklich perfekte Ergebnisse zeigt, kann der Code erst dann weiter optimiert werden, einen Aufruf zu benutzerdefinierten Indikatoren nach dem anderen um Codefragmente der Indikatoren zu ersetzen.
Dabei muss man die Tatsache berücksichtigen, dass die getesteten Gewinnwerte und Verlustwerte nach der Ersetzung des EA-Codes nicht anderes werden sollten! Aus meiner Sicht hat es einen Sinn, nur einfache Situationen mit Übertragung zu betrachten, wenn der Indikator angemessene Größe des Codes hat. Ansonsten wird die Aufgabe so schwer, dass die Lösung dieser Aufgabe die Erkenntnisse eines hochqualifizierten Programmierers verlangt, der das sowieso gut kennt!
Es gibt jede Menge Indikatoren, und jeder hat seinen einzigartigen Code. Deshalb kann man kaum eine universelle Methode für eine Übertragung eines Codes schaffen, die ohne Ausnahme zu allen Indikatoren passen würde. Das Problem wird durch die Tatsache komplizierte, dass dasselbe benutzerdefinierte Indikatoren in einem EA-Code mehrmals vorkommen können! Wenn ein Indikatorcode mehr oder weniger einfach ist, kann er in einer benutzerdefinierte Funktion geschrieben werden und dann wird die Ersetzung der benutzerdefinierten Indikatoren zu Funktionen ganz einfach gehen. Aber sehr oft wird der EA-Code zu groß, dass es fast unmöglich ist, einen Fehler darin zu finden. Und alle unsere Bemühungen werden dann vergeblich!
Ein allgemeines Schema der Struktur eines Indikators
//+------------------------------------------------------------------+ //| IndicatorPlan.mq4 | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2007, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" //---- Darstellung des Indikators im Hauptfenster #property indicator_chart_window //---- die Anzahl der Indikatorpuffers #property indicator_buffers 1 //---- die Farbe des Indikators #property indicator_color1 Gold //---- Eingabeparameter des Indikators extern int period0 = 15; extern int period1 = 15; extern int period2 = 15; //---- Indikatorpuffers double Ind_Buffer0[]; double Ind_Buffer1[]; double Ind_Buffer2[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- Definieren des Zeichenstils vom Chart SetIndexStyle(0, DRAW_LINE); //---- 3 Indikatorpuffers wurden für die Zählung verwendet IndicatorBuffers(3); SetIndexBuffer(0, Ind_Buffer0); SetIndexBuffer(1, Ind_Buffer1); SetIndexBuffer(2, Ind_Buffer2); //---- Das Ende des Initialisierens return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { //---- Die Überprüfung der Anzahl der Bars, damit sie ausreichend für die Berechnung wären if(Bars < period0 + period1 + period2) return(0); //----+ Eingabe der Variablen mit Gleitkomma double Resalt0, Resalt1, Resalt2; //----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars int limit, MaxBar,bar, counted_bars = IndicatorCounted(); //---- Überprüfung auf mögliche Fehler if(counted_bars < 0) return(-1); //---- das letzte berechnete Bar muss neuberechnet werden if(counted_bars > 0) counted_bars--; //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung, // der neuen Bars beginnt limit = Bars - counted_bars - 1; //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung, // aller Bars beginnt MaxBar = Bars - 1 - (period0 + period1 + period2); //---- Initialisieren der Null if(limit > MaxBar) { limit = MaxBar; for(bar = Bars - 1; bar >= MaxBar; bar--) { Ind_Buffer0[bar] = 0.0; Ind_Buffer1[bar] = 0.0; Ind_Buffer2[bar] = 0.0; } } //----+ Die erste Loop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt1 auf der Grundlage der externen //Variable period1 Ind_Buffer1[bar] = Resalt1; } //----+ Die zweite Loop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt2 // auf der Grundlage des Wertes vom Puffer Ind_Buffer1[] und // der externen Variable period2 Ind_Buffer2[bar] = Resalt2; } //----+ Die Hauptloop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt0 // auf der Grundlage des Wertes vom Puffer Ind_Buffer2[] und // der externen Variable period0 Ind_Buffer0[bar] = Resalt0; } return(0); } //+------------------------------------------------------------------+
Nun lassen uns allen unnötigen Elemente aus diesem Schema löschen, die uns in diesem Zusammenhang nicht interessieren, und die im Expert Advisor nicht notwendig sind:
//+------------------------------------------------------------------+ //| IndicatorPlan1.mq4 | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ //---- Eingabeparameter des Indikators extern int period0 = 15; extern int period1 = 15; extern int period2 = 15; //---- Indikatorpuffers double Ind_Buffer0[]; double Ind_Buffer1[]; double Ind_Buffer2[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- Das Ende des Initialisierens return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { //---- Die Überprüfung der Anzahl der Bars, damit sie ausreichend für die Berechnung wären if(Bars < period0 + period1 + period2) return(0); //----+ Eingabe der Variablen mit Gleitkomma double Resalt0, Resalt1, Resalt2; //----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars int limit, MaxBar, bar, counted_bars = IndicatorCounted(); //---- Überprüfung auf mögliche Fehler if(counted_bars < 0) return(-1); //---- das letzte berechnete Bar muss neuberechnet werden if(counted_bars > 0) counted_bars--; //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung, // der neuen Bars beginnt limit = Bars - counted_bars - 1; //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung, // aller Bars beginnt MaxBar = Bars - 1 - (period0 + period1 + period2); //---- Initialisieren der Null if(limit > MaxBar) { limit = MaxBar; for(bar = Bars - 1; bar >= MaxBar; bar--) { Ind_Buffer0[bar] = 0.0; Ind_Buffer1[bar] = 0.0; Ind_Buffer2[bar] = 0.0; } } //----+ Die erste Loop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt1 auf // der Grundlage der externen Variable period1 Ind_Buffer1[bar]= Resalt1; } //----+ Die zweite Loop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt2 // auf der Grundlage des Wertes vom Puffer Ind_Buffer1[] und // der externen Variable period2 Ind_Buffer2[bar] = Resalt2; } //----+ Die Hauptloop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt0 // auf der Grundlage des Wertes vom Puffer Ind_Buffer2[] und // der externen Variable period0 Ind_Buffer0[bar] = Resalt0; } return(0); } //+------------------------------------------------------------------+Dieser Code könnte allerdings leicht in einem Expert Advisor-Code platziert werden, wenn es nicht ein paar kleine Versehen gäben
- Vor allem sollten wir nicht vergessen, dass die Funktion IndicatorCounted() in Expert Advisors nicht funktioniert!
- Wir können auch nicht von den benutzerdefinierten Arrays im Initialisierungsblock um die Indikators Arrays ändern!
Also für eine vollständige Speicherung des Indikatorcodes brauchen wir vor allem ein Analog der Funktion IndicatorCounted() zu erstellen und irgendwie die Analoge der Indikatorpuffer in einem Expert Advisor zu emulieren. Leider ist es nicht möglich, unter Verwendung der Standardfunktionen direkt due Indikatorpuffer in einem EA zu emulieren. Inzwischen gibt es keine Analoge von SetIndexBuffer() und IndicatorBuffers() für Expert Advisors! Also muss dieses Problem anderes gelöst werden. Zum Glück gibt es dafür genug Möglichkeiten in MQL4.
Emulation der Indikatorpuffer in einem Expert Advisor
Zunächst lassen Sie uns in Details die Prozesse betrachten, die in Indikatorpuffern laufen.
- Die Werte, die der Variablen der Indikatorpuffer zugeordnet werden, werden nicht zwischen den Loops verloren, solange der Indikator zum Chart hinzugefügt bleibt und solange der Terminal arbeitet.
- Wenn das nullwertige Bar (das neueste) auf dem Chart geändert wird, werden alle Elemente des Indikatorpuffers verschoben.
- Wenn ein neues Bar kommt, wird sich der Wert der Variable limit von 1 um 2 im Indikator ändern!, und alle Pufferelemente durch 1 verschoben, das heißt, das nullwertiges Element wird dem ersten, das erste wird dem zweiten und so weiter.
- Natürlich werden sich die Abmessungen der Indikatorpuffer ändern. Wenn auf dem nächsten Tick hat sich das nullwertige Bar nicht geändert, werden alle Pufferelemente auf ihren Plätzen bleiben.
Jetzt kommt die Emulation der Indikatorpuffer. Zu diesem Zweck werden wir die folgenden MQL4 Standardfunktionen verwenden: ArraySize(), ArrayResize() und ArraySetAsSeries(). Der Emulationscode der Indikatorpuffer ist ganz einfach und das Prinzip seiner Operation kann man so beschrieben: Wenn das nullwertige Bar sich ändert, wird die direkte Reihenfolge der Elementen-Definition in Puffern wiederhergestellt, es werden durch die Funktion ArrayResize() neue Einheiten in den Puffern von neuen Bars hinzugefügt, danach wird die umgekehrte Reihenfolge der Elemente-Definition in Puffern gesetzt und leere Einheiten erscheinen unter dem ersten emulierten Indikatorpuffer sein.
//---- Die Emulation der Indikatorpuffer int NewSize = iBars(symbol, timeframe); //---- Überprüfung der Änderung des nullwertigen Bars if(ArraySize(Ind_Buffer0) < NewSize) { //---- Stellen Sie die direkte Richtung des Indexeds in Arrays ein ArraySetAsSeries(Ind_Buffer0, false); ArraySetAsSeries(Ind_Buffer1, false); ArraySetAsSeries(Ind_Buffer2, false); //---- Ändern Sie die Größe der emulierten Indikatorpuffer ArrayResize(Ind_Buffer0, NewSize); ArrayResize(Ind_Buffer1, NewSize); ArrayResize(Ind_Buffer2, NewSize); //---- Stellen Sie die Rückwärtsrichtung des Indexed in Arrays ein ArraySetAsSeries(Ind_Buffer0, true); ArraySetAsSeries(Ind_Buffer1, true); ArraySetAsSeries(Ind_Buffer2, true); } //----
Übrigens kann diese Emulationsmethode der Indikatorpuffer auch in Indikatoren verwendet werden, wenn acht Indikatorpuffer für die Zwischenberechnungen eines Indikators nicht ausreichend sind. Die Beispiele dafür sind in den beigefügten Dateien SMI.mq4 und SMI_New.mq4.
Die Ersetzung der Funktion IndicatorCounted().
Lassen Sie uns nun die Emulation der Funktion IndicatorCounted() analysieren. Diese Funktion liefert die Anzahl des aktuellen Chart-Bars, die nach dem letzten Aufruf des Indikators unverändert geblieben sind. Oder wir können es mit anderen Worten so sagen. Diese Funktion liefert die Anzahl des aktuellen Chart-Bars, die im Client-Terminal auf dem vorherigen Tick zur Verfügung standen! Damit die Werte absolut identisch von der Anzahl der resultierenden Bars wären, müssen wir eins daraus subtrahieren. So können wir diese Funktion einfach durch eine statische ganzzahlige Variable ersetzten, die durch den Wert einer vorbestimmten Variable Bars-1 initialisiert wird, nachdem ein Wert von ihr empfangen wird. Danach wird das Schema des Indikators so aussehen:
//+------------------------------------------------------------------+ //| NewIndicatorPlan1.mqh | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ //---- Eingabeparameter des Indikators extern int period0 = 15; extern int period1 = 15; extern int period2 = 15; //---- Indikatorpuffers double Ind_Buffer0[]; double Ind_Buffer1[]; double Ind_Buffer2[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- Das Ende des Initialisierens return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { //---- Die Überprüfung der Anzahl der Bars, damit sie ausreichend für die Berechnung wären if(Bars < period0 + period1 + period2) return(0); //---- Die Emulation der Indikatorpuffer if(ArraySize(Ind_Buffer0) < Bars) { ArraySetAsSeries(Ind_Buffer0, false); ArraySetAsSeries(Ind_Buffer1, false); ArraySetAsSeries(Ind_Buffer2, false); //---- ArrayResize(Ind_Buffer0, Bars); ArrayResize(Ind_Buffer1, Bars); ArrayResize(Ind_Buffer2, Bars); //---- ArraySetAsSeries(Ind_Buffer0, true); ArraySetAsSeries(Ind_Buffer1, true); ArraySetAsSeries(Ind_Buffer2, true); } //----+ Eingabe der ganzen statistischen Speichervariable static int IndCounted; //----+ Eingabe der Variablen mit Gleitkomma double Resalt0, Resalt1, Resalt2; //----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars int limit, MaxBar, bar, counted_bars = IndCounted; //---- Überprüfung auf mögliche Fehler if(counted_bars < 0) return(-1); //---- das letzte berechnete Bar muss neuberechnet werden if(counted_bars > 0) counted_bars--; //----+ Die Speicherung der Anzahl aller Chart-Bars IndCounted = Bars - 1; //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung, // der neuen Bars beginnt limit = Bars - counted_bars - 1; //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung, // aller Bars beginnt MaxBar = Bars - 1 - (period0 + period1 + period2); //---- Initialisieren der Null if(limit > MaxBar) { limit = MaxBar; for(bar = Bars - 1; bar >= 0; bar--) { Ind_Buffer0[bar] = 0.0; Ind_Buffer1[bar] = 0.0; Ind_Buffer2[bar] = 0.0; } } //----+ Die erste Loop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt1 auf der Grundlage der // externen Variable period1 Ind_Buffer1[bar] = Resalt1; } //----+ Die zweite Loop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt2 // auf der Grundlage des Wertes vom Puffer Ind_Buffer1[] und der externen Variable period2 Ind_Buffer2[bar] = Resalt2; } //----+ Die Hauptloop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt0 // auf der Grundlage des Wertes vom Puffer Ind_Buffer2[] und der externen Variable period0 Ind_Buffer0[bar] = Resalt0; } return(0); } //+------------------------------------------------------------------+
Die weitere Transformation des Indikatorcodes und das Schema seiner Struktur
Die Aufgabe der Verarbeitung von Daten aus anderen Timeframes wird auch leicht gelöst. Ersetzen wir im Indikator die vorbestimmten Variablen Bars um die Zeitreihenanordnungen
iBars(string symbol, int timeframe);
NULL - на string symbol;, 0(in Zeitreihenanordnungen) - um int timeframe;, Close[bar] - на
iClose(string symbol, int timeframe, bar);
und so weiter.
Lassen Sie uns nun die Zeilen des Indikators analysieren:
//---- Überprüfung auf mögliche Fehler if(counted_bars < 0) return(-1); //---- das letzte berechnete Bar muss neuberechnet werden if(counted_bars > 0) counted_bars--;
Die angebotene Ersetzung der Funktion IndicatorCounted() der Indikatorstruktur der Variable counted_bars wird in unserer Variante nie kleiner als Null sein. Also die Zeilen:
//---- Überprüfung auf mögliche Fehler if(counted_bars < 0) return(-1);
im EA-Code kann man löschen. Mit den nächsten beiden Zeilen:
//---- das letzte berechnete Bar muss neuberechnet werden if(counted_bars > 0) counted_bars--;
Es ist das Gleiche. Sie sollten gelöscht werden, denn sie verlangsamen nur die Arbeit des Expertes durch die unnötigen Neuberechnungen des ersten Bars und diese Prüfung ist im EA-Code absolut nutzlos. Danach wird der endgültige Code im EA für die Übertragung so aussehen:
//+------------------------------------------------------------------+ //| NewIndicatorPlan2.mqh | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ //---- Eingabeparameter des Indikators extern int period0 = 15; extern int period1 = 15; extern int period2 = 15; //---- Indikatorpuffers double Ind_Buffer0[]; double Ind_Buffer1[]; double Ind_Buffer2[]; //---- Veröffentlichen der Variablen für die Auswahl des Charts string symbol; int timeframe; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- Die Auswahl des Charts für die Berechnung des Indikators symbol = Symbol();//Initialisieren der Variable symbol; timeframe =240;//Initialisieren der Variable timeframe; //---- Das Ende des Initialisierens return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { // Die Erhaltung der Anzahl aller Chart-Bars int IBARS = iBars(symbol, timeframe); //---- Die Überprüfung der Anzahl der Bars, damit sie ausreichend für die Berechnung wären if(IBARS < period0 + period1 + period2) return(0); // Die Emulation der Indikatorpuffer if(ArraySize(Ind_Buffer0) < IBARS) { ArraySetAsSeries(Ind_Buffer0, false); ArraySetAsSeries(Ind_Buffer1, false); ArraySetAsSeries(Ind_Buffer2, false); //---- ArrayResize(Ind_Buffer0, IBARS); ArrayResize(Ind_Buffer1, IBARS); ArrayResize(Ind_Buffer2, IBARS); //---- ArraySetAsSeries(Ind_Buffer0, true); ArraySetAsSeries(Ind_Buffer1, true); ArraySetAsSeries(Ind_Buffer2, true); } // Eingabe der ganzen statistischen Speichervariable static int IndCounted; //----+ Eingabe der Variablen mit Gleitkomma double Resalt0, Resalt1, Resalt2; //----+ Eingabe der ganzen Variablen und erhalten dadurch bereits berechneten Bars int limit, MaxBar, bar, counted_bars = IndCounted; //----+ Die Speicherung der Anzahl aller Chart-Bars IndCounted = IBARS - 1; //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung, // der neuen Bars beginnt limit = IBARS - counted_bars - 1; //---- Die Bestimmung der Nummer des letzten Bars, von dem die Neuberechnung, // aller Bars beginnt MaxBar = IBARS - 1 - (period0 + period1 + period2); //---- Initialisieren der Null if(limit > MaxBar) { limit = MaxBar; for(bar = IBARS - 1; bar >= 0; bar--) { Ind_Buffer0[bar] = 0.0; Ind_Buffer1[bar] = 0.0; Ind_Buffer2[bar] = 0.0; } } //----+ Die erste Loop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt1 auf der Grundlage der externen //Variable period1 Ind_Buffer1[bar] = Resalt1; } //----+ Die zweite Loop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt2 // auf der Grundlage des Wertes vom Puffer Ind_Buffer1[] und der externen Variable period2 Ind_Buffer2[bar] = Resalt2; } //----+ Die Hauptloop der Berechnung des Indikators for(bar = limit; bar >= 0; bar--) { // Hier ist der Berechnungscode der Variable Resalt0 // auf der Grundlage des Wertes vom Puffer Ind_Buffer2[] und der externen Variable period0 Ind_Buffer0[bar] = Resalt0; } return(0); } //+------------------------------------------------------------------+Hier sollten wir einen Moment berücksichtigen. Es gibt Indikatoren, die bei der mehrmaligen Neuberechnung des nullwertigen Bars die Werte einiger Variablen speichern, welche auf dem ersten Bar am Anfang der Berechnungsloops sind, um den Code in den Ausgangszustand zu liefern (Artikel). Im Expert Advisor sollte es nach der Löschung der letzten 2 Zeilen nicht auf dem ersten Bar gespeichert werden, sondern auf dem nullwertigen Bar. Normalerweise enthalten solche Indikatoren am Anfang der Berechnungsloops des Indikators die folgenden Code-Fragmente:
// Speicherung des Wertes der Variablen if(bar == 1) if(((limit == 1) && (time == Time[2])) || (limit > 1)) { time = Time[2]; // Diese Variablen interessieren uns nicht PRICE = price; TREND = trend; RESALT = Resalt; } //+------------------------------------------------------------------+
time = Time[1];
durch
time = iTime(symbol, timeframe, 1);
Als Ergebnis haben wir das folgende geänderte Fragment:
// Speicherung des Wertes der Variablen if(bar == 0) if(((limit == 0) && (time == iTime(symbol, timeframe, 1))) || (limit > 0)) { time = iTime(symbol, timeframe, 1); PRICE = price; TREND = trend; RESALT = Resalt; } //+------------------------------------------------------------------+
Im Indikatorcode können auch von mir entwickelten Funktionen der Glättung wie XXXSeries() sein. Um die Fragmente mit solchen Funktionen im EA-Code zu verwenden, sollten diese Funktionen durch die EA-Analoge ersetzt werden.
Fazit
In diesem Moment ist es zweifellos, dass der angebotene Algorithmus einen Indikator-Code in einen EA-Code in dieser Form zu übertragen, ist eher umständlich und nicht optimal, aber der Zweck dieses Artikels ist nicht eine genaue Beschreibung aller Einzelheiten dieses Prozesses. Die Hauptidee dieses Artikels ist eine allgemeine Vorstellung von Indikatoren zu geben und die Analyse der allgemeinen Idee, den Code in einer maximal einfachen Form zu übertragen, und das nicht mit sekundären Details kompliziert zu machen. Ich finde, dass wir dieses Ziel erreicht haben! Im nächsten Artikel werden wir die allgemeine Struktur eines Expert Advisors und Strukturschemas der Indikatorfunktionen analysieren.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1456
![Automatisch generierte Dokumentation für den MQL5-Code](https://c.mql5.com/2/0/ava.png)
![ABC Trading im Forex](https://c.mql5.com/2/14/304_1.png)
![MQL5.community - Benutzer-Memo](https://c.mql5.com/2/0/helpButton__1.png)
![Die Realisierung der dreifarbigen Indikatoren und einige Möglichkeiten für eine maximale Vereinfachung des Indikatoren-Schreibens](https://c.mql5.com/2/14/298_1.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.