English Русский 中文 Español 日本語 Português 한국어 Français Italiano Türkçe
MQL5 Cookbook: Position-Eigenschaften im MetaTrader 5 Strategietester analysieren

MQL5 Cookbook: Position-Eigenschaften im MetaTrader 5 Strategietester analysieren

MetaTrader 5Beispiele | 27 Juni 2016, 15:44
1 044 0
Anatoli Kazharski
Anatoli Kazharski

Einleitung

In diesem Beitrag verändern wir den im vorangegangenen Beitrag "MQL5 Cookbook: Position-Eigenschaften auf dem Angepassten Info-Panel" erzeugten Expert Advisor und beschäftigen uns mit folgenden Themen:

  • Nach neuen Bar-Ereignissen auf dem aktuellen Symbol suchen;
  • Daten von Bars bekommen
  • Eine Handelsklasse der Standard-Library in eine Datei aufnehmen;
  • Eine Suchfunktion für Handelssignale erzeugen;
  • Eine Funktion zur Ausführung von Handelsoperationen erzeugen;;
  • Handelsereignisse in der OnTrade() Funktion festlegen.

Eigentlich verdient jedes dieser Themen einen eigenen Beitrag, doch meiner Meinung nach würde dadurch das Verstehen und Lernen der Sprache nur noch komplizierter werden.

Ich werde Ihnen anhand von sehr einfachen Beispielen zu zeigen versuchen, wie diese Features implementiert werden können. Mit anderen Worten: Die Implementierung jede der oben aufgezählten Aufgaben passt buchstäblich in eine einfache und klare Funktion. Wenn wir in den weiteren Beiträgen dieser Reihe dann eine gewisse Vorstellung erhalten haben, machen wir diese Funktionen nach und nach komplexer, je nach und im Umfang der anstehenden Aufgabe.

Kopieren wir also zunächst den Expert Advisor aus dem vorangegangenen Beitrag, da wir all seine Funktionen brauchen.


Einen Expert Advisor entwickeln

Wir beginnen damit, die CTrade Klasse aus der Standard-Library in unsere Datei aufzunehmen. Diese Klasse besitzt alle zur Ausführung von Handelsoperationen notwendigen Funktionen. Als Anfang können wir sie leicht nutzen, ohne uns ihr Innenleben anzusehen. Und genauso machen wir's erst einmal auch.

Um die Klasse mit aufzunehmen, müssen wir folgendes schreiben:

//--- Include a class of the Standard Library
#include <Trade/Trade.mqh>

Sie können diese Code ganz an den Anfang der Datei platzieren, damit Sie ihn später leichter wieder finden, z.B. nach der #define Direktive. Die #include Anmerkung gibt an, dass dieTrade.mqh Datei aus <MetaTrader 5 terminal directory>\MQL5\Include\Trade\ geholt werden muss. Auf die gleiche Weise kann jede andere Datei, die Funktionen erhält, mit aufgenommen werden. Das ist insbesondere hilfreich, wenn die Masse des Projektcodes immer größer wird und eine Navigation zunehmend schwieriger wird.

Um Zugriff auf alle Funktionen der Klasse zu haben, müssen wir jetzt eine Instanz der Klasse erzeugen. Dies geschieht, indem man den Namen der Instanz nach dem Namen der Klasse schreibt:

//--- Load the class
CTrade trade;

In unserer Version des Expert Advisors verwenden wir nur von alle in der CTrade Klasse zur Verfügung stehenden Funktionen nur eine Handelsfunktion, nämlich die PositionOpen() Funktion mit deren Hilfe eine Position geöffnet wird. Mit dieser Funktion kann auch eine bestehende offene Position umgekehrt werden. Wie diese Funktion von der Klasse aus aufgerufen werden kann, erfahren Sie später in diesem Beitrag, wenn wir eine Funktion erzeugen, die für die Ausführung von Handelsoperationen verantwortlich ist.

Zudem müssen wir zwei dynamische Arrays in globalem Umfang hinzufügen. Diese Arrays werden Bar-Werte aufnehmen.

//--- Price data arrays
double               close_price[]; // Close (closing prices of the bar)
double               open_price[];  // Open (opening prices of the bar)

Als Nächstes erzeugen wir eine CheckNewBar() Funktion mit deren Hilfe das Programm nach neuen Bar-Ereignissen sucht, das Handelsoperationen nur auf abgeschlossenen Bars ausgeführt werden.

Der Code für CheckNewBar() Funktion samt detailliert Anmerkungen steht unten:

//+------------------------------------------------------------------+
//| CHECKING FOR THE NEW BAR                                         |
//+------------------------------------------------------------------+
bool CheckNewBar()
  {
//--- Variable for storing the opening time of the current bar
   static datetime new_bar=NULL;
//--- Array for getting the opening time of the current bar
   static datetime time_last_bar[1]={0};
//--- Get the opening time of the current bar
//    If an error occurred when getting the time, print the relevant message
   if(CopyTime(_Symbol,Period(),0,1,time_last_bar)==-1)
     { Print(__FUNCTION__,": Error copying the opening time of the bar: "+IntegerToString(GetLastError())+""); }
//--- If this is a first function call
   if(new_bar==NULL)
     {
      // Set the time
      new_bar=time_last_bar[0];
      Print(__FUNCTION__,": Initialization ["+_Symbol+"][TF: "+TimeframeToString(Period())+"]["
            +TimeToString(time_last_bar[0],TIME_DATE|TIME_MINUTES|TIME_SECONDS)+"]");
      return(false); // Return false and exit 
     }
//--- If the time is different
   if(new_bar!=time_last_bar[0])
     {
      new_bar=time_last_bar[0]; // Set the time and exit 
      return(true); // Store the time and return true
     }
//--- If we have reached this line, then the bar is not new, return false
   return(false);
  }

Wie Sie im oben stehenden Code sehen können, liefert die CheckNewBar() Funktion bei einem neuen Bar 'true' und 'false', wenn es noch keinen neuen Bar gibt. Auf diese Weise können Sie die Situation beim Handeln/Testen kontrollieren und nur Handelsoperationen auf abgeschlossen Bars durchführen.

Ganz am Anfang der Funktion, deklarieren wir eine statische Variable und ein statisches Array des Typs datetime. Statische lokale Variablen behalten ihre Werte, selbst wenn man die Funktion verlassen hat. Bei jedem späteren Funktionsaufruf besitzen solche statischen Variablen die Werte, die sie beim vorherigen Aufruf der Funktion angenommen haben.

Das Weiteren möchte ich explizit auf die CopyTime() Funktion hinweisen. Mit ihr erhalten wie die Uhrzeit des letzten Bars im time_last_bar Array. Vergessen Sie nicht, sich die Funktionssyntax in den MQL5 Referenzhinweisen genau anzusehen.

Sie bemerken sicherlich auch die benutzerdefinierte Funktion TimeframeToString(), die in dieser Beitragsreihe bisher noch nie angesprochen worden ist. Sie wandelt Zeitrahmenwerte in einen String um, der für den Benutzer glasklar ist:

string TimeframeToString(ENUM_TIMEFRAMES timeframe)
  {
   string str="";
   //--- If the passed value is incorrect, take the time frame of the current chart
   if(timeframe==WRONG_VALUE || timeframe == NULL)
      timeframe = Period();
   switch(timeframe)
     {
      case PERIOD_M1  : str="M1";  break;
      case PERIOD_M2  : str="M2";  break;
      case PERIOD_M3  : str="M3";  break;
      case PERIOD_M4  : str="M4";  break;
      case PERIOD_M5  : str="M5";  break;
      case PERIOD_M6  : str="M6";  break;
      case PERIOD_M10 : str="M10"; break;
      case PERIOD_M12 : str="M12"; break;
      case PERIOD_M15 : str="M15"; break;
      case PERIOD_M20 : str="M20"; break;
      case PERIOD_M30 : str="M30"; break;
      case PERIOD_H1  : str="H1";  break;
      case PERIOD_H2  : str="H2";  break;
      case PERIOD_H3  : str="H3";  break;
      case PERIOD_H4  : str="H4";  break;
      case PERIOD_H6  : str="H6";  break;
      case PERIOD_H8  : str="H8";  break;
      case PERIOD_H12 : str="H12"; break;
      case PERIOD_D1  : str="D1";  break;
      case PERIOD_W1  : str="W1";  break;
      case PERIOD_MN1 : str="MN1"; break;
     }
//---
   return(str);
  }

Wie die Funktion CheckNewBar() verwendet wird wird später in diesem Beitrag beschrieben, dann, wenn wir alle anderen notwendigen Funktionen fertig haben. Werfen wir jetzt einen Blick auf die Funktion GetBarsData(), die die Werte der geforderten Anzahl an Bars annimmt.

//+------------------------------------------------------------------+
//| GETTING BAR VALUES                                               |
//+------------------------------------------------------------------+
void GetBarsData()
  {
//--- Number of bars for getting their data in an array
   int amount=2;
//--- Reverse the time series ... 3 2 1 0
   ArraySetAsSeries(close_price,true);
   ArraySetAsSeries(open_price,true);
//--- Get the closing price of the bar
//    If the number of the obtained values is less than requested, print the relevant message
   if(CopyClose(_Symbol,Period(),0,amount,close_price)<amount)
     {
      Print("Failed to copy the values ("
            +_Symbol+", "+TimeframeToString(Period())+") to the Close price array! "
            "Error "+IntegerToString(GetLastError())+": "+ErrorDescription(GetLastError()));
     }
//--- Get the opening price of the bar
//    If the number of the obtained values is less than requested, print the relevant message
   if(CopyOpen(_Symbol,Period(),0,amount,open_price)<amount)
     {
      Print("Failed to copy the values ("
            +_Symbol+", "+TimeframeToString(Period())+") to the Open price array! "
            "Error "+IntegerToString(GetLastError())+": "+ErrorDescription(GetLastError()));
     }
  }

Den o.g. Code sollten wir uns genauer ansehen. In der Variable 'Menge' geben wir zunächst die Anzahl der Bars an, deren Daten wir erhalten müssen. Dann richten wir mit Hilfe der ArraySetAsSeries() Funktion die Indizierungsreihenfolge des Arrays so ein, dass der Wert des letzten (aktuellen) Bars im Null-Index des Arrays ist. Wenn Sie also z.B. den Wert des letzten Bars in Ihrer Berechnung verwenden wollen, kann dies folgendermaßen geschrieben werden, falls durch den Eröffnungskurs veranschaulicht: open_price[0]. Die Schreibweise für den zweiten bis letzten Bar ist analog: open_price[1].

Der Mechanismus zum Abrufen der Schluss- und Eröffnungskurse ist ähnlich dem der Funktion CheckNewBar(), wo wir die Uhrzeit des letzten Bars erhalten mussten. In diesem Fall verwenden wir halt nur die CopyClose() und CopyOpen() Funktionen. Und analog werden CopyHigh() und CopyLow() dazu verwendet, die Kurse des hohen bzw. niedrigen Bars zu bekommen.

Gehen wir weiter und betrachten uns ein ganz einfaches Beispiel anhand dessen klar wird, wie man Signale zur Eröffnung/Umkehrung einer Position festlegt. Kurs-Arrays speichern Daten für zwei Bars (den aktuellen und den vorherigen, abgeschlossenen Bar). Wir arbeiten mit den Daten des abgeschlossenen Bars.

  • Ein Kaufen-Signal taucht auf, wenn der Abschlusskurs über dem Eröffnungskurs liegt (Hausse-Bar);
  • Ein Verkaufen-Signal taucht auf, wenn der Abschlusskurs unter dem Eröffnungskurs liegt (Baisse-Bar).

Der Code zur Implementierung dieser einfachen Bedingungen steht unten:

//+------------------------------------------------------------------+
//| DETERMINING TRADING SIGNALS                                      |
//+------------------------------------------------------------------+
int GetTradingSignal()
  {
//--- A Buy signal (0) :
   if(close_price[1]>open_price[1])
      return(0);
//--- A Sell signal (1) :
   if(close_price[1]<open_price[1])
      return(1);
//--- No signal (3):
   return(3);
  }

Sie sehen - alles ganz einfach. Man kann sich hier leicht vorstellen, wie man mit komplexeren Situationen auf ähnlich simple Weise umgehen kann. Die Funktion liefert '0', wenn ein abgeschlossener Bar oben ist oder '1', wenn ein abgeschlossener Bar unten ist. Sollte es auch irgendeinem Grund kein Signal gaben, liefert die Funktion '3'.

Jetzt müssen wir nur noch eine TradingBlock() Funktion zur Implementierung der Handelsaktivitäten erzeugen. Unten steht der Code dieser Funktion samt seiner detaillierten Anmerkungen:

//+------------------------------------------------------------------+
//| TRADING BLOCK                                                    |
//+------------------------------------------------------------------+
void TradingBlock()
  {
   int               signal=-1;           // Variable for getting a signal
   string            comment="hello :)";  // Position comment
   double            start_lot=0.1;       // Initial volume of a position
   double            lot=0.0;             // Volume for position calculation in case of reverse position
   double            ask=0.0;             // Ask price
   double            bid=0.0;             // Bid price
//--- Get a signal
   signal=GetTradingSignal();
//--- Find out if there is a position
   pos_open=PositionSelect(_Symbol);
//--- If it is a Buy signal
   if(signal==0)
     {
      //--- Get the Ask price
      ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
      //--- If there is no position
      if(!pos_open)
        {
         //--- Open a position. If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,start_lot,ask,0,0,comment))
           { Print("Error opening a BUY position: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
        }
      //--- If there is a position
      else
        {
         //--- Get the position type
         pos_type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         //--- If it is a SELL position
         if(pos_type==POSITION_TYPE_SELL)
           {
            //--- Get the position volume
            pos_volume=PositionGetDouble(POSITION_VOLUME);
            //--- Adjust the volume
            lot=NormalizeDouble(pos_volume+start_lot,2);
            //--- Open a position. If the position failed to open, print the relevant message
            if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,lot,ask,0,0,comment))
              { Print("Error opening a SELL position: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
           }
        }
      //---
      return;
     }
//--- If there is a Sell signal
   if(signal==1)
     {
      //-- Get the Bid price
      bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
      //--- If there is no position
      if(!pos_open)
        {
         //--- Open a position. If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,start_lot,bid,0,0,comment))
           { Print("Error opening a SELL position: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
        }
      //--- If there is a position
      else
        {
         //--- Get the position type
         pos_type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         //--- If it is a BUY position
         if(pos_type==POSITION_TYPE_BUY)
           {
            //--- Get the position volume
            pos_volume=PositionGetDouble(POSITION_VOLUME);
            //--- Adjust the volume
            lot=NormalizeDouble(pos_volume+start_lot,2);
            //--- Open a position. If the position failed to open, print the relevant message
            if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,lot,bid,0,0,comment))
              { Print("Error opening a SELL position: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
           }
        }
      //---
      return;
     }
  }

Bis zum dem Punkt, an dem eine Position eröffnet wird, sollte meiner Meinung nach jetzt alles klar sein. Wie Sie im obigen Code erkennen können, folgt dem (Handel)-Zeiger ein Punkt, dem seinerseits die PositionOpen() Methode folgt. So kann man eine bestimmte von der Klasse aufrufen. Nachdem Sie den Punkt gesetzt haben, sehen Sie eine Liste mit allen Klassenmethoden. Sie müssen nur noch die erforderliche Methode aus der Liste auswählen:

Abb. 1 Eine Klassenmethode aufrufen.

Abb. 1 Eine Klassenmethode aufrufen.

In der TradingBlock() Funktion gibt es zwei wichtige Blöcke - kaufen und verkaufen. Gleich nachdem wir die Richtung des Signals ermittelt haben, bekommen wir den Briefkurs im Falle eines Kauf-Signals und den Geldkurs im Falle eines Verkauf-Signals.

Alle in Handels-Orders benutzten Kurse/Stufen müssen mit Hilfe der NormalizeDouble() Funktion normalisiert werden, denn sonst führt der Versuch, eine Position zu eröffnen oder zu ändern, zu einem Fehler. Es empfiehlt sich auch, diese Funktion bei der Berechnung des Postens einzusetzen. Beachten Sie auch zudem, dass die Parameter Stop Loss und Take Profit Null-Werte besitzen. Mehr Informationen über die Einrichtung von Handelsstufen finden Sie im nächsten Beitrag dieser Reihe.

Jetzt sind alle benutzerdefinierten Funktionen fertig. Wir können sie also in der korrekten Reihenfolge anordnen:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Initialize the new bar
   CheckNewBar();
//--- Get position properties and update the values on the panel
   GetPositionProperties();
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Print the deinitialization reason to the journal
   Print(GetDeinitReasonText(reason));
//--- When deleting from the chart
   if(reason==REASON_REMOVE)
      //--- Delete all objects relating to the info panel from the chart
      DeleteInfoPanel();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- If the bar is not new, exit
   if(!CheckNewBar())
      return;
//--- If there is a new bar
   else
     {
      GetBarsData();  // Get bar data
      TradingBlock(); // Check the conditions and trade
     }
//--- Get the properties and update the values on the panel
   GetPositionProperties();
  }

Nur eine Sache müssen wir noch berücksichtigen: die Festlegung von Handelsereignissen mit Hilfe der OnTrade() Funktion. Darauf gehen wir hier nur kurz ein, nur damit Sie eine Vorstellung davon bekommen. In unserem Fall müssen wir das folgende Szenario implementieren: beim manuellen Eröffnen/Schließen/Verändern einer Position müssen die Werte in der Liste der Position-Eigenschaften auf dem Info-Panel aktualisiert werden, sobald der Vorgang abgeschlossen ist und nicht wenn man eine neue Kursschwankung (Tick) erhält. Zu diesem Zweck müssen wir nur den folgenden Code hinzufügen:

//+------------------------------------------------------------------+
//| TRADE EVENT                                                      |
//+------------------------------------------------------------------+
void OnTrade()
  {
//--- Get position properties and update the values on the panel
   GetPositionProperties();
  }

So im Grunde ist nun alles fertig und wir können uns dem Testen zuwenden. Mit dem Strategietester können Sie rasch einen Test im Visualisierungsmodus durchführen und Fehler finden, sollten welche vorhanden sein. Die Verwendung des Strategietesters ist auch deshalb von Vorteil, weil Sie Ihre Programme auch an Wochenenden weiter entwickeln können, wenn alle Märkte geschlossen sind.

Richten Sie den Strategietester ein, aktivieren Sie den Visualisierungsmodus und klicken auf 'Start'. Der Expert Advisor beginnt mit dem Handel im Strategietester und Sie sehen ein Bild, das dem unten gezeigten sehr ähnlich ist:

Abb. 2 Visualisierungsmodus im MetaTrader 5 Strategietester.

Abb. 2 Visualisierungsmodus im MetaTrader 5 Strategietester.

Das Testen im Visualisierungsmodus können Sie jederzeit unterbrechen und es dann Schritt für Schritt wieder aufnehmen, indem Sie F12 drücken. Der Schritt entspricht einem Bar, wenn Sie den Strategietester auf den Modus 'Nur Eröffnungskurse' eingestellt haben oder einer Kursschwankung, wenn Sie den Modus 'Jede Kursschwankung' gewählt haben. Die Geschwindigkeit des Tests können Sie ebenfalls kontrollieren.

Um sicherzugehen, dass die Werte auf dem Info-Panel unmittelbar nach dem manuellen Öffnen/Schließen einer Position oder dem Hinzufügen/Ändern der Stop Loss/Take Profit-Stufen aktualisiert werden, sollte der Expert Advisor im Echtzeit-Modus getestet werden. Warten Sie nicht zu lange, lassen Sie den Expert Advisor einfach auf einem Zeitrahmen von 1 Minute laufen, sodass alle 60 Sekunden Handelsoperationen durchgeführt werden.

Übrigens habe ich das Info-Panel um ein weiteres Array ergänzt - für die Namen der Position-Eigenschaften:

// Array of position property names
string pos_prop_texts[INFOPANEL_SIZE]=
  {
   "Symbol :",
   "Magic Number :",
   "Comment :",
   "Swap :",
   "Commission :",
   "Open Price :",
   "Current Price :",
   "Profit :",
   "Volume :",
   "Stop Loss :",
   "Take Profit :",
   "Time :",
   "Identifier :",
   "Type :"
  };

Im vorherigen Beitrag habe ich davon gesprochen, dass wir dieses Array zur Reduzierung des SetInfoPanel() Funktionscodes bräuchten. Jetzt sehen Sie, wie dies geht, wenn Sie es nicht bereits selbst schon implementiert oder herausgefunden haben. Die neue Implementierung der Liste zur Erzeugung der Objekte in Zusammenhang mit den Position-Eigenschaften lautet so:

//--- List of the names of position properties and their values
   for(int i=0; i<INFOPANEL_SIZE; i++)
     {
      //--- Property name
      CreateLabel(0,0,pos_prop_names[i],pos_prop_texts[i],anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[i],2);
      //--- Property value
      CreateLabel(0,0,pos_prop_values[i],GetPropertyValue(i),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[i],2);
     }

Zu Anfang der SetInfoPanel() Funktion fällt Ihnen bestimmt die folgende Zeile auf:

//--- Testing in the visualization mode
   if(MQL5InfoInteger(MQL5_VISUAL_MODE))
     {
      y_bg=2;
      y_property=16;
     }

Sie übermittelt dem Programm, dass Y-Koordinaten der Objekte auf dem Info-Panel angepasst werden müssen, wenn das Programm derzeit im Visualierungsmodus getestet wird. Das liegt daran, dass beim Testen im Visualisierungsmodus des Strategietesters der Name des Expert Advisors in der oberen Ecke des Charts nicht so wie in Echtzeit angezeigt wird. Die unnötige Einrückung kann daher auf diese Weise gelöscht werden.


Fazit

Das ist für den Moment alles. Im nächsten Beitrag konzentrieren wir uns auf die Einrichtung und Veränderung von Handelsstufen. Unten können Sie den Quellcode, PositionPropertiesTesterEN.mq5, für den Expert Advisor herunterladen.

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

Beigefügte Dateien |
MQL5 Cookbook: Position-Eigenschaften auf dem Angepassten Info-Panel MQL5 Cookbook: Position-Eigenschaften auf dem Angepassten Info-Panel
Diesmal erzeugen wir einen einfachen Expert Advisor, der die Position-Eigenschaften auf dem aktuellen Symbol abruft und sie im angepassten Info-Panel während manuell durchgeführtem Handel anzeigt. Das Info-Panel wird mit Hilfe graphischer Objekte erstellt, und die angezeigte Information wird bei jeder Kursschwankung (Tick) aktualisiert. Das ist weitaus bequemer als ständig das im vorangegangenen Beitrag der Reihe "MQL5 Cookbook: Wie man Position-Eigenschaften abruft", beschriebene Script manuell laufen lassen zu müssen.
MQL5 Cookbook: Wie man bei der Einrichtung/Änderung von Handelsstufen Fehler vermeidet MQL5 Cookbook: Wie man bei der Einrichtung/Änderung von Handelsstufen Fehler vermeidet
Als Fortsetzung unserer Arbeit am Expert Advisor aus dem vorangegangenen Beitrag der MQL5 Cookbook-Reihe mit dem Titel : "Position-Eigenschaften im MetaTrader 5 Strategietester analysieren", wollen wir diesmal den EA durch viele nützliche Funktionen erweitern und die bereits bestehenden verbessern und optimieren. Diesmal wird der Expert Advisor externe Parameter haben, die im MetaTrader 5 Strategietester optimiert werden können, sodass er auf gewisse Weise einem einfachen Handelssystem gleicht.
MQL5 Cookbook: Wie man Position-Eigenschaften bekommt MQL5 Cookbook: Wie man Position-Eigenschaften bekommt
In diesem Beitrag beschäftigen wir uns damit, wie man ein Script schreibt, das alle Position-Eigenschaften abruft und sie für den Anwender im Dialogfenster anzeigt. Wenn Sie das Script starten, können Sie aus zwei Modi wählen, die in der Dropdown-Liste in den externen Parametern zur Verfügung stehen: entweder Ansicht der Position-Eigenschaften nur auf dem aktuellen Symbol oder Ansicht der Position-Eigenschaften auf allen Symbolen.
MQL5 Cookbook: Die History der Abschlüsse und Funktions-Library zum Erhalt von Position-Eigenschaften MQL5 Cookbook: Die History der Abschlüsse und Funktions-Library zum Erhalt von Position-Eigenschaften
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.