![MQL5 Cookbook: Die History der Abschlüsse und Funktions-Library zum Erhalt von Position-Eigenschaften](https://c.mql5.com/i/articles/overlay.png)
MQL5 Cookbook: Die History der Abschlüsse und Funktions-Library zum Erhalt von Position-Eigenschaften
Einleitung
Eine gute Gelegenheit, die in den vorangegangenen Beiträgen zu Position-Eigenschaften beschriebenen Informationen nochmals kurz zusammenzufassen. In diesem Beitrag werden wir einige zusätzliche Funktionen erzeugen, um die Eigenschaften zu erhalten, die man nur nach Zugriff auf die History der Abschlüsse abrufen kann. Darüber hinaus lernen wir Datenstrukturen kennen, mit deren Hilfe wir auf Position- und Symboleigenschaften auf weitaus bequemere Weise zugreifen können.
Handelssysteme, bei denen die Position-Volumen während ihres ganzen Bestehens unverändert bleiben, verlangen nicht wirklich die Arbeit mit den Funktionen, die in diesem Beitrag beschrieben werden. Doch sollten Sie in Ihrer Handelsstrategie später ein Geldverwaltungssystem implementieren und die Größe eines Position-Postens kontrollieren wollen, dann sind diese Funktionen unerlässlich.
Bevor wir beginnen, möchte ich all denjenigen Lesern, die zum ersten Mal diese Website besuchen und via eines Links auf diesen Beitrag gestoßen sind oder gerade mit dem Erlernen der MQL5-Sprache begonnen haben, folgenden Vorschlag machen: Lesen Sie bitte zuerst die vorangegangenen Beiträge dieser "MQL5 Cookbook" Beitragsreihe.
Entwicklung des Expert Advisors
Um zu sehen, wie die neuen Funktionen im Expert Advisor funktionieren, der im vorangegangenen Beitrag mit dem Titel "MQL5 Cookbook: Wie man bei der Einrichtung/Veränderung von Handelsstufen Fehler vermeidet" verändert wurde, fügen wir die Möglichkeit hinzu, das Position-Volumen erhöhen zu können, sobald ein Signal zur Eröffnung auftritt und die Position bereits vorhanden ist.
In der Position-History können mehrere Abschlüsse vorhanden sein. Falls es im Position-Volumen im Verlauf des Handels also zu Änderungen gekommen ist, dann müssen auch im aktuellen Position-Kurs Änderungen gewesen sein. Um den Kurs am ersten Eintrittspunkt herauszufinden, müssen wir daher auf die History der Abschlüsse hinsichtlich dieser bestimmten Position zugreifen können. Die folgende Abbildung veranschaulicht einen Fall, in dem eine Position nur einen Abschluss hat (Eintrittspunkt):
Abb. 1 Erster Abschluss in der Position.
Die nächste Abbildung zweigt eine Änderung im Position-Kurs nach dem zweiten Abschluss:
Abb. 2 Zweiter Abschluss in der Position.
Wie in den vorangegangenen Beiträgen gezeigt, können Sie mit Standard-Identifikatoren nur den aktuellen Position-Kurs (POSITION_PRICE_OPEN) sowie den aktuellen Kurs eines Symbols (POSITION_PRICE_CURRENT) für die die Position eröffnet ist, erhalten.
Doch in einigen Handelssystemen müssen wir auch den Abstand kennen, der vom Kurs beim ersten Eintrittspunkt abgedeckt wird, sowie auch den Kurs des letzten Abschlusses. Diese Informationen sind alle in der History der Abschlüsse/Order im Konto vorhanden. Unten steht eine Liste der Abschlüsse im Zusammenhang mit der obigen Abbildung:
Abb. 3 Die History der Abschlüsse im Konto.
Meiner Meinung nach ist die Situation nun klar und alle Ziele sind gesetzt. Kommen wir also nun zur Veränderung des in den vorangegangenen Beiträgen erwähnten Expert Advisors. Als Erstes fügen wir der Aufzählung der Position-Eigenschaften neue Identifikatoren hinzu: 0, 6, 9, 12 und 16:
//--- Enumeration of position properties enum ENUM_POSITION_PROPERTIES { P_TOTAL_DEALS = 0, P_SYMBOL = 1, P_MAGIC = 2, P_COMMENT = 3, P_SWAP = 4, P_COMMISSION = 5, P_PRICE_FIRST_DEAL= 6, P_PRICE_OPEN = 7, P_PRICE_CURRENT = 8, P_PRICE_LAST_DEAL = 9, P_PROFIT = 10, P_VOLUME = 11, P_INITIAL_VOLUME = 12, P_SL = 13, P_TP = 14, P_TIME = 15, P_DURATION = 16, P_ID = 17, P_TYPE = 18, P_ALL = 19 };
Die Anmerkungen für jede Eigenschaft erfolgen in einer Struktur, die wir uns etwas später hier ansehen werden.
Erhöhen wir auch die Anzahl der externen Parameter. Jetzt können wir nämlich angeben:
- MagicNumber - eine eindeutige ID des Expert Advisors (magische Zahl);
- Deviation - Modulation;
- VolumeIncrease - Wert um den das Position-Volumen erhöht wird;
- InfoPanel - Parameter mit dem Sie die Anzeige des Info-Panels aktivieren/deaktivieren können.
Und so wird das implementiert:
//--- External parameters of the Expert Advisor sinput long MagicNumber=777; // Magic number sinput int Deviation=10; // Slippage input int NumberOfBars=2; // Number of Bullish/Bearish bars for a Buy/Sell input double Lot=0.1; // Lot input double VolumeIncrease=0.1; // Position volume increase input double StopLoss=50; // Stop Loss input double TakeProfit=100; // Take Profit input double TrailingStop=10; // Trailing Stop input bool Reverse=true; // Position reversal sinput bool ShowInfoPanel=true; // Display of the info panel
Bitte beachten Sie die Parameter, deren Sinput-Modifikator eingerichtet wurde. Mit Hilfe dieses Modifikators können Sie die Optimierung im Strategietester deaktivieren. Denn wenn Sie ein Programm zur eigenen Verwendung entwickeln, wissen Sie in der Tat ganz genau, welche Parameter sich auf das Endergebnis auswirken werden, also können Sie sie einfach aus der Optimierung entfernen (entsprechendes Häkchen entfernen). Doch bei einer sehr großen Menge von Parametern können Sie mit dieser Methode diese Parameter visuell von anderen abtrennen, da sie grau unterlegt sind:
Abb. 4 Für die Optimierung deaktivierte Parameter sind grau unterlegt.
Ersetzen wir nun die globalen Variablen, die die Werte für Position- und Symboleigenschaften gespeichert haben durch Datenstrukturen ersetzen (struct):
//--- Position properties struct position_properties { uint total_deals; // Number of deals bool exists; // Flag of presence/absence of an open position string symbol; // Symbol long magic; // Magic number string comment; // Comment double swap; // Swap double commission; // Commission double first_deal_price; // Price of the first deal in the position double price; // Current position price double current_price; // Current price of the position symbol double last_deal_price; // Price of the last deal in the position double profit; // Profit/Loss of the position double volume; // Current position volume double initial_volume; // Initial position volume double sl; // Stop Loss of the position double tp; // Take Profit of the position datetime time; // Position opening time ulong duration; // Position duration in seconds long id; // Position identifier ENUM_POSITION_TYPE type; // Position type };
//--- Symbol properties struct symbol_properties { int digits; // Number of decimal places in the price int spread; // Spread in points int stops_level; // Stops level double point; // Point value double ask; // Ask price double bid; // Bid price double volume_min; // Minimum volume for a deal double volume_max; // Maximum volume for a deal double volume_limit; // Maximum permissible volume for a position and orders in one direction double volume_step; // Minimum volume change step for a deal double offset; // Offset from the maximum possible price for a transaction double up_level; // Upper Stop level price double down_level; // Lower Stop level price }
Um auf ein bestimmtes Element der Struktur zugreifen zu können, müssen wir nun eine Variable dieses Strukturtyps erzeugen. Dies erfolgt ganz ähnlich wie die Erzeugung eines Objekts für eine Handelsklasse, was im Beitrag mit dem Titel "MQL5 Cookbook: Position-Eigenschaften m MetaTrader 5 Strategietester analysieren" beschrieben wurde.
//--- variables for position and symbol properties
position_properties pos;
symbol_properties symb;
Auf diese Elemente können Sie auf die gleiche Art und Weise zugreifen, wie Sie mit Klassenmethoden umgehen. Mit anderen Worten: Es genügt nach dem Namen einer Strukturvariablen einen Punkt zu setzen, damit die Liste der in dieser angegebenen Struktur enthaltenen Elemente angezeigt wird. Das ist ist ziemlich bequem. Sollten für die Felder der Struktur (wo wie in unserm Beispiel) einzeilige Anmerkungen vorhanden sein, werden diese in einem Tooltip auf der rechten Seite angezeigt.
Abb. 5 Liste der Strukturfelder.
Noch ein wichtiger Punkt. Bei der Veränderung des Expert Advisors haben wir buchstäblich all seine globalen Variablen, die in vielen Funktionen verwendet werden, geändert, dher müssen wir sie jetzt durch die entsprechenden Strukturfeldern für Symbol- und Position-Eigenschaften ersetzen. So wurde z.B. die globale Variable pos_open, die zur Speicherung des Markers für geöffnete Position vorhanden/nicht vorhanden verwendet wurde, durch das Feld exists imposition_properties Strukturtyp ersetzt. Daher muss überall wo die Variable pos_open verwendet wurde, diese nun durch pos.exists ersetzt werden.
Wenn Sie dies per Hand machen müssen, dann dauert das extrem lange und ist sehr mühsam. Daher ist es besser diese Aufgabe mit Hilfe der MetaEditor Features: Suchen und Ersetzen -> Ersetzen im Menü Bearbeiten- oder der Tastenkombination Strg+H zu automatisieren:
Abb. 6 Den Text suchen und ersetzen.
Wir müssen alle globalen Variablen für Position- und Symboleigenschaften suchen und ersetzen, um später, nachdem wir die Datei erstellt haben, einen Test laufen lassen zu können. Werden keine Fehler gemeldet, haben wir alles richtig gemacht. Damit dieser Beitrag nicht zu lang wird, stelle ich den Code hier nicht zur Verfügung. Denn ein einsatzbereiter Quellcode ist am Ende dieses Beitrags sowieso für eine Download angehängt.
Da wir jetzt das Problem mit den Variablen geregelt haben, gehen wir zur Änderung der bestehenden Funktionen und zur Erzeugung neuer weiter.
In den externen Parametern können Sie jetzt die magische Zahl und die Modulation in Punkten einrichten. Daher müssen wir auch die entsprechenden Veränderungen im Code des Expert Advisors vornehmen. Wir erzeugen eine benutzerdefinierte Hilfsfunktion OpenPosition(), in der diese Eigenschaften mit Hilfe der Funktionen der CTrade Klasse vor dem Abschicken einer Order für eine Position-Eröffnung eingerichtet werden.
//+------------------------------------------------------------------+ //| Opening a position | //+------------------------------------------------------------------+ void OpenPosition(double lot, ENUM_ORDER_TYPE order_type, double price, double sl, double tp, string comment) { trade.SetExpertMagicNumber(MagicNumber); // Set the magic number in the trading structure trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); // Set the slippage in points //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) { Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } }
Im Code der Haupt-Handelsfunktion des Expert Advisors - TradingBlock() - müssen wir nur einige kleine Änderungen vornehmen. Unten steht der Teil des Codes der Funktion, der geändert wurde:
//--- If there is no position if(!pos.exists) { //--- Adjust the volume lot=CalculateLot(Lot); //--- Open a position OpenPosition(lot,order_type,position_open_price,sl,tp,comment); } //--- If there is a position else { //--- Get the position type GetPositionProperties(P_TYPE); //--- If the position is opposite to the signal and the position reversal is enabled if(pos.type==opposite_position_type && Reverse) { //--- Get the position volume GetPositionProperties(P_VOLUME); //--- Adjust the volume lot=pos.volume+CalculateLot(Lot); //--- Reverse the position OpenPosition(lot,order_type,position_open_price,sl,tp,comment); return; } //--- If the signal is in the direction of the position and the volume increase is enabled, increase the position volume if(!(pos.type==opposite_position_type) && VolumeIncrease>0) { //--- Get the Stop Loss of the current position GetPositionProperties(P_SL); //--- Get the Take Profit of the current position GetPositionProperties(P_TP); //--- Adjust the volume lot=CalculateLot(Increase); //--- Increase the position volume OpenPosition(lot,order_type,position_open_price,pos.sl,pos.tp,comment); return; }
Der obige Code ist um den Block erweitert worden, in dem die Richtung der aktuellen Position vor dem Hintergrund der Richtung des Signals geprüft wird. Stimmen beide Richtungen überein und ist in den externen Parametern eine Erhöhung des Position-Volumens aktiviert (der Wert des VolumeIncrease Parameters ist > 0), prüfen und passen wir einen gegebenen Posten an und schicken die entsprechende Order ab. Um eine Order zur Eröffnung oder Umkehrung einer Position oder zur Erhöhung des Position-Volumens abzuschicken, müssen sie nur eine Codezeile schreiben.
Erzeugen wir nun Funktionen, um Position-Eigenschaften aus History der Abschlüsse zu erhalten. Wir beginnen dabei mit der CurrentPositionTotalDeals() Funktion, die die Anzahl der Abschlüsse in der aktuellen Position liefert:
//+------------------------------------------------------------------+ //| Returning the number of deals in the current position | //+------------------------------------------------------------------+ uint CurrentPositionTotalDeals() { int total =0; // Total deals in the selected history list int count =0; // Counter of deals by the position symbol string deal_symbol =""; // symbol of the deal //--- If the position history is obtained if(HistorySelect(pos.time,TimeCurrent())) { //--- Get the number of deals in the obtained list total=HistoryDealsTotal(); //--- Iterate over all the deals in the obtained list for(int i=0; i<total; i++) { //--- Get the symbol of the deal deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL); //--- If the symbol of the deal and the current symbol are the same, increase the counter if(deal_symbol==_Symbol) count++; } } //--- return(count); }
Der obige Code steht mit reichlich detaillierten Anmerkungen zur Verfügung. Doch zuvor sollten wir kurz darauf eingehen, wie die History ausgewählt wird. In unserem Fall haben wir mit Hilfe der HistorySelect() Funktion die Liste vom Punkt der Eröffnung der aktuellen Position bekommen, bestimmt durch die Eröffnungszeit bis zum aktuellen Zeitpunkt Nachdem die History ausgewählt worden ist, können wir mit Hilfe der HistoryDealsTotal() Funktion die Anzahl der Abschlüsse in der Liste finden. Der Rest sollte anhand der Anmerkungen klar sein.
Mit Hilfe der HistorySelectByPosition() Funktion kann die History einer bestimmten Position auch via ihres Identifikators ausgewählt werden. Hier müssen Sie allerdings berücksichtigen, dass der Position-Identifikator derselbe bleibt, wenn die Position umgekehrt wird, da dies im Expert Advisor manchmal vorkommt. Bei einer solchen Umkehr verändert sich die Zeit der Eröffnung hingegen nicht, und daher ist diese Variante leichter zu implementieren. Wenn Sie allerdings mit der History der Abschlüsse arbeiten müssen, die nicht nur für die aktuell offene Position gilt, dann müssen Sie mit Identifikatoren arbeiten. Zur History der Abschlüsse kommen wir in späteren Beiträgen erneut.
Machen wir weiter, und erzeugen die Funktion CurrentPositionFirstDealPrice(), die den Kurs des ersten Abschlusses in der Position liefert, d.h. den Kurs des Abschlusses zu dem die Position eröffnet wurde.
//+------------------------------------------------------------------+ //| Returning the price of the first deal in the current position | //+------------------------------------------------------------------+ double CurrentPositionFirstDealPrice() { int total =0; // Total deals in the selected history list string deal_symbol =""; // symbol of the deal double deal_price =0.0; // Price of the deal datetime deal_time =NULL; // Time of the deal //--- If the position history is obtained if(HistorySelect(pos.time,TimeCurrent())) { //--- Get the number of deals in the obtained list total=HistoryDealsTotal(); //--- Iterate over all the deals in the obtained list for(int i=0; i<total; i++) { //--- Get the price of the deal deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE); //--- Get the symbol of the deal deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL); //--- Get the time of the deal deal_time=(datetime)HistoryDealGetInteger(HistoryDealGetTicket(i),DEAL_TIME); //--- If the time of the deal equals the position opening time, // and if the symbol of the deal and the current symbol are the same, exit the loop if(deal_time==pos.time && deal_symbol==_Symbol) break; } } //--- return(deal_price); }
Das Prinzip hier ist das gleiche wie in der vorangegangenen Funktion. Wir bekommen die History vom Punkt der Position-Eröffnung und prüfen dann bei jeder Wiederholung die Uhrzeit des Abschlusses und die Eröffnungszeit der Position. Zusammen mit dem Kurs des Abschlusses, erhalten wir auch noch den Symbolnamen und den Zeitpunkt des Abschlusses. Der allererste Abschluss wird dort ermittelt, wo der Zeitpunkt des Abschlusses mit der Eröffnungszeit der Position zusammenfällt. Da ja sein Kurs bereits der entsprechenden Variable zugewiesen wurde, müssen wir den Wert nur noch liefern.
Machen wir also weiter. Manchmal müssen Sie vielleicht den Kurs des letzten Abschlusses in der aktuellen Position haben. Und zu diesem Zweck erzeugen wir eine CurrentPositionLastDealPrice() Funktion:
//+------------------------------------------------------------------+ //| Returning the price of the last deal in the current position | //+------------------------------------------------------------------+ double CurrentPositionLastDealPrice() { int total =0; // Total deals in the selected history list string deal_symbol =""; // Symbol of the deal double deal_price =0.0; // Price //--- If the position history is obtained if(HistorySelect(pos.time,TimeCurrent())) { //--- Get the number of deals in the obtained list total=HistoryDealsTotal(); //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal for(int i=total-1; i>=0; i--) { //--- Get the price of the deal deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE); //--- Get the symbol of the deal deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL); //--- If the symbol of the deal and the current symbol are the same, exit the loop if(deal_symbol==_Symbol) break; } } //--- return(deal_price); }
Diesmal hat die Zeitschleife beim letzten Abschluss in der Liste begonnen. Es kommt auch oft vor, dass der erforderliche Abschluss bei der ersten Wiederholung der Schleife identifiziert wird. Bevor Sie also auf mehreren Symbolen handeln, fährt die Schleife fort, bis das Symbol des Abschlusses mit dem aktuellen Symbol übereinstimmt.
Das aktuelle Position-Volumen erhält man mit Hilfe des POSITION_VOLUME Standard-Identifikators. Um das ursprüngliche Position-Volumen herauszufinden (das Volumen des ersten Abschlusses), erzeugen wir dazu eine CurrentPositionInitialVolume() Funktion:
//+------------------------------------------------------------------+ //| Returning the initial volume of the current position | //+------------------------------------------------------------------+ double CurrentPositionInitialVolume() { int total =0; // Total deals in the selected history list ulong ticket =0; // Ticket of the deal ENUM_DEAL_ENTRY deal_entry =WRONG_VALUE; // Position modification method bool inout =false; // Flag of position reversal double sum_volume =0.0; // Counter of the aggregate volume of all deals, except for the first one double deal_volume =0.0; // Volume of the deal string deal_symbol =""; // Symbol of the deal datetime deal_time =NULL; // Deal execution time //--- If the position history is obtained if(HistorySelect(pos.time,TimeCurrent())) { //--- Get the number of deals in the obtained list total=HistoryDealsTotal(); //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal for(int i=total-1; i>=0; i--) { //--- If the order ticket by its position is obtained, then... if((ticket=HistoryDealGetTicket(i))>0) { //--- Get the volume of the deal deal_volume=HistoryDealGetDouble(ticket,DEAL_VOLUME); //--- Get the position modification method deal_entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY); //--- Get the deal execution time deal_time=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME); //--- Get the symbol of the deal deal_symbol=HistoryDealGetString(ticket,DEAL_SYMBOL); //--- When the deal execution time is less than or equal to the position opening time, exit the loop if(deal_time<=pos.time) break; //--- otherwise calculate the aggregate volume of deals by the position symbol, except for the first one if(deal_symbol==_Symbol) sum_volume+=deal_volume; } } } //--- If the position modification method is a reversal if(deal_entry==DEAL_ENTRY_INOUT) { //--- If the position volume has been increased/decreased // I.e. the number of deals is more than one if(fabs(sum_volume)>0) { //--- Current volume minus the volume of all deals except for the first one double result=pos.volume-sum_volume; //--- If the resulting value is greater than zero, return the result, otherwise return the current position volume deal_volume=result>0 ? result : pos.volume; } //--- If there are no more deals, other than the entry, if(sum_volume==0) deal_volume=pos.volume; // return the current position volume } //--- Return the initial position volume return(NormalizeDouble(deal_volume,2)); }
Diese Funktion erwies sich leider als komplexer als die vorangegangenen. Ich habe nämlich versucht, alle möglichen Situationen zu berücksichtigen, die zu einem falschen wert führen könnten. Doch nach einem sorgfältigen Test konnte keine Probleme festgestellt werden. Die detaillierten Anmerkungen des Codes sollten Ihnen begreiflich machen, was ich meine.
Es empfiehlt sich auch, eine Funktion zu haben, die die Dauer der Position liefert. Diese ordnen wir so an, dass der Anwender das passende Format des gelieferten Wertes selbst auswählen kann: Sekunden, Minuten, Stunden oder Tage. Deswegen erzeugen wir nun eine weitere Aufzählung:
//--- Position duration enum ENUM_POSITION_DURATION { DAYS = 0, // Days HOURS = 1, // Hours MINUTES = 2, // Minutes SECONDS = 3 // Seconds };
Unten steht der Code für die CurrentPositionDuration() Funktion, die für alle relevanten Berechnungen verantwortlich ist:
//+------------------------------------------------------------------+ //| Returning the duration of the current position | //+------------------------------------------------------------------+ ulong CurrentPositionDuration(ENUM_POSITION_DURATION mode) { ulong result=0; // End result ulong seconds=0; // Number of seconds //--- Calculate the position duration in seconds seconds=TimeCurrent()-pos.time; //--- switch(mode) { case DAYS : result=seconds/(60*60*24); break; // Calculate the number of days case HOURS : result=seconds/(60*60); break; // Calculate the number of hours case MINUTES : result=seconds/60; break; // Calculate the number of minutes case SECONDS : result=seconds; break; // No calculations (number of seconds) //--- default : Print(__FUNCTION__,"(): Unknown duration mode passed!"); return(0); } //--- Return result return(result); }
Erzeugen wir nun eine CurrentPositionDurationToString() Funktion für das Info-Panel, wo die Position-Eigenschaften angezeigt werden. Diese Funktion wandelt die Dauer der Position in Sekunden in ein Format um, das vom Anwender leicht verstanden werden kann. Die Anzahl der Sekunden wird an die Funktion übertragen und die Funktion ihrerseits liefert dann einen String mit der Dauer der Position in Tagen, Stunden, Minuten und Sekunden:
//+------------------------------------------------------------------+ //| Converting the position duration to a string | //+------------------------------------------------------------------+ string CurrentPositionDurationToString(ulong time) { //--- A dash if there is no position string result="-"; //--- If the position exists if(pos.exists) { //--- Variables for calculation results ulong days=0; ulong hours=0; ulong minutes=0; ulong seconds=0; //--- seconds=time%60; time/=60; //--- minutes=time%60; time/=60; //--- hours=time%24; time/=24; //--- days=time; //--- Generate a string in the specified format DD:HH:MM:SS result=StringFormat("%02u d: %02u h : %02u m : %02u s",days,hours,minutes,seconds); } //--- Return result return(result); }
Jetzt ist alles eingerichtet und fertig. Die Codes der GetPositionProperties() und GetPropertyValue() Funktion, die in Übereinstimmung mit allen zuvor vorgenommenen Änderungen verändert werden müssen, biete ich hier nicht an. Wenn Sie alle vorangegangenen Beiträge dieser Reihe lesen, sollten Sie diese Änderungen ohne große Probleme selbst vornehmen können. Für alle Fälle ist die Datei mit dem Quellcode jedoch am Ende des Beitrags angehängt.
Als Ergebnis sollte das Info-Panel jetzt, wie unten gezeigt, erscheinen:
Abb. 7 Veranschaulichung aller Position-Eigenschaften auf dem Info-Panel.
Jetzt haben wir also die Funktions-Library, um die Position-Eigenschaften zu bekommen. Wahrscheinlich arbeiten wir in den folgenden Beiträgen, wann und wie erforderlich, weiter an ihnen.
Optimierung von Parametern und Testen des Expert Advisors
Versuchen wir mal, quasi als Experiment, die Parameter des Expert Advisors zu optimieren. Zwar ist das, was wir derzeit vor uns haben noch weit von einem voll funktionsfähigen Handelssystem entfernt, doch die Ergebnisse, die wir erhalten werden, öffnen uns die Augen in Bezug auf einige Punkte und bringen uns mehr Erfahrung als Entwickler von Handelssystemen.
Die Einstellungen des Strategietesters machen wir, wie unten gezeigt:
Abb. 8 Einstellungen des Strategietesters zur Optimierung von Parametern.
Die Einstellungen der externen Parameter des Expert Advisors sollten folgendermaßen sein:
Abb. 9 Einstellungen der Expert Advisor-Parameter zur Optimierung.
Im Anschluss an die Optimierung, sortieren wir die erhaltenen Ergebnisse nach dem maximalen Rückflussfaktor
Abb. 10 Ergebnisse sortiert nach dem maximalen Rückflussfaktor.
Testen wir nun das alleroberste Parameter-Set, mit einem Rückflussfaktor-Wert von = 4,07. Selbst angesichts der Tatsache, dass die Optimierung für EURUSD durchgeführt worden ist, erkennen wir klar die positiven Ergebnisse für viele Symbole:
Ergebnisse für EURUSD:
Abb. 11 Ergebnisse für.
Ergebnisse für AUDUSD:
Abb. 12 Ergebnisse für AUDUSD.
Ergebnisse für NZDUSD:
Abb. 13 Ergebnisse für NZDUSD.
Fazit
Buchstäblich jede Idee kann entwickelt und verbessert werden. Jedes Handelssystem sollte erst sorgfältig getestet werden, bevor man es als fehlerhaft zurückweist. In den folgenden Beiträgen werden wir uns mit verschiedenen Mechanismen und Schemata beschäftigen, die bei der individuellen Konfiguration und Anpassung von fast jedem Handelssystem eine sehr positive Rolle spielen.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/644
![MQL5 Cookbook: Wie man bei der Einrichtung/Änderung von Handelsstufen Fehler vermeidet](https://c.mql5.com/2/0/avatar1.png)
![MQL5 Cookbook: Handelsbedingungen mit Hilfe von Indikatoren in Experts Advisors einrichten](https://c.mql5.com/2/0/Avatar__1.png)
![MQL5 Cookbook: Position-Eigenschaften im MetaTrader 5 Strategietester analysieren](https://c.mql5.com/2/0/Avatar_Recipes_tester.png)
![Der ZigZag-Indikator: Frischer Ansatz und Neue Lösungen](https://c.mql5.com/2/0/avatar2.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.