English Русский 中文 Español 日本語 Português
Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil I). Konzept, Datenverwaltung und erste Ergebnisse

Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil I). Konzept, Datenverwaltung und erste Ergebnisse

MetaTrader 5Beispiele | 3 Mai 2019, 09:08
2 219 2
Artyom Trishkin
Artyom Trishkin

Inhalt

Einführung

Bei der Analyse einer Vielzahl von Handelsstrategien, Aufträgen zur Entwicklung von Anwendungen für die Terminals von MetaTrader 5 und 4 und verschiedenen Websites über Skripte, Indikatoren und Roboter für MetaTrader kam ich zu dem Schluss, dass diese ganze Vielfalt hauptsächlich auf den gleichen elementaren Funktionen, Aktionen und Werten basiert, die regelmäßig in verschiedenen Programmen wiederkehren.

Tatsächlich kann die Logik eines jeden Programms in viele identische Aktionen unterteilt werden. Die Ergebnisse dieser Aktionen werden verwendet, um die Logik von Anwendungen aufzubauen. Dies wurde immer wieder durch die Einheitlichkeit der Fragen in den MQL4/MQL5-Foren bestätigt. Verschiedene Benutzer stellen im Wesentlichen die gleichen Fragen zu den Algorithmen und Aufgaben, die sie lösen.

Vor diesem Hintergrund entschied ich mich, eine große Bibliothek mit integrierten Funktionen zur Anforderung und Beschaffung der notwendigen Daten zu entwickeln. Um den Datensatz der vorgeschlagenen Bibliothek zu verwenden, müssen die Benutzer nur auf die Frage-Antwort-Methode zurückgreifen, um eine große Menge an völlig unterschiedlichen Daten (in verschiedenen Kombinationen und Sortierparametern) zu erhalten, die die Bibliothek sammelt und in ihrer Datenbank speichert.

Konzept

Jeder Datentyp kann als eine Reihe von Objekten mit denselben Eigenschaften dargestellt werden.
So kann beispielsweise eine Zeitreihe als eine lange geordnete Liste dargestellt werden, in der jede nachfolgende Zelle ein Objekt mit der Menge von Eigenschaften speichert, die vom gleichen Typ ist wie bei allen anderen, die zu ähnlichen Objekten innerhalb der Zeitreihe gehören. Die Daten eines solchen Objekts werden durch die Struktur MqlRates dargestellt:

Struktur zur Speicherung von Informationen über Preise, Volumina und Spreads.

struct MqlRates 
  { 
   datetime time;         // Anfangszeit der Zeitspanne
   double   open;         // Eröffnungspreis
   double   high;         // Höchster Preis der Zeitspanne
   double   low;          // tiefster Preis der Zeitspanne
   double   close;        // Schlusskurs
   long     tick_volume;  // Tick-Volumen 
   int      spread;       // Spread 
   long     real_volume;  // Börsenvolumen
  };

Auch die Tick-Daten können als geordnete Liste dargestellt werden, wobei ein Tick, der durch die Struktur MqlTick repräsentiert wird, ein Objekt mit einem festen Satz von Eigenschaften ist:

Struktur zur Speicherung der letzten Preise eines Symbols. Die Struktur ist so konzipiert, dass die am häufigsten benötigten Daten über die aktuellen Preise zeitnah abgerufen werden können.

struct MqlTick 
  { 
   datetime     time;          // Zeit der letzten Preisaktualisierung
   double       bid;           // Aktueller Bid-Preis
   double       ask;           // Aktueller Ask-Preis
   double       last;          // Aktueller Preis des letzten Deals (Last) 
   ulong        volume;        // Volumen des letzten Preises
   long         time_msc;      // Zeit der letzeten Preisaktualisierung in Millisekunden
   uint         flags;         // Tick flags 
   double       volume_real;   // Volumen des aktuellen Preisen (Last) mit ansteigender Genauigkeit
  };

Alle weiteren Daten, die zur Analyse und Vorbereitung der Programmlogik notwendig sind, sind ebenfalls als einfache Objektlisten angeordnet.

Alle Objekte in einer Liste haben den gleichen Datentyp, der für diesen Objekttyp spezifisch ist, unabhängig davon, ob es sich um eine Liste von Aufträgen, Geschäften oder offenen Aufträgen handelt. Für jedes spezifische Objekt entwickeln wir eine Klasse mit der minimal notwendigen Funktionalität zum Speichern, Sortieren und Anzeigen von Daten.

Datenstruktur der Bibliothek

Wie bereits erwähnt, soll die Bibliothek aus einer Objektliste bestehen und die Möglichkeit bieten, jedes der Listenelemente nach einem benutzerdefinierten Kriterium oder einer Eigenschaft auszuwählen, die von diesem Objekt unterstützt wird. Die Bibliothek sammelt die notwendigen Daten für die eigenständige Speicherung und Handhabung. Es ist kein menschliches Eingreifen erforderlich. Die Nutzer werden nur die Ergebnisse ihrer Bibliotheksabfragen verwenden.

Ich werde alle Schritte der Entwicklung der Bibliothek beschreiben, beginnend mit den einfachsten Themen und allmählich werden die neuen Funktionen und Daten zu den bereits vorhandenen hinzugefügt. Die Bibliothek soll im "Live"-Modus entwickelt werden. Erforderliche Änderungen und Ergänzungen sind in jedem Artikel vorzunehmen. Ich glaube, diese Art der Präsentation ist sehr nützlich, da sie die Leser in die Entwicklung einbezieht.

Die minimale Struktur der Bibliotheksdaten besteht aus einer Reihe von verschiedenen Objekten zur Beschreibung der Eigenschaften der erforderlichen Daten, während Datensammlungen Listen mit den entsprechenden Objekten sind.

Wir werden die Klasse des dynamischen Arrays von Zeigern auf Instanzen von CObject-Klasse und ihre geerbten Klassen aus der Standardbibliotheksdatenbank verwenden, um die Listen anzuordnen. Da für die Ablage in einer solchen Liste Objekte der Basisklasse der CObject Standardbibliothek benötigt werden, leiten wir einfach jede Klasse unserer Objekte von der Basisklasse CObject ab.

Erste Umsetzung

Zunächst werden wir die Bibliothek für Hedge-Konten des MetaTrader 5 Terminals entwickeln. Nachdem wir die Mindestfunktionalität vorbereitet haben, werden wir deren Verwendung für den MetaTrader 4 anpassen. Als nächstes werden wir nach der Implementierung der Kontohistorie, der aktuellen Marktpositionen und der ausstehenden Auftragsabwicklung die Möglichkeit der Zusammenarbeit mit MetaTrader 5 Netting-Konten hinzufügen. Schließlich werden wir die Bibliothek mit einer Vielzahl ganzer Funktionen versehen.

Beginnen wir mit der Kontenübersicht. Viele Strategien wenden die Ergebnisse vergangener Geschäfte auf die eine oder andere Weise an, z.B. Ergebnisse früherer Geschäfte, die Methoden ihrer Schließung (Stop-Loss, Take-Profit), Preis, etc. Außerdem können die Ergebnisse des letzten Tages als Ausgangspunkt für die aktuelle Arbeit verwendet werden. Die Arten von Handelsstrategien sind grenzenlos, und unsere Aufgabe ist es, einen schnellen Zugang zu der ganzen Vielfalt zu ermöglichen.

Zuerst definieren wir die Terminologie für die Arbeit mit Sammlungen historischer Aufträge, Geschäfte, Marktaufträge und Positionen. Das Order-System des MetaTrader 4 unterscheidet sich vom MetaTrader 5. Während MetaTrader 4 Markt- und Pending-Orders bietet, ist eine Order in MetaTrader 5 im Grunde genommen eine Handelsanfrage (Market Order), die ein Geschäft generiert, während das Geschäft wiederum eine Position generiert. Außerdem gibt es noch offene Aufträge. Mit anderen Worten, wir haben mindestens drei Objekte — einen Auftrag, eine Transaktion (Deal) und eine Position. Um nicht durch Namen und Definitionen abgelenkt zu werden, rufen wir die Klasse zur Speicherung von Daten durch Orders, Deals und Positionen einfach als abstrakte Orderklasse auf. Weiterhin ist alles nach Typen (Bestellungen, Deals, etc.) in unserer Liste (Sammlung der am Anfang des Artikels erwähnten historischen Bestellungen) zu sortieren.

Die abstrakte Klasse der Orders ein Order- oder Deal-Ticket sowie die gesamten Daten über die Parameter des Orders oder Deals und dessen Status enthalten. Der Status zeigt an, was genau das Objekt ist — ein Auftrag, ein Geschäft oder eine Position.

Im Ordner <terminal data>\MQL5\Include erstellen wir den Ordner DoEasy, in dem die Bibliotheksdateien gespeichert werden sollen. In dieser Phase benötigen wir zwei weitere Verzeichnisse im DoEasy-Ordner: Der Ordner Objects speichert Objektklassen, während Collections Datensammlungen (Objektlisten) enthält.
Um das Verzeichnis des Terminal zu finden, gehen Sie zu File -> Dateiordner öffnen (Ctrl + Shift + D).

Nun können wir die erste Klasse (abstrakte Klasse der Aufträge) anlegen. Erstellen Sie eine neue Klasse im Ordner Objects und nennen Sie sie COrder (1). Stellen Sie sicher, dass Sie die CObject (2) Klasse der Standardbibliothek als Basisklasse einstellen. In diesem Fall wird unsere neue Objektklasse von der Klasse CObject übernommen und kann in die Liste der CArrayObj-Objekte der Standardbibliothek aufgenommen werden.


Nach dem Klicken auf "Fertig stellen" erscheint die neue Datei Order.mqh (3) im Ordner Objects des Bibliotheksverzeichnisses. Noch ist dies nur eine Klasse:

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:

public:
                     COrder();
                    ~COrder();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::COrder()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::~COrder()
  {
  }
//+------------------------------------------------------------------+

Beim Versuch, den Code zu kompilieren, erhalten wir fünf Fehler. Sie zeigen das Fehlen der CO-Objektklasse an, aus der die Klasse COrder abgeleitet ist. Binden wir die Klassendatei CObject in den Code ein und kompilieren sie erneut. Jetzt ist alles in Ordnung.

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#include <Object.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:

public:
                     COrder();
                    ~COrder();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::COrder()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::~COrder()
  {
  }
//+------------------------------------------------------------------+

Das Objekt der Klasse wird in einer Schleife über Orders, Deals oder Positionen erzeugt, wenn die nächste Order, Deal oder Position ausgewählt wird. Um die Felder des Objekts sofort zu initialisieren, werden wir einen privaten Konstruktor anlegen, an den der Objekttyp (Status) und das Ticket zur späteren Identifizierung übergeben werden. Aber zuerst platzieren wir die neue Include-Datei Defines.mqh in den Projekt-Root-Ordner, in dem alle für die Bibliothek notwendigen Enumerationen sowie Makro-Substitutionen, Konstanten und Strukturen gespeichert sind.

Derzeit benötigen wir Aufzählungen, die einen Auftragsstatus beschreiben, und Aufzählungen, die alle Parameter von Orders, Deals oder Positionen beschreiben. Es wird drei Enumerationen mit Auftragsparametern geben: Ganzahlig (int), Gleitkomma (double) und Zeichenketten (string).

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
//+------------------------------------------------------------------+
//| Abstrakter Order-Typ (Status)                                    |
//+------------------------------------------------------------------+
enum ENUM_ORDER_STATUS
  {
   ORDER_STATUS_MARKET_PENDING,                             // Aktuelle Pending-Order
   ORDER_STATUS_MARKET_ACTIVE,                              // Aktive Marktorder
   ORDER_STATUS_HISTORY_ORDER,                              // Historie der Marktorders
   ORDER_STATUS_HISTORY_PENDING,                            // Entfernte Pending-Order
   ORDER_STATUS_BALANCE,                                    // Saldo-Operation
   ORDER_STATUS_CREDIT,                                     // Finanz-Operation
   ORDER_STATUS_DEAL,                                       // Deal (Transaktion)
   ORDER_STATUS_UNKNOWN                                     // Status unbekannt
  };
//+------------------------------------------------------------------+
//| Order, Deal, Position, ganzzahlige Eigenschaften                 |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_INTEGER
  {
   ORDER_PROP_TICKET = 0,                                   // Order-Ticket
   ORDER_PROP_MAGIC,                                        // Order Magicnummer
   ORDER_PROP_TIME_OPEN,                                    // Eröffnungszeit
   ORDER_PROP_TIME_CLOSE,                                   // Schlusszeit
   ORDER_PROP_TIME_EXP,                                     // Verfallszeit der Order (für Pending-Orders)
   ORDER_PROP_TYPE,                                         // Order- und Deal-Type
   ORDER_PROP_STATUS,                                       // Order-Status (aus der Enumeration ENUM_ORDER_STATUS)
   ORDER_PROP_REASON,                                       // Deal/Order/Position Grund oder Quelle
   ORDER_PROP_POSITION_ID,                                  // Positions-ID
   ORDER_PROP_POSITION_BY_ID,                               // Entgegengesetzte Positions-ID
   ORDER_PROP_DEAL_ORDER,                                   // Order, weswegen der Deal ausgeführt wurde
   ORDER_PROP_DEAL_ENTRY,                                   // Deal-Richtung – IN, OUT oder IN/OUT
   ORDER_PROP_TIME_OPEN_MSC,                                // Eröffnungszeit in Millisekunden
   ORDER_PROP_TIME_CLOSE_MSC,                               // Schlusszeit in Millisekunden (Zeit der Ausführung oder Entfernung - ORDER_TIME_DONE_MSC)
   ORDER_PROP_TIME_UPDATE,                                  // Zeit der Positionsänderung in Sekunden
   ORDER_PROP_TIME_UPDATE_MSC,                              // Zeit der Positionsänderung in Millisekunden
   ORDER_PROP_TICKET_FROM,                                  // Ticket der Ober-Order
   ORDER_PROP_TICKET_TO,                                    // Ticket der abgeleiteten Order
   ORDER_PROP_PROFIT_PT,                                    // Gewinn in Points
   ORDER_PROP_CLOSE_BY_SL,                                  // Flag für das Schließen durch StopLoss
   ORDER_PROP_CLOSE_BY_TP,                                  // Flag für das Schließen mit TakeProfit
   ORDER_PROP_DIRECTION,                                    // Richtung (Buy, Sell)
  }; 
#define ORDER_PROP_INTEGER_TOTAL    (22)                    // Gesamtzahl der ganzzahligen Eigenschaften
//+------------------------------------------------------------------+
//| Order, Deal, Position Double-Eigenschaften                       |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_DOUBLE
  {
   ORDER_PROP_PRICE_OPEN = ORDER_PROP_INTEGER_TOTAL,        // Eröffnungspreis (MQL5 Deal-Preis)
   ORDER_PROP_PRICE_CLOSE,                                  // Schlusskurs
   ORDER_PROP_PROFIT,                                       // Gewinn
   ORDER_PROP_COMMISSION,                                   // Kommission
   ORDER_PROP_SWAP,                                         // Swap
   ORDER_PROP_VOLUME,                                       // Volumen
   ORDER_PROP_VOLUME_CURRENT,                               // Nicht ausgeführtes Volumen
   ORDER_PROP_SL,                                           // Preis des StopLoss'
   ORDER_PROP_TP,                                           // Preis des TakeProfits
   ORDER_PROP_PROFIT_FULL,                                  // Gewinn+Kommission+Swap
   ORDER_PROP_PRICE_STOP_LIMIT,                             // Preis der Limit-Order, wenn eine StopLimit-Order aktiviert ist
  };
#define ORDER_PROP_DOUBLE_TOTAL     (11)                    // Gesamtzahl der Double-Eigenschaften
//+------------------------------------------------------------------+
//| Order, Deal, Position String-Eigenschaften                       |
//+------------------------------------------------------------------+
enum ENUM_ORDER_PROP_STRING
  {
   ORDER_PROP_SYMBOL = (ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL), // Order-Symbol
   ORDER_PROP_COMMENT,                                      // Order-Kommentar
   ORDER_PROP_EXT_ID                                        // Order-ID im externen Handelssystem
  };
#define ORDER_PROP_STRING_TOTAL     (3)                     // Gesamtzahl der String-Eigenschaften
//+------------------------------------------------------------------+

Einige Eigenschaften wurden zusätzlich zu den Aufzählungen platziert: Ticket der Ober-Order, Ticket der abgeleiteten Order, Profit in Points, Eigenschaften des Schließens bei Stop-Loss oder Take-Profit, Richtung und voller Gewinn — unter Berücksichtigung von Provision und Swap. Diese Daten werden häufig in der Logik der Handelsstrategie verwendet, so dass sie in den abstrakten Orderfeldern gespeichert und sofort in benutzerdefinierten Programmen aktualisiert und empfangen werden sollten.

Um alle Eigenschaften der Orders (ganzzahlig, Double- und String-Eigenschaften) zusammenzufassen, erstellen Sie Makro-Substitutionen, die die Anzahl der Parameter in jeder der drei Aufzählungen für jeden Eigenschaftstyp enthalten.
Die Nummerierung der Aufzählungen von ganzzahligen Eigenschaften beginnt bei Null, während die Nummerierung der Aufzählungen von anderen Eigenschaften bei der Gesamtzahl der vorherigen Eigenschaften beginnt. So können wir immer den Index der benötigten Eigenschaft als Differenz zwischen der Nummer einer angeforderten Eigenschaft und der Nummer der ursprünglichen Eigenschaft dieser Enumeration erhalten.

Nachdem wir die Datei Defines.mqh erstellt haben, verbinden wir sie mit der aktuellen Datei der COrder-Klasse und erstellen im Bereich 'private' die Klassenmitgliedsvariable zum Speichern des Auftragstickets und drei Arrays zum Speichern der Auftragseigenschaften Integer, Double und String :

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#include <Object.mqh>
#include "..\Defines.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:
   ulong             m_ticket;                                 // Ticket der ausgewählten Order/Deal (MQL5)
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];    // Ganzzahlige Eigenschaften
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];   // Double-Eigenschaften
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];   // String-Eigenschaften
public:
                     COrder();
                    ~COrder();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::COrder()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::~COrder()
  {
  }
//+------------------------------------------------------------------+

Um die Datei Defines.mqh einzubinden, setzen wir einen relativen Pfad zur Datei in Anführungszeichen, anstatt spitzer Klammern (<>), die wir bei der Einbindung von CObject verwendet haben. Dies geschieht, damit beim Übertragen der Bibliothek in ein anderes Verzeichnis die Verbindung zwischen den Dateien nicht verloren geht und sich immer auf den Speicherort der Datei Defines.mqh im Verhältnis zum aktuellen Verzeichnis bezieht.

Nun, lassen Sie uns zwei Methoden im gleichen privaten Bereich erstellen. Das erste ist, eine genaue Position der notwendigen Eigenschaft in den Property-Arrays zurückzugeben, während das zweite, einen geschützten Konstruktor in dem entsprechenden geschützten Abschnitt zurückzugeben ist. Lassen Sie den Standardkonstruktor für die Erstellung eines leeren Auftragsobjekts stehen, ohne seine Eigenschaften zu initialisieren, und entfernen Sie den Destruktor (wir benötigen ihn nicht, und er wird automatisch während der Kompilierung erstellt):

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#include <Object.mqh>
#include "..\Defines.mqh"
//+------------------------------------------------------------------+
//| Abstract order class                                             |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:
   ulong             m_ticket;                                    // Ticket der ausgewählten Order/Deal (MQL5)
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];       // Ganzzahlige Eigenschaften
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];      // Double-Eigenschaften
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];      // String-Eigenschaften
   
   //--- Rückgabe des Arrayindex der aktuellen Double-Eingenschaft
   int               IndexProp(ENUM_ORDER_PROP_DOUBLE property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL;                  }
   //--- Rückgabe des Arrayindex der aktuellen String-Eingenschaft
   int               IndexProp(ENUM_ORDER_PROP_STRING property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL-ORDER_PROP_DOUBLE_TOTAL;}
public:
   //--- Standardmäßiger Konstruktor
                     COrder(void){;}
protected:                                                                     
   //--- 'Protected' Konstruktor                                
                     COrder(ENUM_ORDER_STATUS order_status,const ulong ticket);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket)
  {
  }
//+------------------------------------------------------------------+

Bisher tut der 'protected' Konstruktor nichts. Er wird verwendet, um sofort alle Eigenschaften der Reihenfolge zu initialisieren, deren Ticket an den Klassenkonstruktor übergeben wird, wenn ein Objekt erstellt wird. Da die Reihenfolge bereits ausgewählt wurde, können wir die notwendigen Eigenschaften einer ausgewählten Reihenfolge ermitteln und in die Arrays der Objekteigenschaften schreiben. Wir werden dies etwas später tun, nachdem wir Methoden zum Empfangen und Zurückgeben von Auftragsdaten erstellt haben.

Da es sich um eine plattformübergreifende Bibliothek handelt, ist es bequemer, separate Methoden zur Erlangung von Auftragseigenschaften zu erstellen.
Fügen Sie im geschützten Abschnitt Beschreibungen von Methoden zum Empfangen von Integer, Double und String Eigenschaften einer ausgewählten Ordnung hinzu.

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#include <Object.mqh>
#include "..\Defines.mqh"
//+------------------------------------------------------------------+
//| Abstract order class                                             |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:
   ulong             m_ticket;                                    // Ticket der ausgewählten Order/Deal (MQL5)
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];       // Ganzzahlige Eigenschaften
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];      // Double-Eigenschaften
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];      // String-Eigenschaften
   
   //--- Rückgabe des Arrayindex der aktuellen Double-Eingenschaft
   int               IndexProp(ENUM_ORDER_PROP_DOUBLE property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL;                        }
   //--- Rückgabe des Arrayindex der aktuellen String-Eingenschaft
   int               IndexProp(ENUM_ORDER_PROP_STRING property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL-ORDER_PROP_DOUBLE_TOTAL;}
public:
   //--- Standardmäßiger Konstruktor
                     COrder(void){;}
protected:
   //--- 'Protected' Konstruktor
                     COrder(ENUM_ORDER_STATUS order_status,const ulong ticket);
                     
   //--- Die ganzzahligen Eigenschaften der ausgewählten Order aus den Parametern abrufen und zurückgeben
   long              OrderMagicNumber(void)        const;
   long              OrderTicket(void)             const;
   long              OrderTicketFrom(void)         const;
   long              OrderTicketTo(void)           const;
   long              OrderPositionID(void)         const;
   long              OrderPositionByID(void)       const;
   long              OrderOpenTimeMSC(void)        const;
   long              OrderCloseTimeMSC(void)       const;
   long              OrderType(void)               const;
   long              OrderTypeByDirection(void)    const;
   long              OrderTypeFilling(void)        const;
   long              OrderTypeTime(void)           const;
   long              OrderReason(void)             const;
   long              DealOrder(void)               const;
   long              DealEntry(void)               const;
   bool              OrderCloseByStopLoss(void)    const;
   bool              OrderCloseByTakeProfit(void)  const;
   datetime          OrderOpenTime(void)           const;
   datetime          OrderCloseTime(void)          const;
   datetime          OrderExpiration(void)         const;
   datetime          PositionTimeUpdate(void)      const;
   datetime          PositionTimeUpdateMSC(void)   const;
   
   //--- Die Double-Eigenschaften der ausgewählten Order aus den Parametern abrufen und zurückgeben: (1) Eröffnungspreis, (2) Schlusskurs, (3) Gewinn,
   //---  (4) Kommission, (5) Swap, (6) Volumen, (7) nicht ausgeführtes Volumen, (8) StopLoss, (9) TakeProfit, (10) StopLimit-Order
   double            OrderOpenPrice(void)          const;
   double            OrderClosePrice(void)         const;
   double            OrderProfit(void)             const;
   double            OrderCommission(void)         const;
   double            OrderSwap(void)               const;
   double            OrderVolume(void)             const;
   double            OrderVolumeCurrent(void)      const;
   double            OrderStopLoss(void)           const;
   double            OrderTakeProfit(void)         const;
   double            OrderPriceStopLimit(void)     const;
   
   //--- Die Double-Eigenschaften der ausgewählten Order aus den Parametern abrufen und zurückgeben: (1) Symbol, (2) Kommentar, (3) ID des Börsenplatzes
   string            OrderSymbol(void)             const;
   string            OrderComment(void)            const;
   string            OrderExternalID(void)         const;
   
//---
  };
//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket)
  {
  }
//+------------------------------------------------------------------+

Derzeit sind nur die Methoden zur Übernahme Empfangen von Eigenschaften deklariert. Sie sind noch nicht implementiert, obwohl die Klasse fehlerfrei kompiliert wurde. Arrays mit den Order-Eigenschaften werden im Klassenkonstruktor mit den Methoden befüllt, die wir gerade hinzugefügt haben. Wenn alles fertig ist, werden diese Arrays es uns ermöglichen, im Programm jede Eigenschaft auf Anfrage zu erhalten.

Die virtuelle Methode zum Vergleichen von Objekten durch bestimmte Eigenschaften wird in der Klasse CObject der Standardbibliothek deklariert. Die Methode sollte jedoch in den abgeleiteten Klassen implementiert werden. Fügen wir daher der abstrakten Order-Klasse die Methode hinzu, um COrder-Objekte gemäß einer ihrer Eigenschaften zu vergleichen, sowie mehrere öffentliche Methoden für den Zugriff auf Auftragseigenschaften und virtuelle Methoden, die Flags zurückgeben, um die spezifische Eigenschaft eines Auftragsobjekts zu unterstützen. Diese Methoden sind in den nachkommenden Objekten der Klasse COrder zu implementieren. Dies wird später erforderlich sein, um Aufträge aus der Abholliste nach einer ihrer Eigenschaften auszuwählen. Standardmäßig, wenn eine dieser Methoden nicht in der abgeleiteten Klasse implementiert ist, wird das Flag zurückgegeben, das die Unterstützung der Bestellung für diese Eigenschaft anzeigt.

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#include <Object.mqh>
#include "..\Defines.mqh"
//+------------------------------------------------------------------+
//| Abstract order class                                             |
//+------------------------------------------------------------------+
class COrder : public CObject
  {
private:
   ulong             m_ticket;                                    // Ticket der ausgewählten Order/Deal (MQL5)
   long              m_long_prop[ORDER_PROP_INTEGER_TOTAL];       // Ganzzahlige Eigenschaften
   double            m_double_prop[ORDER_PROP_DOUBLE_TOTAL];      // Double-Eigenschaften
   string            m_string_prop[ORDER_PROP_STRING_TOTAL];      // String-Eigenschaften
   
   //--- Rückgabe des Arrayindex der aktuellen Double-Eingenschaft
   int               IndexProp(ENUM_ORDER_PROP_DOUBLE property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL;                        }
   //--- Rückgabe des Arrayindex der aktuellen String-Eingenschaft
   int               IndexProp(ENUM_ORDER_PROP_STRING property)   const { return (int)property-ORDER_PROP_INTEGER_TOTAL-ORDER_PROP_DOUBLE_TOTAL;}
public:
   //--- Standardmäßiger Konstruktor
                     COrder(void){;}
protected:
   //--- 'Protected' Konstruktor
                     COrder(ENUM_ORDER_STATUS order_status,const ulong ticket);
                     
   //--- Die ganzzahligen Eigenschaften der ausgewählten Order aus den Parametern abrufen und zurückgeben
   long              OrderMagicNumber(void)        const;
   long              OrderTicket(void)             const;
   long              OrderTicketFrom(void)         const;
   long              OrderTicketTo(void)           const;
   long              OrderPositionID(void)         const;
   long              OrderPositionByID(void)       const;
   long              OrderOpenTimeMSC(void)        const;
   long              OrderCloseTimeMSC(void)       const;
   long              OrderType(void)               const;
   long              OrderTypeByDirection(void)    const;
   long              OrderTypeFilling(void)        const;
   long              OrderTypeTime(void)           const;
   long              OrderReason(void)             const;
   long              DealOrder(void)               const;
   long              DealEntry(void)               const;
   bool              OrderCloseByStopLoss(void)    const;
   bool              OrderCloseByTakeProfit(void)  const;
   datetime          OrderOpenTime(void)           const;
   datetime          OrderCloseTime(void)          const;
   datetime          OrderExpiration(void)         const;
   datetime          PositionTimeUpdate(void)      const;
   datetime          PositionTimeUpdateMSC(void)   const;
   
   //--- Die Double-Eigenschaften der ausgewählten Order aus den Parametern abrufen und zurückgeben: (1) Eröffnungspreis, (2) Schlusskurs, (3) Gewinn,
   //---  (4) Kommission, (5) Swap, (6) Volumen, (7) nicht ausgeführtes Volumen, (8) StopLoss, (9) TakeProfit, (10) StopLimit-Order
   double            OrderOpenPrice(void)          const;
   double            OrderClosePrice(void)         const;
   double            OrderProfit(void)             const;
   double            OrderCommission(void)         const;
   double            OrderSwap(void)               const;
   double            OrderVolume(void)             const;
   double            OrderVolumeCurrent(void)      const;
   double            OrderStopLoss(void)           const;
   double            OrderTakeProfit(void)         const;
   double            OrderPriceStopLimit(void)     const;
   
   //--- Die Double-Eigenschaften der ausgewählten Order aus den Parametern abrufen und zurückgeben: (1) Symbol, (2) Kommentar, (3) ID des Börsenplatzes
   string            OrderSymbol(void)             const;
   string            OrderComment(void)            const;
   string            OrderExternalID(void)         const;
   
public:
   //--- Rückgabe der Order-Eigenschaften (1) Integer, (2) Double und (3) String aus dem Array der Eigenschaften
   long              GetProperty(ENUM_ORDER_PROP_INTEGER property)      const { return m_long_prop[property];                    }
   double            GetProperty(ENUM_ORDER_PROP_DOUBLE property)       const { return m_double_prop[this.IndexProp(property)];  }
   string            GetProperty(ENUM_ORDER_PROP_STRING property)       const { return m_string_prop[this.IndexProp(property)];  }
   
   //--- Rückgabe des Flags der Order mit den Eigenschaften
   virtual bool      SupportProperty(ENUM_ORDER_PROP_INTEGER property)        { return true; }
   virtual bool      SupportProperty(ENUM_ORDER_PROP_DOUBLE property)         { return true; }
   virtual bool      SupportProperty(ENUM_ORDER_PROP_STRING property)         { return true; }
   
   //--- Vergleich der Objekte von COrder mit allen möglichen Eigenschaften
   virtual int       Compare(const CObject *node,const int mode=0) const;
   
//---
  };
//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket)
  {
  }
//+------------------------------------------------------------------+

Implementierung des Verfahrens zum Vergleichen zweier Aufträge durch eine bestimmte Eigenschaft:

//+------------------------------------------------------------------+
//| Compare COrder objects by all possible properties                |
//+------------------------------------------------------------------+
int COrder::Compare(const CObject *node,const int mode=0) const
  {
   const COrder *order_compared=node;
//--- Vergleich der ganzzahligen Eigenschaften von zwei Orders
   if(mode<ORDER_PROP_INTEGER_TOTAL)
     {
      long value_compared=order_compared.GetProperty((ENUM_ORDER_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_ORDER_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- Vergleich der Double-Eigenschaften von zwei Orders
   else if(mode<ORDER_PROP_DOUBLE_TOTAL+ORDER_PROP_INTEGER_TOTAL)
     {
      double value_compared=order_compared.GetProperty((ENUM_ORDER_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_ORDER_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- Vergleich der String-Eigenschaften von zwei Orders
   else if(mode<ORDER_PROP_DOUBLE_TOTAL+ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_STRING_TOTAL)
     {
      string value_compared=order_compared.GetProperty((ENUM_ORDER_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_ORDER_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+

Die Methode übergibt den Zeiger an das Order-Objekt, dessen Eigenschaft mit einem bestimmten vorgegebenen Wert verglichen werden soll, sowie den Wert selbst aus der Enumeration der Auftragseigenschaften.
Wenn der Bestellwert den Vergleichswert überschreitet, gibt das System 1 zurück, wenn er kleiner als der Vergleichswert ist, gibt das System -1 zurück, ansonsten - 0. Die Liste der Aufträge, die verglichen werden, sollte vorläufig nach der verglichenen Eigenschaft sortiert werden.

Nun, lassen Sie uns die Methoden zum Empfangen von Auftragseigenschaften implementieren und sie in die Eigenschaftsarrays schreiben. Dies sind die Methoden, die zuvor im privaten Bereich deklariert wurden. Da die Methoden zum Empfangen von Ordnungseigenschaften plattformübergreifend sind, analysieren wir sie am Beispiel des erhalts der Magicnummer des EAs:

//+------------------------------------------------------------------+
//| Return magic number                                              |
//+------------------------------------------------------------------+
long COrder::OrderMagicNumber() const
  {
#ifdef __MQL4__
   return ::OrderMagicNumber();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_MAGIC);           break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_MAGIC);                 break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_MAGIC);   break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_MAGIC); break;
      default                             : res=0;                                              break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+

Wenn dies ein Code für MQL4 ist, wird die Magicnummer von der OrderMagicNumber() MQL5-Funktion zurückgegeben. Andernfalls wir der Auftragsstatus überprüft. Je nachdem, womit wir es zu tun haben, geben Sie entweder eine Position, eine Order oder eine magische Zahl zurück.

Die übrigen Methoden zum Lesen und Schreiben der Eigenschaften einer hervorgehobenen Order/Deal/Position werden auf die gleiche Weise durchgeführt. Sie können sie selbst analysieren.

Methoden zum Erhalt der ganzzahligen Eigenschaften von Auftrag/Deal/Position:
//+------------------------------------------------------------------+
//| Rückgabe des Tickets                                             |
//+------------------------------------------------------------------+
long COrder::OrderTicket(void) const
  {
#ifdef __MQL4__
   return ::OrderTicket();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     :
      case ORDER_STATUS_MARKET_PENDING    :
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     :
      case ORDER_STATUS_DEAL              : res=(long)m_ticket;                                 break;
      default                             : res=0;                                              break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Rückgabe des Tickets der Ober-Order                              |
//+------------------------------------------------------------------+
long COrder::OrderTicketFrom(void) const
  {
   long ticket=0;
#ifdef __MQL4__
   string order_comment=::OrderComment();
   if(::StringFind(order_comment,"from #")>WRONG_VALUE) ticket=::StringToInteger(::StringSubstr(order_comment,6));
#endif
   return ticket;
  }
//+------------------------------------------------------------------+
//| Rückgabe des Tickets der abgeleiteten Order                      |
//+------------------------------------------------------------------+
long COrder::OrderTicketTo(void) const
  {
   long ticket=0;
#ifdef __MQL4__
   string order_comment=::OrderComment();
   if(::StringFind(order_comment,"to #")>WRONG_VALUE) ticket=::StringToInteger(::StringSubstr(order_comment,4));
#endif
   return ticket;
  }
//+------------------------------------------------------------------+
//| Rückgabe der Positions-ID                                        |
//+------------------------------------------------------------------+
long COrder::OrderPositionID(void) const
  {
#ifdef __MQL4__
   return ::OrderMagicNumber();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_IDENTIFIER);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_POSITION_ID);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_POSITION_ID); break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_POSITION_ID);   break;
      default                             : res=0;                                                    break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Rückgabe des der entgegengesetzten Positions-ID                  |
//+------------------------------------------------------------------+
long COrder::OrderPositionByID(void) const
  {
#ifdef __MQL4__
   return 0;
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_POSITION_BY_ID);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_POSITION_BY_ID); break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Rückgabe der Zeit in Millisekunden                               |
//+------------------------------------------------------------------+
long COrder::OrderOpenTimeMSC(void) const
  {
#ifdef __MQL4__
   return (long)::OrderOpenTime();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_TIME_MSC);                 break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_TIME_SETUP_MSC);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TIME_SETUP_MSC); break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_TIME_MSC);         break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Rückgabe der Schlusszeit in Millisekunden                        |
//+------------------------------------------------------------------+
long COrder::OrderCloseTimeMSC(void) const
  {
#ifdef __MQL4__
   return (long)::OrderCloseTime();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TIME_DONE_MSC);     break;
      case ORDER_STATUS_DEAL              : res=(datetime)::HistoryDealGetInteger(m_ticket,DEAL_TIME_MSC);  break;
      default                             : res=0;                                                          break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Rückgabe des Typs                                                |
//+------------------------------------------------------------------+
long COrder::OrderType(void) const
  {
#ifdef __MQL4__
   return (long)::OrderType();
#else
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_TYPE);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_TYPE);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TYPE);  break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_TYPE);    break;
      default                             : res=0;                                              break;
     }
   return res;
#endif
  }
//+------------------------------------------------------------------+
//| Rückgabe des Typs auf Grund der Richtung                         |
//+------------------------------------------------------------------+
long COrder::OrderTypeByDirection(void) const
  {
   ENUM_ORDER_STATUS status=(ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS);
   if(status==ORDER_STATUS_MARKET_ACTIVE)
     {
      return(this.OrderType()==POSITION_TYPE_BUY ? ORDER_TYPE_BUY : ORDER_TYPE_SELL);
     }
   if(status==ORDER_STATUS_MARKET_PENDING || status==ORDER_STATUS_HISTORY_PENDING)
     {
      return
        (
         this.OrderType()==ORDER_TYPE_BUY_LIMIT || 
         this.OrderType()==ORDER_TYPE_BUY_STOP 
         #ifdef __MQL5__                        ||
         this.OrderType()==ORDER_TYPE_BUY_STOP_LIMIT 
         #endif ? 
         ORDER_TYPE_BUY : 
         ORDER_TYPE_SELL
        );
     }
   if(status==ORDER_STATUS_HISTORY_ORDER)
     {
      return this.OrderType();
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+
//| Rückgabe des Ausführungstyps des Restes                          |
//+------------------------------------------------------------------+
long COrder::OrderTypeFilling(void) const
  {
#ifdef __MQL4__
   return (long)ORDER_FILLING_RETURN;
#else 
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_TYPE_FILLING);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TYPE_FILLING);break;
      default                             : res=0;                                                    break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe der Laufzeit der Order                                  |
//+------------------------------------------------------------------+
long COrder::OrderTypeTime(void) const
  {
#ifdef __MQL4__
   return (long)ORDER_TIME_GTC;
#else 
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_TYPE_TIME);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_TYPE_TIME);break;
      default                             : res=0;                                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Grund oder Quelle der Order                                      |
//+------------------------------------------------------------------+
long COrder::OrderReason(void) const
  {
#ifdef __MQL4__
   return
     (
      this.OrderCloseByStopLoss()   ?  ORDER_REASON_SL      :
      this.OrderCloseByTakeProfit() ?  ORDER_REASON_TP      :  
      this.OrderMagicNumber()!=0    ?  ORDER_REASON_EXPERT  : WRONG_VALUE
     );
#else 
   long res=WRONG_VALUE;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_REASON);          break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_REASON);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_REASON);break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_REASON);  break;
      default                             : res=WRONG_VALUE;                                    break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Order, weswegen der Deal ausgeführt wurde                        |
//+------------------------------------------------------------------+
long COrder::DealOrder(void) const
  {
#ifdef __MQL4__
   return ::OrderTicket();
#else 
   long res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetInteger(POSITION_IDENTIFIER);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetInteger(ORDER_POSITION_ID);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetInteger(m_ticket,ORDER_POSITION_ID); break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetInteger(m_ticket,DEAL_ORDER);         break;
      default                             : res=0;                                                    break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Deal-Richtung IN, OUT, IN/OUT                                    |
//+------------------------------------------------------------------+
long COrder::DealEntry(void) const
  {
#ifdef __MQL4__
   return ::OrderType();
#else 
   long res=WRONG_VALUE;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_DEAL  : res=::HistoryDealGetInteger(m_ticket,DEAL_ENTRY);break;
      default                 : res=WRONG_VALUE;                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des Flags der Positionsschließung durch StopLoss        |
//+------------------------------------------------------------------+
bool COrder::OrderCloseByStopLoss(void) const
  {
#ifdef __MQL4__
   return(::StringFind(::OrderComment(),"[sl")>WRONG_VALUE);
#else 
   return
     (
      this.Status()==ORDER_STATUS_HISTORY_ORDER ? this.OrderReason()==ORDER_REASON_SL : 
      this.Status()==ORDER_STATUS_DEAL ? this.OrderReason()==DEAL_REASON_SL : false
     );
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des Flags der Positionsschließung durch TakeProfit      |
//+------------------------------------------------------------------+
bool COrder::OrderCloseByTakeProfit(void) const
  {
#ifdef __MQL4__
   return(::StringFind(::OrderComment(),"[tp")>WRONG_VALUE);
#else 
   return
     (
      this.Status()==ORDER_STATUS_HISTORY_ORDER ? this.OrderReason()==ORDER_REASON_TP : 
      this.Status()==ORDER_STATUS_DEAL ? this.OrderReason()==DEAL_REASON_TP : false
     );
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe der Eröffnungszeit                                      |
//+------------------------------------------------------------------+
datetime COrder::OrderOpenTime(void) const
  {
#ifdef __MQL4__
   return ::OrderOpenTime();
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=(datetime)::PositionGetInteger(POSITION_TIME);                 break;
      case ORDER_STATUS_MARKET_PENDING    : res=(datetime)::OrderGetInteger(ORDER_TIME_SETUP);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=(datetime)::HistoryOrderGetInteger(m_ticket,ORDER_TIME_SETUP); break;
      case ORDER_STATUS_DEAL              : res=(datetime)::HistoryDealGetInteger(m_ticket,DEAL_TIME);         break;
      default                             : res=0;                                                             break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe der Schlusszeit                                         |
//+------------------------------------------------------------------+
datetime COrder::OrderCloseTime(void) const
  {
#ifdef __MQL4__
   return ::OrderCloseTime();
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=(datetime)::HistoryOrderGetInteger(m_ticket,ORDER_TIME_DONE);  break;
      case ORDER_STATUS_DEAL              : res=(datetime)::HistoryDealGetInteger(m_ticket,DEAL_TIME);         break;
      default                             : res=0;                                                             break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe der Verfallszeit                                        |
//+------------------------------------------------------------------+
datetime COrder::OrderExpiration(void) const
  {
#ifdef __MQL4__
   return ::OrderExpiration();
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=(datetime)::OrderGetInteger(ORDER_TIME_EXPIRATION);                  break;
      case ORDER_STATUS_HISTORY_PENDING   : res=(datetime)::HistoryOrderGetInteger(m_ticket,ORDER_TIME_EXPIRATION);  break;
      default                             : res=0;                                                                   break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Zeit der Positionsänderung in Sekunden                           |
//+------------------------------------------------------------------+
datetime COrder::PositionTimeUpdate(void) const
  {
#ifdef __MQL4__
   return 0;
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE  : res=(datetime)::PositionGetInteger(POSITION_TIME_UPDATE); break;
      default                          : res=0;                                                    break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Zeit der Positionsänderung in Millisekunden                      |
//+------------------------------------------------------------------+
datetime COrder::PositionTimeUpdateMSC(void) const
  {
#ifdef __MQL4__
   return 0;
#else 
   datetime res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE  : res=(datetime)::PositionGetInteger(POSITION_TIME_UPDATE_MSC);break;
      default                          : res=0;                                                       break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Methoden zum Erhalt der Double-Eigenschaften von Auftrag/Deal/Position:

//+------------------------------------------------------------------+
//| Rückgabe des Eröffnungspreises                                   |
//+------------------------------------------------------------------+
double COrder::OrderOpenPrice(void) const
  {
#ifdef __MQL4__
   return ::OrderOpenPrice();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetDouble(POSITION_PRICE_OPEN);          break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_PRICE_OPEN);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_PRICE_OPEN);break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetDouble(m_ticket,DEAL_PRICE);       break;
      default                             : res=0;                                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des Schlusskurses                                       |
//+------------------------------------------------------------------+
double COrder::OrderClosePrice(void) const
  {
#ifdef __MQL4__
   return ::OrderClosePrice();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_PRICE_OPEN);break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetDouble(m_ticket,DEAL_PRICE);       break;
      default                             : res=0;                                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des Gewinns                                             |
//+------------------------------------------------------------------+
double COrder::OrderProfit(void) const
  {
#ifdef __MQL4__
   return ::OrderProfit();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE  : res=::PositionGetDouble(POSITION_PROFIT);        break;
      case ORDER_STATUS_DEAL           : res=::HistoryDealGetDouble(m_ticket,DEAL_PROFIT);break;
      default                          : res=0;                                           break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe der Kommission                                          |
//+------------------------------------------------------------------+
double COrder::OrderCommission(void) const
  {
#ifdef __MQL4__
   return ::OrderCommission();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_DEAL  : res=::HistoryDealGetDouble(m_ticket,DEAL_COMMISSION);  break;
      default                 : res=0;                                                 break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des Swap                                                |
//+------------------------------------------------------------------+
double COrder::OrderSwap(void) const
  {
#ifdef __MQL4__
   return ::OrderSwap();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE  : res=::PositionGetDouble(POSITION_SWAP);          break;
      case ORDER_STATUS_DEAL           : res=::HistoryDealGetDouble(m_ticket,DEAL_SWAP);  break;
      default                          : res=0;                                           break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des Volumens                                            |
//+------------------------------------------------------------------+
double COrder::OrderVolume(void) const
  {
#ifdef __MQL4__
   return ::OrderLots();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetDouble(POSITION_VOLUME);                    break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_VOLUME_INITIAL);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_VOLUME_INITIAL);  break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetDouble(m_ticket,DEAL_VOLUME);            break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des nicht ausgeführten Volumens                         |
//+------------------------------------------------------------------+
double COrder::OrderVolumeCurrent(void) const
  {
#ifdef __MQL4__
   return ::OrderLots();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_VOLUME_CURRENT);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_VOLUME_CURRENT);  break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des StopLoss                                            |
//+------------------------------------------------------------------+
double COrder::OrderStopLoss(void) const
  {
#ifdef __MQL4__
   return ::OrderStopLoss();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetDouble(POSITION_SL);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_SL);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_SL);  break;
      default                             : res=0;                                           break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des TakeProfit                                          |
//+------------------------------------------------------------------+
double COrder::OrderTakeProfit(void) const
  {
#ifdef __MQL4__
   return ::OrderTakeProfit();
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetDouble(POSITION_TP);            break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_TP);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_TP);  break;
      default                             : res=0;                                           break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des Preises der Limit-Order                             |
//| Wenn eine StopLimit-Order aktiviert ist                          |
//+------------------------------------------------------------------+
double COrder::OrderPriceStopLimit(void) const
  {
#ifdef __MQL4__
   return 0;
#else 
   double res=0;
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetDouble(ORDER_PRICE_STOPLIMIT);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetDouble(m_ticket,ORDER_PRICE_STOPLIMIT); break;
      default                             : res=0;                                                       break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Methoden zum Erhalt der Zeichenketten-Eigenschaften von Ordnung, Handel und Position:

//+------------------------------------------------------------------+
//| Rückgabe des Symbols                                             |
//+------------------------------------------------------------------+
string COrder::OrderSymbol(void) const
  {
#ifdef __MQL4__
   return ::OrderSymbol();
#else 
   string res="";
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetString(POSITION_SYMBOL);           break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetString(ORDER_SYMBOL);                 break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetString(m_ticket,ORDER_SYMBOL); break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetString(m_ticket,DEAL_SYMBOL);   break;
      default                             : res="";                                             break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe des Kommentars                                          |
//+------------------------------------------------------------------+
string COrder::OrderComment(void) const
  {
#ifdef __MQL4__
   return ::OrderComment();
#else 
   string res="";
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_ACTIVE     : res=::PositionGetString(POSITION_COMMENT);          break;
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetString(ORDER_COMMENT);                break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetString(m_ticket,ORDER_COMMENT);break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetString(m_ticket,DEAL_COMMENT);  break;
      default                             : res="";                                             break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+
//| Rückgabe der ID, die der Börsenplatz verwendet                   |
//+------------------------------------------------------------------+
string COrder::OrderExternalID(void) const
  {
#ifdef __MQL4__
   return "";
#else 
   string res="";
   switch((ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS))
     {
      case ORDER_STATUS_MARKET_PENDING    : res=::OrderGetString(ORDER_EXTERNAL_ID);                  break;
      case ORDER_STATUS_HISTORY_PENDING   :
      case ORDER_STATUS_HISTORY_ORDER     : res=::HistoryOrderGetString(m_ticket,ORDER_EXTERNAL_ID);  break;
      case ORDER_STATUS_DEAL              : res=::HistoryDealGetString(m_ticket,DEAL_EXTERNAL_ID);    break;
      default                             : res="";                                                   break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Wir haben die 'private' Methoden zur Übernahme von Eigenschaften aus den Auftragsdaten deklariert und implementiert.

Jetzt ist es an der Zeit, den 'protected' Klassenkonstruktor zu implementieren, indem wir ihm mit Methoden versehen, die alle Eigenschaften der Order speichern, deren Ticket an den Konstruktor übergeben wurde.

Implementierung des Konstruktors der 'protected' Klasse:

//+------------------------------------------------------------------+
//| Closed parametric constructor                                    |
//+------------------------------------------------------------------+
COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket)
  {
//--- Sichern der ganzzahligen Eigenschaften
   m_ticket=ticket;
   m_long_prop[ORDER_PROP_STATUS]                              = order_status;
   m_long_prop[ORDER_PROP_MAGIC]                               = this.OrderMagicNumber();
   m_long_prop[ORDER_PROP_TICKET]                              = this.OrderTicket();
   m_long_prop[ORDER_PROP_TIME_OPEN]                           = (long)(ulong)this.OrderOpenTime();
   m_long_prop[ORDER_PROP_TIME_CLOSE]                          = (long)(ulong)this.OrderCloseTime();
   m_long_prop[ORDER_PROP_TIME_EXP]                            = (long)(ulong)this.OrderExpiration();
   m_long_prop[ORDER_PROP_TYPE]                                = this.OrderType();
   m_long_prop[ORDER_PROP_DIRECTION]                           = this.OrderTypeByDirection();
   m_long_prop[ORDER_PROP_POSITION_ID]                         = this.OrderPositionID();
   m_long_prop[ORDER_PROP_REASON]                              = this.OrderReason();
   m_long_prop[ORDER_PROP_DEAL_ORDER]                          = this.DealOrder();
   m_long_prop[ORDER_PROP_DEAL_ENTRY]                          = this.DealEntry();
   m_long_prop[ORDER_PROP_POSITION_BY_ID]                      = this.OrderPositionByID();
   m_long_prop[ORDER_PROP_TIME_OPEN_MSC]                       = this.OrderOpenTimeMSC();
   m_long_prop[ORDER_PROP_TIME_CLOSE_MSC]                      = this.OrderCloseTimeMSC();
   m_long_prop[ORDER_PROP_TIME_UPDATE]                         = (long)(ulong)this.PositionTimeUpdate();
   m_long_prop[ORDER_PROP_TIME_UPDATE_MSC]                     = (long)(ulong)this.PositionTimeUpdateMSC();
   
//--- Sichern der Double-Eigenschaften
   m_double_prop[this.IndexProp(ORDER_PROP_PRICE_OPEN)]        = this.OrderOpenPrice();
   m_double_prop[this.IndexProp(ORDER_PROP_PRICE_CLOSE)]       = this.OrderClosePrice();
   m_double_prop[this.IndexProp(ORDER_PROP_PROFIT)]            = this.OrderProfit();
   m_double_prop[this.IndexProp(ORDER_PROP_COMMISSION)]        = this.OrderCommission();
   m_double_prop[this.IndexProp(ORDER_PROP_SWAP)]              = this.OrderSwap();
   m_double_prop[this.IndexProp(ORDER_PROP_VOLUME)]            = this.OrderVolume();
   m_double_prop[this.IndexProp(ORDER_PROP_SL)]                = this.OrderStopLoss();
   m_double_prop[this.IndexProp(ORDER_PROP_TP)]                = this.OrderTakeProfit();
   m_double_prop[this.IndexProp(ORDER_PROP_VOLUME_CURRENT)]    = this.OrderVolumeCurrent();
   m_double_prop[this.IndexProp(ORDER_PROP_PRICE_STOP_LIMIT)]  = this.OrderPriceStopLimit();
   
//--- Sichern der String-Eigenschaften
   m_string_prop[this.IndexProp(ORDER_PROP_SYMBOL)]            = this.OrderSymbol();
   m_string_prop[this.IndexProp(ORDER_PROP_COMMENT)]           = this.OrderComment();
   m_string_prop[this.IndexProp(ORDER_PROP_EXT_ID)]            = this.OrderExternalID();
   
//--- Sichern weiterer ganzzahliger Eigenschaften
   m_long_prop[ORDER_PROP_PROFIT_PT]                           = this.ProfitInPoints();
   m_long_prop[ORDER_PROP_TICKET_FROM]                         = this.OrderTicketFrom();
   m_long_prop[ORDER_PROP_TICKET_TO]                           = this.OrderTicketTo();
   m_long_prop[ORDER_PROP_CLOSE_BY_SL]                         = this.OrderCloseByStopLoss();
   m_long_prop[ORDER_PROP_CLOSE_BY_TP]                         = this.OrderCloseByTakeProfit();
   
//--- Sichern weiterer Double-Eigenschaften
   m_double_prop[this.IndexProp(ORDER_PROP_PROFIT_FULL)]       = this.ProfitFull();
  }
//+------------------------------------------------------------------+

Wenn wir die Historie durchgehen, oder Marktorders/Deals/Positionen in einer Schleife übergeben, oder eine neue Order/Deal/Position auswählen, wird ein neues Objekt der Klasse COrder angelegt. Der Klassenkonstruktor mit Auftragsstatus und Ticket wird aufgerufen, wenn der Klassenkonstruktor nur das Auftragsticket erhält. Anschließend werden die Arrays mit den Order-Eigenschaften im Konstruktor der Klasse COrder mit den oben beschriebenen Methoden einfach gefüllt.

So soll jede neue Order/Deal/Position ihre einzigartige Eigenschaft haben. Alle sind in den Listen zu speichern, während die Arbeit mit solchen Listen die Haupttätigkeit der Bibliothek ist. Die Listen können nach jeder Eigenschaften von Order/Deal/Position sortiert werden. Außerdem ist es möglich, aus den ausgewählten Listen neue Listen zu generieren.

In dieser Phase wurde die Grundfunktionalität der abstrakten Auftragsklasse COrder implementiert. Dies ist eine Basisklasse zur Speicherung verschiedener Arten von Aufträgen, Deals und Positionen. Alle anderen werden daraus abgeleitet, um Objekte zu erstellen, die nach Arten von Aufträgen, Deals und Positionen unterteilt sind.

Die Bibliothek ist für einen vereinfachten Zugriff auf Daten und eine einfache Programmentwicklung konzipiert.
Im aktuellen Zustand haben wir drei 'public' Methoden für den Zugriff auf die Eigenschaften der abstrakten Order GetProperty(XXX). Sie können sie verwenden, aber das ist nicht sehr praktisch, da Sie sich die Mitgliedsnamen der Aufzählungen merken müssen, die eine bestimmte Ordnungseigenschaft beschreiben. Daher werden wir mehrere weitere öffentliche Methoden hinzufügen, um die benötigten Daten zu erhalten. Diese Methoden werden sprechende Namen haben, so dass sofort klar ist, welche Eigenschaft durch die Verwendung einer bestimmten Methode erhalten werden kann.

Diese Methoden können in nutzerdefinierten Programmen verwendet werden, um die Eigenschaften eines ausgewählten Auftrags, Deals oder einer Position zu lesen:
   //--- Return (1) ticket, (2) parent order ticket, (3) derived order ticket, (4) magic number, (5) order reason (6) position ID
   //--- (7) ID der entgegengesetzten Position, (8) Flag für ein Schließen durch StopLoss, (9) Flag für ein Schließen durch TakeProfit (10) Eröffnungszeit, (11) Schlusszeit,
   //--- (12) Eröffnungszeit in Millisekunden, (13) Schlusszeit in Millisekunden, (14) Verfallszeit, (15) Typ, (16) Status, (17) Richtung
   long              Ticket(void)                                       const { return this.GetProperty(ORDER_PROP_TICKET);                     }
   long              TicketFrom(void)                                   const { return this.GetProperty(ORDER_PROP_TICKET_FROM);                }
   long              TicketTo(void)                                     const { return this.GetProperty(ORDER_PROP_TICKET_TO);                  }
   long              Magic(void)                                        const { return this.GetProperty(ORDER_PROP_MAGIC);                      }
   long              Reason(void)                                       const { return this.GetProperty(ORDER_PROP_REASON);                     }
   long              PositionID(void)                                   const { return this.GetProperty(ORDER_PROP_POSITION_ID);                }
   long              PositionByID(void)                                 const { return this.GetProperty(ORDER_PROP_POSITION_BY_ID);             }
   bool              IsCloseByStopLoss(void)                            const { return (bool)this.GetProperty(ORDER_PROP_CLOSE_BY_SL);          }
   bool              IsCloseByTakeProfit(void)                          const { return (bool)this.GetProperty(ORDER_PROP_CLOSE_BY_TP);          }
   datetime          TimeOpen(void)                                     const { return (datetime)this.GetProperty(ORDER_PROP_TIME_OPEN);        }
   datetime          TimeClose(void)                                    const { return (datetime)this.GetProperty(ORDER_PROP_TIME_CLOSE);       }
   datetime          TimeOpenMSC(void)                                  const { return (datetime)this.GetProperty(ORDER_PROP_TIME_OPEN_MSC);    }
   datetime          TimeCloseMSC(void)                                 const { return (datetime)this.GetProperty(ORDER_PROP_TIME_CLOSE_MSC);   }
   datetime          TimeExpiration(void)                               const { return (datetime)this.GetProperty(ORDER_PROP_TIME_EXP);         }
   ENUM_ORDER_TYPE   TypeOrder(void)                                    const { return (ENUM_ORDER_TYPE)this.GetProperty(ORDER_PROP_TYPE);      }
   ENUM_ORDER_STATUS Status(void)                                       const { return (ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS);  }
   ENUM_ORDER_TYPE   TypeByDirection(void)                              const { return (ENUM_ORDER_TYPE)this.GetProperty(ORDER_PROP_DIRECTION); }
   
   //--- Rückgabe von (1) Eröffnungspreis, (2) Schlusskurs, (3) Gewinn, (4) Kommission, (5) Swap, (6) Volumen, 
   //--- (7) nicht ausgeführtes Volumen, (8) StopLoss und (9) TakeProfit, (10) Preis der StopLimit-Oorder
   double            PriceOpen(void)                                    const { return this.GetProperty(ORDER_PROP_PRICE_OPEN);                 }
   double            PriceClose(void)                                   const { return this.GetProperty(ORDER_PROP_PRICE_CLOSE);                }
   double            Profit(void)                                       const { return this.GetProperty(ORDER_PROP_PROFIT);                     }
   double            Comission(void)                                    const { return this.GetProperty(ORDER_PROP_COMMISSION);                 }
   double            Swap(void)                                         const { return this.GetProperty(ORDER_PROP_SWAP);                       }
   double            Volume(void)                                       const { return this.GetProperty(ORDER_PROP_VOLUME);                     }
   double            VolumeCurrent(void)                                const { return this.GetProperty(ORDER_PROP_VOLUME_CURRENT);             }
   double            StopLoss(void)                                     const { return this.GetProperty(ORDER_PROP_SL);                         }
   double            TakeProfit(void)                                   const { return this.GetProperty(ORDER_PROP_TP);                         }
   double            PriceStopLimit(void)                               const { return this.GetProperty(ORDER_PROP_PRICE_STOP_LIMIT);           }
   
   //--- Rückgabe von (1) Symbol, (2) Kommentar, (3) ID des Börsenplatzes
   string            Symbol(void)                                       const { return this.GetProperty(ORDER_PROP_SYMBOL);                     }
   string            Comment(void)                                      const { return this.GetProperty(ORDER_PROP_COMMENT);                    }
   string            ExternalID(void)                                   const { return this.GetProperty(ORDER_PROP_EXT_ID);                     }

   //--- Gesamter Gewinn der Order
   double            ProfitFull(void)                                   const { return this.Profit()+this.Comission()+this.Swap();              }
   //--- Gesamter Gewinn der Order in Points
   int               ProfitInPoints(void) const;

Die Methode, die den Gewinn in Points ermittelt:

//+------------------------------------------------------------------+
//| Rückgabe des Gewinns der Order in Points                         |
//+------------------------------------------------------------------+
int COrder::ProfitInPoints(void) const
  {
   ENUM_ORDER_TYPE type=this.TypeOrder();
   string symbol=this.Symbol();
   double point=::SymbolInfoDouble(symbol,SYMBOL_POINT);
   if(type>ORDER_TYPE_SELL || point==0) return 0;
   if(this.Status()==ORDER_STATUS_HISTORY_ORDER)
      return int(type==ORDER_TYPE_BUY ? (this.PriceClose()-this.PriceOpen())/point : type==ORDER_TYPE_SELL ? (this.PriceOpen()-this.PriceClose())/point : 0);
   else if(this.Status()==ORDER_STATUS_MARKET_ACTIVE)
     {
      if(type==ORDER_TYPE_BUY)
         return int((::SymbolInfoDouble(symbol,SYMBOL_BID)-this.PriceOpen())/point);
      else if(type==ORDER_TYPE_SELL)
         return int((this.PriceOpen()-::SymbolInfoDouble(symbol,SYMBOL_ASK))/point);
     }
   return 0;
  }
//+------------------------------------------------------------------+

Fügen wir noch 'public' Methoden hinzu, um einige Eigenschaften des Order-Objekts zu beschreiben, so dass wir sie bei Bedarf auf bequeme Weise anzeigen können:

   //--- Abrufen der Beschreibung der Order (1) Integer-, (2) Double- und (3) String-Eigenschaft
   string            GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_ORDER_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_ORDER_PROP_STRING property);
   //--- Rückgabe des Namens des Order-Status
   string            StatusDescription(void) const;
   //--- Rückgabe des Namens der Order oder Position
   string            TypeDescription(void) const;
   //--- Rückgabe des Namens der Richtung des Deals
   string            DealEntryDescription(void) const;
   //--- Rückgabe der Richtung von Order/Position
   string            DirectionDescription(void) const;
   //--- Senden der Eigenschaften der Order an das Journal (full_prop=true - alle Eigenschaften, false - nur die unterstützten)
   void              Print(const bool full_prop=false);

Bevor wir diese Methoden implementieren, werden wir noch ein weiteres Problem lösen: Die Bibliothek und die darauf basierenden Programme benötigen verschiedene Servicefunktionen. Zum Beispiel benötigen wir für diesen Fall die Funktion der Anzeige der Zeit in Millisekunden und die Funktion des Empfangs von Nachrichten in einer von zwei Sprachen. Die Sprache der Meldungen soll von der Terminalsprache abhängen.

Erstellen einer neuen Include-Datei im Stammverzeichnis der Bibliothek


und nennen sie DELib. Dies wird die Bibliotheksdatei der Servicefunktionen sein, die sowohl den Bibliotheksklassen selbst als auch den bibliotheksbasierten Programmen zur Verfügung stehen.


Klicken Sie auf Fertig stellen, um eine Vorlagendatei zu erstellen:

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
//+------------------------------------------------------------------+
//| Definitionen                                                     |
//+------------------------------------------------------------------+
// #define MacrosHello   "Hello, world!"
// #define MacrosYear    2010
//+------------------------------------------------------------------+
//| DLL importieren                                                  |
//+------------------------------------------------------------------+
// #import "user32.dll"
//   int      SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
//   int      ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 importieren                                                  |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
//   string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+

Binden wir die Datei Defines.mqh ein und ändern die Vorlage entsprechend unsren Notwendigkeiten

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property strict  // Notwendig für mql4
//+------------------------------------------------------------------+
//| Include-Dateien                                                  |
//+------------------------------------------------------------------+
#include "Defines.mqh"
//+------------------------------------------------------------------+
//| Service-Funktionen                                               |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+

Da wir Defines.mqh in diese Datei eingebunden haben, können wir diese neue Datei (und nicht Defines.mqh) in die Klassendatei COrder einbinden, so dass beide in der Bibliothek verfügbar sind. Außerdem werden wir es in einer Zeichenkette tun, nicht in zwei.
Ersetzen wir noch die Include-Anweisung in der Datei Order.mqh
:

//+------------------------------------------------------------------+
//|                                                        Order.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#include <Object.mqh>
#include "..\DELib.mqh"
//+------------------------------------------------------------------+
//| Abstract order class                                             |
//+------------------------------------------------------------------+

Ergänzen wir also auch die Landessprache des Nutzers als Makro-Substitution in der Datei Defines.mqh:

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
//+------------------------------------------------------------------+
//| Macro-Substitution                                               |
//+------------------------------------------------------------------+
#define COUNTRY_LANG    "Russian"
//+------------------------------------------------------------------+

So kann der Nutzer seine Muttersprache für angezeigte Nachrichten einstellen, wenn die Terminalsprache nicht Englisch ist. Um dies zu erreichen, müssen wir jedoch alle zukünftigen Nachrichten, die wir hier eingeben werden, durch die vom Benutzer gewünschten ersetzen.

Fügen wir die Funktion für die Rückgabe der einen von zwei Sprachen in der Datei DELib.mqh hinzu:

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property strict  // Notwendig für mql4
//+------------------------------------------------------------------+
//| Include-Dateien                                                  |
//+------------------------------------------------------------------+
#include "Defines.mqh"
//+------------------------------------------------------------------+
//| Service-Funktionen                                               |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Rückgabe des Textes in einer der beiden Sprachen                 |
//+------------------------------------------------------------------+
string TextByLanguage(const string text_country_lang,const string text_en)
  {
   return(TerminalInfoString(TERMINAL_LANGUAGE)==COUNTRY_LANG ? text_country_lang : text_en);
  }
//+------------------------------------------------------------------+

Die Funktion prüft die Terminalsprache und wenn sie mit den in der Makro-Substitution COUNTRY_LANG angegebenen Sprachen übereinstimmt, wird der Text in der Sprache des ersten Funktionsparameters angezeigt. Andernfalls wird der Text in der Sprache des zweiten Funktionsparameters (Englisch) angezeigt.

Fügen wir auch die Funktion hinzu, um die Millisekunden der Zeit anzuzeigen:

//+------------------------------------------------------------------+
//|                                                        DELib.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property strict  // Notwendig für mql4
//+------------------------------------------------------------------+
//| Include-Datei                                                    |
//+------------------------------------------------------------------+
#include "Defines.mqh"
//+------------------------------------------------------------------+
//| Service-Funktionen                                               |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Rückgabe des Textes in einer der beiden Sprachen                 |
//+------------------------------------------------------------------+
string TextByLanguage(const string text_country_lang,const string text_en)
  {
   return(TerminalInfoString(TERMINAL_LANGUAGE)==COUNTRY_LANG ? text_country_lang : text_en);
  }
//+------------------------------------------------------------------+
//| Rückgabe der Zeit in Millisekunden                               |
//+------------------------------------------------------------------+
string TimeMSCtoString(const long time_msc)
  {
   return TimeToString(time_msc/1000,TIME_DATE|TIME_MINUTES|TIME_SECONDS)+"."+IntegerToString(time_msc%1000,3,'0');
  }
//+------------------------------------------------------------------+

Hier ist alles ganz einfach: Die Zeit in Millisekunden wird der Funktion übergeben. Um die Zeit in Sekunden zu berechnen, müssen wir den der Funktion übergebenen Wert durch 1000 teilen. Um die Millisekunden zu berechnen, verwenden Sie den Rest dieser Division. Alle empfangenen Werte werden als Zeichenketten formatiert und an das aufrufende Programm zurückgegeben.

Manchmal kann es sinnvoll sein, die Anzahl der Dezimalstellen der Losgröße eines Symbols zu ermitteln. Lassen Sie uns diese Funktion in unsere Datei der Servicefunktionen aufnehmen:

//+------------------------------------------------------------------+
//| Rückgabe der Anzahl der Dezimalstellen der Losgröße des Symbols  |
//+------------------------------------------------------------------+
uint DigitsLots(const string symbol_name) 
  { 
   return (int)ceil(fabs(log(SymbolInfoDouble(symbol_name,SYMBOL_VOLUME_STEP))/log(10)));
  }
//+------------------------------------------------------------------+

Zusätzlich zu den Servicefunktionen benötigen wir drei Methoden, die den Auftragsgrund, die Richtung und die Geschäftsart zurückgeben, um Nachrichten im Journal anzuzeigen. Wir fügen die drei Methoden dem 'protected' Teil der Klasse COrder hinzu:

   //--- Rückgabe von (1) Grund, (2) Richtung, (3) Deal-Typ
   string            GetReasonDescription(const long reason)            const;
   string            GetEntryDescription(const long deal_entry)         const;
   string            GetTypeDealDescription(const long type_deal)       const;

Und die Umsetzung

//+------------------------------------------------------------------+
//| Grund                                                            |
//+------------------------------------------------------------------+
string COrder::GetReasonDescription(const long reason) const
  {
#ifdef __MQL4__
   return
     (
      this.IsCloseByStopLoss()            ?  TextByLanguage("Срабатывание StopLoss","Due to StopLoss")                  :
      this.IsCloseByTakeProfit()          ?  TextByLanguage("Срабатывание TakeProfit","Due to TakeProfit")              :
      this.Reason()==ORDER_REASON_EXPERT  ?  TextByLanguage("Выставлен из mql4-программы","Placed from mql4 program")   :
      TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4")
     );
#else 
   string res="";
   switch(this.Status())
     {
      case ORDER_STATUS_MARKET_ACTIVE        : 
         res=
           (
            reason==POSITION_REASON_CLIENT   ?  TextByLanguage("Позиция открыта из десктопного терминала","Position opened from desktop terminal") :
            reason==POSITION_REASON_MOBILE   ?  TextByLanguage("Позиция открыта из мобильного приложения","Position opened from mobile app") :
            reason==POSITION_REASON_WEB      ?  TextByLanguage("Позиция открыта из веб-платформы","Position opened from web platform") :
            reason==POSITION_REASON_EXPERT   ?  TextByLanguage("Позиция открыта из советника или скрипта","Position opened from EA or script") : ""
           );
         break;
      case ORDER_STATUS_MARKET_PENDING       :
      case ORDER_STATUS_HISTORY_PENDING      : 
      case ORDER_STATUS_HISTORY_ORDER        : 
         res=
           (
            reason==ORDER_REASON_CLIENT      ?  TextByLanguage("Ордер выставлен из десктопного терминала","Order set from desktop terminal") :
            reason==ORDER_REASON_MOBILE      ?  TextByLanguage("Ордер выставлен из мобильного приложения","Order set from mobile app") :
            reason==ORDER_REASON_WEB         ?  TextByLanguage("Ордер выставлен из веб-платформы","Oder set from web platform") :
            reason==ORDER_REASON_EXPERT      ?  TextByLanguage("Ордер выставлен советником или скриптом","Order set from EA or script") :
            reason==ORDER_REASON_SL          ?  TextByLanguage("Срабатывание StopLoss","Due to StopLoss") :
            reason==ORDER_REASON_TP          ?  TextByLanguage("Срабатывание TakeProfit","Due to TakeProfit") :
            reason==ORDER_REASON_SO          ?  TextByLanguage("Ордер выставлен в результате наступления Stop Out","Due to Stop Out") : ""
           );
         break;
      case ORDER_STATUS_DEAL                 : 
         res=
           (
            reason==DEAL_REASON_CLIENT       ?  TextByLanguage("Сделка проведена из десктопного терминала","Deal carried out from desktop terminal") :
            reason==DEAL_REASON_MOBILE       ?  TextByLanguage("Сделка проведена из мобильного приложения","Deal carried out from mobile app") :
            reason==DEAL_REASON_WEB          ?  TextByLanguage("Сделка проведена из веб-платформы","Deal carried out from web platform") :
            reason==DEAL_REASON_EXPERT       ?  TextByLanguage("Сделка проведена из советника или скрипта","Deal carried out from EA or script") :
            reason==DEAL_REASON_SL           ?  TextByLanguage("Срабатывание StopLoss","Due to StopLoss") :
            reason==DEAL_REASON_TP           ?  TextByLanguage("Срабатывание TakeProfit","Due to TakeProfit") :
            reason==DEAL_REASON_SO           ?  TextByLanguage("Сделка проведена в результате наступления Stop Out","Due to Stop Out") :
            reason==DEAL_REASON_ROLLOVER     ?  TextByLanguage("Сделка проведена по причине переноса позиции","Due to position rollover") :
            reason==DEAL_REASON_VMARGIN      ?  TextByLanguage("Сделка проведена по причине начисления/списания вариационной маржи","Due to variation margin") :
            reason==DEAL_REASON_SPLIT        ?  TextByLanguage("Сделка проведена по причине сплита (понижения цены) инструмента","Due to split") : ""
           );
         break;
      default                                : res="";   break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Die Zugehörigkeit zu MQL4 oder MQL5 wird überprüft, der in den Eingaben übergebene Auftragsgrund wird entsprechend dem Auftragsstatus verifiziert und seine Beschreibung wird zurückgegeben.

//+------------------------------------------------------------------+
//| Beschreibung der Richtung des Deals                              |
//+------------------------------------------------------------------+
string COrder::GetEntryDescription(const long deal_entry) const
  {
#ifdef __MQL4__
   return TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4");
#else 
   string res="";
   switch(this.Status())
     {
      case ORDER_STATUS_MARKET_ACTIVE     : 
         res=TextByLanguage("Свойство не поддерживается у позиции","Property not supported for position"); 
         break;
      case ORDER_STATUS_MARKET_PENDING    :
      case ORDER_STATUS_HISTORY_PENDING   : 
         res=TextByLanguage("Свойство не поддерживается у отложенного ордера","Property not supported for pending order"); 
         break;
      case ORDER_STATUS_HISTORY_ORDER     : 
         res=TextByLanguage("Свойство не поддерживается у исторического ордера","Property not supported for history order"); 
         break;
      case ORDER_STATUS_DEAL              : 
         res=
           (
            deal_entry==DEAL_ENTRY_IN     ?  TextByLanguage("Вход в рынок","Entry to the market") :
            deal_entry==DEAL_ENTRY_OUT    ?  TextByLanguage("Выход из рынка","Out from the market") :
            deal_entry==DEAL_ENTRY_INOUT  ?  TextByLanguage("Разворот","Reversal") :
            deal_entry==DEAL_ENTRY_OUT_BY ?  TextByLanguage("Закрытие встречной позицией","Closing by opposite position") : ""
           );
         break;
      default                             : res=""; break;
     }
   return res;
#endif 
  }
//+------------------------------------------------------------------+

Die Zugehörigkeit zu MQL4 oder MQL5 wird überprüft, die Richtung des Deals in den Eingaben gemäß dem Auftragsstatus verifiziert und seine Beschreibung wird zurückgegeben.

//+------------------------------------------------------------------+
//| Rückgabe des Namens des Deal-Typs                                |
//+------------------------------------------------------------------+
string COrder::GetTypeDealDescription(const long deal_type) const
  {
#ifdef __MQL4__
   return TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4");
#else 
   string res="";
   switch(this.Status())
     {
      case ORDER_STATUS_MARKET_ACTIVE     : 
         res=TextByLanguage("Свойство не поддерживается у позиции","Property not supported for position"); 
         break;
      case ORDER_STATUS_MARKET_PENDING    :
      case ORDER_STATUS_HISTORY_PENDING   : 
         res=TextByLanguage("Свойство не поддерживается у отложенного ордера","Property not supported for pending order"); 
         break;
      case ORDER_STATUS_HISTORY_ORDER     : 
         res=TextByLanguage("Свойство не поддерживается у исторического ордера","Property not supported for history order"); 
         break;
      case ORDER_STATUS_DEAL              : 
         res=
           (
            deal_type==DEAL_TYPE_BUY                      ?  TextByLanguage("Сделка на покупку","Buy deal") :
            deal_type==DEAL_TYPE_SELL                     ?  TextByLanguage("Сделка на продажу","Sell deal") :
            deal_type==DEAL_TYPE_BALANCE                  ?  TextByLanguage("Начисление баланса","Balance accrual") :
            deal_type==DEAL_TYPE_CREDIT                   ?  TextByLanguage("Начисление кредита","Credit accrual") :
            deal_type==DEAL_TYPE_CHARGE                   ?  TextByLanguage("Дополнительные сборы","Extra charges") :
            deal_type==DEAL_TYPE_CORRECTION               ?  TextByLanguage("Корректирующая запись","Corrective entry") :
            deal_type==DEAL_TYPE_BONUS                    ?  TextByLanguage("Перечисление бонусов","Bonuses") :
            deal_type==DEAL_TYPE_COMMISSION               ?  TextByLanguage("Дополнительные комиссии","Additional comissions") :
            deal_type==DEAL_TYPE_COMMISSION_DAILY         ?  TextByLanguage("Комиссия, начисляемая в конце торгового дня","Commission accrued at the end of a trading day") :
            deal_type==DEAL_TYPE_COMMISSION_MONTHLY       ?  TextByLanguage("Комиссия, начисляемая в конце месяца","Commission accrued at the end of a month") :
            deal_type==DEAL_TYPE_COMMISSION_AGENT_DAILY   ?  TextByLanguage("Агентская комиссия, начисляемая в конце торгового дня","Agency commission charged at the end of a trading day") :
            deal_type==DEAL_TYPE_COMMISSION_AGENT_MONTHLY ?  TextByLanguage("Агентская комиссия, начисляемая в конце месяца","Agency commission charged at the end of a month") :
            deal_type==DEAL_TYPE_INTEREST                 ?  TextByLanguage("Начисления процентов на свободные средства","Accrued interest on free funds") :
            deal_type==DEAL_TYPE_BUY_CANCELED             ?  TextByLanguage("Отмененная сделка покупки","Canceled buy transaction") :
            deal_type==DEAL_TYPE_SELL_CANCELED            ?  TextByLanguage("Отмененная сделка продажи","Canceled sell transaction") :
            deal_type==DEAL_DIVIDEND                      ?  TextByLanguage("Начисление дивиденда","Accrued dividends") :
            deal_type==DEAL_DIVIDEND_FRANKED              ?  TextByLanguage("Начисление франкированного дивиденда","Accrual of franked dividend") :
            deal_type==DEAL_TAX                           ?  TextByLanguage("Начисление налога","Tax accrual") : ""
           );
         break;
      default                             : res=""; break;
     }
   return res;
#endif 
  }

Die Zugehörigkeit zu MQL4 oder MQL5 wird überprüft, der Typ des Deals in den Eingaben gemäß dem Auftragsstatus verifiziert und seine Beschreibung wird zurückgegeben.

Die Methode für die Beschreibung der Auftragseigenschaften

//+------------------------------------------------------------------+
//| Rückgabe der Beschreibung der ganzzahligen Eigenschaft der Order |
//+------------------------------------------------------------------+
string COrder::GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property)
  {
   return
     (
   //--- Allgemeine Eigenschaften
      property==ORDER_PROP_MAGIC             ?  TextByLanguage("Магик","Magic")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET            ?  TextByLanguage("Тикет","Ticket")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_FROM       ?  TextByLanguage("Тикет родительского ордера","Ticket of parent order")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TICKET_TO         ?  TextByLanguage("Тикет наследуемого ордера","Inherited order ticket")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          " #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_OPEN         ?  TextByLanguage("Время открытия","Open time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==ORDER_PROP_TIME_CLOSE        ?  TextByLanguage("Время закрытия","Close time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)
         )  :
      property==ORDER_PROP_TIME_EXP          ?  TextByLanguage("Дата экспирации","Expiration date")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          (this.GetProperty(property)==0     ?  TextByLanguage(": Не задана",": Not set") :
          ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS))
         )  :
      property==ORDER_PROP_TYPE              ?  TextByLanguage("Тип","Type")+": "+this.TypeDescription()                   :
      property==ORDER_PROP_DIRECTION         ?  TextByLanguage("Тип по направлению","Type by direction")+": "+this.DirectionDescription() :
      
      property==ORDER_PROP_REASON            ?  TextByLanguage("Причина","Reason")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetReasonDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_ID       ?  TextByLanguage("Идентификатор позиции","Position ID")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ORDER        ?  TextByLanguage("Сделка на основании ордера","Deal by order")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": #"+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_DEAL_ENTRY        ?  TextByLanguage("Направление сделки","Deal direction")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+this.GetEntryDescription(this.GetProperty(property))
         )  :
      property==ORDER_PROP_POSITION_BY_ID    ?  TextByLanguage("Идентификатор встречной позиции","Opposite position ID")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_TIME_OPEN_MSC     ?  TextByLanguage("Время открытия в милисекундах","Open time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property))
         )  :
      property==ORDER_PROP_TIME_CLOSE_MSC    ?  TextByLanguage("Время закрытия в милисекундах","Close time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property))
         )  :
      property==ORDER_PROP_TIME_UPDATE       ?  TextByLanguage("Время изменения позиции","Position change time")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)!=0 ? ::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS) : "0")
         )  :
      property==ORDER_PROP_TIME_UPDATE_MSC   ?  TextByLanguage("Время изменения позиции в милисекундах","Position change time in milliseconds")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property)!=0 ? (string)this.GetProperty(property)+" > "+TimeMSCtoString(this.GetProperty(property)) : "0")
         )  :
   //--- Zusätzliche Eigenschaften
      property==ORDER_PROP_STATUS            ?  TextByLanguage("Статус","Status")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": \""+this.StatusDescription()+"\""
         )  :
      property==ORDER_PROP_PROFIT_PT         ?  TextByLanguage("Прибыль в пунктах","Profit in points")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==ORDER_PROP_CLOSE_BY_SL       ?  TextByLanguage("Закрытие по StopLoss","Close by StopLoss")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==ORDER_PROP_CLOSE_BY_TP       ?  TextByLanguage("Закрытие по TakeProfit","Close by TakeProfit")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Rückgabe der Beschreibung der Double-Eigenschaft der Order       |
//+------------------------------------------------------------------+
string COrder::GetPropertyDescription(ENUM_ORDER_PROP_DOUBLE property)
  {
   int dg=(int)::SymbolInfoInteger(this.GetProperty(ORDER_PROP_SYMBOL),SYMBOL_DIGITS);
   int dgl=(int)DigitsLots(this.GetProperty(ORDER_PROP_SYMBOL));
   return
     (
      //--- Allgemeine Eigenschaften
      property==ORDER_PROP_PRICE_CLOSE       ?  TextByLanguage("Цена закрытия","Close price")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==ORDER_PROP_PRICE_OPEN        ?  TextByLanguage("Цена открытия","Open price")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==ORDER_PROP_SL                ?  TextByLanguage("Цена StopLoss","StopLoss price")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          (this.GetProperty(property)==0     ?  TextByLanguage(": Отсутствует",": Not set"):": "+::DoubleToString(this.GetProperty(property),dg))
         )  :
      property==ORDER_PROP_TP                ?  TextByLanguage("Цена TakeProfit","TakeProfit price")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          (this.GetProperty(property)==0     ?  TextByLanguage(": Отсутствует",": Not set"):": "+::DoubleToString(this.GetProperty(property),dg))
         )  :
      property==ORDER_PROP_PROFIT            ?  TextByLanguage("Прибыль","Profit")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==ORDER_PROP_COMMISSION        ?  TextByLanguage("Комиссия","Comission")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==ORDER_PROP_SWAP              ?  TextByLanguage("Своп","Swap")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==ORDER_PROP_VOLUME            ?  TextByLanguage("Объём","Volume")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dgl)
          ) :
      property==ORDER_PROP_VOLUME_CURRENT    ?  TextByLanguage("Невыполненный объём","Unfulfilled volume")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dgl)
          ) :
      property==ORDER_PROP_PRICE_STOP_LIMIT  ? 
         TextByLanguage("Цена постановки Limit ордера при активации StopLimit ордера","Price of placing Limit order when StopLimit order activated")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
          ) :
      //--- Zusätzliche Eigenschaften
      property==ORDER_PROP_PROFIT_FULL       ?  TextByLanguage("Прибыль+комиссия+своп","Profit+Comission+Swap")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
          ": "+::DoubleToString(this.GetProperty(property),2)
          ) :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Rückgabe der Beschreibung der String-Eigenschaft der Order       |
//+------------------------------------------------------------------+
string COrder::GetPropertyDescription(ENUM_ORDER_PROP_STRING property)
  {
   return
     (
      property==ORDER_PROP_SYMBOL         ?  TextByLanguage("Символ","Symbol")+": \""+this.GetProperty(property)+"\""            :
      property==ORDER_PROP_COMMENT        ?  TextByLanguage("Комментарий","Comment")+
         (this.GetProperty(property)==""  ?  TextByLanguage(": Отсутствует",": Not set"):": \""+this.GetProperty(property)+"\"") :
      property==ORDER_PROP_EXT_ID         ?  TextByLanguage("Идентификатор на бирже","ID on exchange")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property not supported") :
         (this.GetProperty(property)==""  ?  TextByLanguage(": Отсутствует",": Not set"):": \""+this.GetProperty(property)+"\"")):
      ""
     );
  }
//+------------------------------------------------------------------+

Die Methoden zur Rückgabe des Namens eines Auftragsstatus, eines Auftrags oder einer Position, des Namens einer Geschäftsrichtung, einer Beschreibung, eines Auftrags-/Positionsrichtungstyps und des Verfahrens zur komfortablen Anzeige von Auftragseigenschaften im Journal.

Fügen wir zunächst noch eine weitere Makro-Substitution zur Datei Defines.mqh hinzu, um einen Funktions-/Methodennamen im Journal bequem anzuzeigen:

//+------------------------------------------------------------------+
//| Macro-Substitution                                               |
//+------------------------------------------------------------------+
#define COUNTRY_LANG    "Russian"            // Landessprache
#define DFUN           (__FUNCTION__+": ")   // "Funktionsbeschreibung"
//+------------------------------------------------------------------+

Nun, anstatt die ganzen Zeichenketten zu schreiben, können wir einfach DFUN schreiben, und der Compiler ändert die Beschreibung in die im Makro gesetzten Zeichenketten.

//+------------------------------------------------------------------+
//| Rückgabe des Namens des Order-Status                             |
//+------------------------------------------------------------------+
string COrder::StatusDescription(void) const
  {
   ENUM_ORDER_STATUS status=this.Status();
   ENUM_ORDER_TYPE   type=(ENUM_ORDER_TYPE)this.TypeOrder();
   return
     (
      status==ORDER_STATUS_BALANCE        ?  TextByLanguage("Балансная операция","Balance operation") :
      status==ORDER_STATUS_CREDIT         ?  TextByLanguage("Кредитная операция","Credits operation") :
      status==ORDER_STATUS_HISTORY_ORDER  || status==ORDER_STATUS_HISTORY_PENDING                     ?  
      (
       type>ORDER_TYPE_SELL ? TextByLanguage("Отложенный ордер","Pending order")                      :
       TextByLanguage("Ордер на ","The order to ")+(type==ORDER_TYPE_BUY ? TextByLanguage("покупку","buy") : TextByLanguage("продажу","sell"))
      )                                                                                               :
      status==ORDER_STATUS_DEAL           ?  TextByLanguage("Сделка","Deal")                          :
      status==ORDER_STATUS_MARKET_ACTIVE  ?  TextByLanguage("Позиция","Active position")              :
      status==ORDER_STATUS_MARKET_PENDING ?  TextByLanguage("Установленный отложенный ордер","Active pending order") :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Rückgabe des Namens der Order oder Position                      |
//+------------------------------------------------------------------+
string COrder::TypeDescription(void) const
  {
   if(this.Status()==ORDER_STATUS_DEAL)
      return this.GetTypeDealDescription(this.TypeOrder());
   else switch(this.TypeOrder())
     {
      case ORDER_TYPE_BUY              :  return "Buy";
      case ORDER_TYPE_BUY_LIMIT        :  return "Buy Limit";
      case ORDER_TYPE_BUY_STOP         :  return "Buy Stop";
      case ORDER_TYPE_SELL             :  return "Sell";
      case ORDER_TYPE_SELL_LIMIT       :  return "Sell Limit";
      case ORDER_TYPE_SELL_STOP        :  return "Sell Stop";
      #ifdef __MQL4__
      case ORDER_TYPE_BALANCE          :  return TextByLanguage("Балансовая операция","Balance operation");
      case ORDER_TYPE_CREDIT           :  return TextByLanguage("Кредитная операция","Credit operation");
      #else 
      case ORDER_TYPE_BUY_STOP_LIMIT   :  return "Buy Stop Limit";
      case ORDER_TYPE_SELL_STOP_LIMIT  :  return "Sell Stop Limit";
      #endif 
      default                          :  return TextByLanguage("Неизвестный тип","Unknown type");
     }
  }
//+------------------------------------------------------------------+
//| Richtung des Namens der Deal-Richtung                            |
//+------------------------------------------------------------------+
string COrder::DealEntryDescription(void) const
  {
   return(this.Status()==ORDER_STATUS_DEAL ? this.GetEntryDescription(this.GetProperty(ORDER_PROP_DEAL_ENTRY)) : "");
  }
//+------------------------------------------------------------------+
//| Rückgabe des Typs der Richtung von Order/Position                |
//+------------------------------------------------------------------+
string COrder::DirectionDescription(void) const
  {
   if(this.Status()==ORDER_STATUS_DEAL)
      return this.TypeDescription();
   switch(this.TypeByDirection())
     {
      case ORDER_TYPE_BUY  :  return "Buy";
      case ORDER_TYPE_SELL :  return "Sell";
      default              :  return TextByLanguage("Неизвестный тип","Unknown type");
     }
  }
//+------------------------------------------------------------------+
//| Senden der Eigenschaften der Order an das Journal                |
//+------------------------------------------------------------------+
void COrder::Print(const bool full_prop=false)
  {
   ::Print("============= ",TextByLanguage("Начало списка параметров: \"","Beginning of the parameter list: \""),this.StatusDescription(),"\" =============");
   int beg=0, end=ORDER_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_ORDER_PROP_INTEGER prop=(ENUM_ORDER_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=ORDER_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_ORDER_PROP_DOUBLE prop=(ENUM_ORDER_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=ORDER_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_ORDER_PROP_STRING prop=(ENUM_ORDER_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("================== ",TextByLanguage("Конец списка параметров: \"","End of the parameter list: \""),this.StatusDescription(),"\" ==================\n");
  }
//+------------------------------------------------------------------+

Nachdem nun alle Methoden der abstrakten Auftragsklasse COrder implementiert sind, können wir sehen, was wir in diesem Stadium wirklich erreicht haben.

Test der abstrakten Order COrder

Testen und sehen wir, wie COrder-Basisobjekte erstellt und mit Daten befüllt werden. Im weiteren Verlauf werden wir darauf aufbauende Objekte nach Typen entwickeln und in Sammlungen speichern.

Erstellen wir im Verzeichnis oder Unterverzeichnis Experts einen neuen Ordner und nennen Sie ihn TestDoEasy. Als nächstes erstellen wir einen weiteren Ordner innerhalb des neu erstellten Ordners: Teil01. Die Testdatei des EAs soll sich darin befinden.

Klicken Sie mit der rechten Maustaste auf Part01 im Editor-Navigator und wählen Sie "Neue Datei" aus dem Popup-Menü, oder drücken Sie Strg+N, während der Ordner Part01 markiert ist. Das Fenster des MQL-Assistenten wird mit der bereits ausgewählten Option "Expert Advisor (Vorlage)" geöffnet, klicken Sie auf "Weiter" und fügen Sie den Namen der neuen Datei TestDoEasyPart01 dem bereits angegebenen Dateipfad im Namenseingabefeld hinzu. Klicken Sie auf "Weiter", bis Sie das Ende der Assistentenoperation erreicht haben. Wir benötigen für den Test keine zusätzliche Ereignisbehandlung, so dass wir alle Kontrollkästchen leer lassen können. Klicken Sie auf "Fertig stellen", um die neue EA-Vorlage zu erstellen:
//+------------------------------------------------------------------+
//|                                             TestDoEasyPart01.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Deinitialisierungsfunktion des Experten                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Experten Funktion OnTick                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

Dieser Test ist so einfach wie möglich, es gibt keine Notwendigkeit, das Rad neu zu erfinden. Damit haben wir schließen einfach die Klasse unsere abstrakte Order COrder und die Klasse CArrayObj aus der Standardbibliothek eingebunden, und erstellen die Objektliste:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart01.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//--- includes
#include <DoEasy\Objects\Order.mqh>
#include <Arrays\ArrayObj.mqh>
//--- Globale Variablen
CArrayObj      list_all_orders;
//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+

Als Nächstes bestimmen wir das Flag für die Sortierung der Objektliste in OnInit() und befüllen sie mit der gesamten Historie von Deals und Aufträgen in zwei Schleifen.

Dann schreiben wir mittels einer Schleife die Daten zu jedem der Objekte der befüllten Liste in das Expertenjournal des Terminalsan:

//+------------------------------------------------------------------+
//| Initialisierungsfunktion des Experten                            |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   list_all_orders.Sort();
   list_all_orders.Clear();
   if(!HistorySelect(0,TimeCurrent()))
     {
      Print(DFUN,TextByLanguage(": Не удалось получить историю сделок и ордеров",": Failed to get history of deals and orders"));
      return INIT_FAILED;
     }
//--- Deals
   int total_deals=HistoryDealsTotal();
   for(int i=0; i<total_deals; i++)
     {
      ulong deal_ticket=::HistoryDealGetTicket(i);
      if(deal_ticket==0) continue;
      COrder *deal=new COrder(ORDER_STATUS_DEAL,deal_ticket);
      if(deal==NULL) continue;
      list_all_orders.InsertSort(deal);
     }
//--- Orders
   int total_orders=HistoryOrdersTotal();
   for(int i=0; i<total_orders; i++)
     {
      ulong order_ticket=::HistoryOrderGetTicket(i);
      if(order_ticket==0) continue;
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::HistoryOrderGetInteger(order_ticket,ORDER_TYPE);
      if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL)
        {
         COrder *order=new COrder(ORDER_STATUS_HISTORY_ORDER,order_ticket);
         if(order==NULL) continue;
         list_all_orders.InsertSort(order);
        }
      else
        {
         COrder *order=new COrder(ORDER_STATUS_HISTORY_PENDING,order_ticket);
         if(order==NULL) continue;
         list_all_orders.InsertSort(order);
        }
     }
//--- Darstellung im Journal
   int total=list_all_orders.Total();
   for(int i=0;i<total;i++)
     {
      COrder *order=list_all_orders.At(i);
      if(order==NULL)
         continue;
      order.Print();
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Wenn wir nun versuchen, den EA zu kompilieren, erhalten wir drei Fehler:


Die Fehler deuten darauf hin, dass wir von außen nicht auf die 'protected' Methoden der Klasse zugreifen können. Schließlich haben wir den COrder-Konstruktor im 'protected' Bereich der Klasse erstellt. Wenn wir die Klasse als Basis verwenden, um Objekte nach Typen zu entwickeln, wird alles in Ordnung sein, da sie offene Konstruktoren haben. Um den Test durchzuführen, verschieben wir nun einfach den Konstruktor in den öffentlichen Bereich der Klasse COrder:


Jetzt ist alles fehlerfrei zusammengestellt, und die Daten über alle Aufträge und Geschäfte in der Historie des Handelskontos werden im Terminaljournal angezeigt.


Alle Eigenschaften aller Orders/Deals, einschließlich der nicht unterstützten, werden angezeigt.


Tatsache ist, dass wir die Methoden entwickelt haben, die die Flags zur Unterstützung bestimmter Eigenschaften in dieser Reihenfolge als virtuell zurückgeben, so dass sie in den abgeleiteten Klassen neu definiert werden. Diese abgeleiteten Klassen werden dann zur Anzeige von Daten im Journal verwendet. In diesem Fall sollte alles korrekt angezeigt werden. Wenn es eine Eigenschaft gibt, die vom Auftrag nicht unterstützt wird, wird sie im Journal nicht angezeigt, da die Methode Print(const bool full_prop=false) der Klasse COrder das Standardflag für Deaktivieren einer Anzeige von nicht unterstützten Eigenschaften im Journal hat, während die virtuellen Methoden der Klasse SupportProperty() einfach 'true' für jede Eigenschaft zurückgeben.

Was kommt als Nächstes?

Der erste (und das kleinste) Teil ist fertig. Wir haben ein Basisobjekt für die Sammlung von historischen Aufträge und Deals sowie für die Sammlung der Marktorders und Positionen entwickelt. Bisher gibt es keinen praktischen Wert, aber das ist ja auch erst der Anfang. Dieses einzelne Basisobjekt soll zu einem Eckpfeiler für das System werden, das Daten auf dem Auftragssystem speichert und anzeigt. Unser nächster Schritt ist die Entwicklung weiterer notwendiger Objekte und Sammlungen nach den gleichen Prinzipien. Ich werde auch die Erfassung der ständig benötigten Daten automatisieren.


Im nächsten Teil werde ich mehrere Klassen entwickeln, die auf darauf basieren. Die Klassen beschreiben spezifische Auftrags-, Deal- und Positionsarten. Ich werde die erste Sammlung (Sammlung historischer Aufträge und Deals) sowie die Basis und das Hauptobjekt der Bibliothek — Engine — entwickeln. Ich werde auch Fehler beseitigen, während ich versuche, die Bibliothek in MQL4 in den folgenden Teilen der Bibliotheksentwicklungsbeschreibung zu kompilieren.

Nachfolgend finden Sie ein Archiv mit allen im ersten Teil behandelten Dateien. Sie können sie herunterladen und im Detail analysieren. Stellen Sie Ihre Fragen, Kommentare und Vorschläge in den Kommentaren.

Bitte beachten Sie, dass die Bibliothek parallel zum Schreiben der Artikel aufgebaut wird. Daher werden die Methoden und Variablen der Bibliothek von Artikel zu Artikel überarbeitet. In diesem Zusammenhang kann es zu geringfügigen Inkonsistenzen im Inhalt der angehängten Dateien und Beschreibungstexte im Artikel kommen. So kann es beispielsweise Änderungen in den Kommentaren geben, Neuordnungen der Elemente der Enumerationen, etc. Dies hat keinen Einfluss auf die Performance der angehängten Beispiele.

Zurück zum Inhalt.


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

Beigefügte Dateien |
MQL5.zip (16.19 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (2)
Tobias Johannes Zimmer
Tobias Johannes Zimmer | 5 Feb. 2021 in 09:31

Thanks a lot!

I am fairly new to programming and I was afraid of your articles because they look so cryptic and have no pictures in them AHAHAHA.

But no actually they are very well written and well translated and they are helping me jump into object oriented programming.

Artyom Trishkin
Artyom Trishkin | 5 Feb. 2021 in 14:10
pennyhunter:

Thanks a lot!

I am fairly new to programming and I was afraid of your articles because they look so cryptic and have no pictures in them AHAHAHA.

But no actually they are very well written and well translated and they are helping me jump into object oriented programming.

:)

OK. Your welcome

Untersuchung von Techniken zur Analyse der Kerzen (Teil II): Automatische Suche nach den Mustern Untersuchung von Techniken zur Analyse der Kerzen (Teil II): Automatische Suche nach den Mustern
Im vorherigen Artikel haben wir 14 Muster analysiert, die aus einer Vielzahl von bestehenden Kerzenformationen ausgewählt wurden. Es ist unmöglich, alle Muster einzeln zu analysieren, deshalb wurde eine andere Lösung gefunden. Das neue System sucht und testet neue Kerzenmuster basierend auf bekannten den Kerzentypen.
MQL-Parsing mit Hilfe von MQL MQL-Parsing mit Hilfe von MQL
Der Artikel beschreibt einen Präprozessor, einen Scanner und einen Parser, die beim Parsen der MQL-basierten Quellcodes verwendet werden sollten. Die MQL-Implementierung ist beigefügt.
Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil II). Erhebung (Collection) historischer Aufträge und Deals Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil II). Erhebung (Collection) historischer Aufträge und Deals
Im ersten Teil begannen wir mit dem Erstellen einer großen plattformübergreifenden Bibliothek, die die Entwicklung von Programmen für MetaTrader 5 und MetaTrader 4 Plattformen vereinfacht. Wir haben das abstrakte Objekt COrder angelegt, das als Basisobjekt für die Speicherung von Daten zu historischen Aufträgen und Deals sowie zu Marktorders und Positionen dient. Jetzt werden wir alle notwendigen Objekte entwickeln, um die Daten der Kontenhistorie in "Collections" (Sammlungen bzw. Listen) zu speichern.
Die Stärke von ZigZag (Teil II). Beispiele für das Empfangen, Verarbeiten und Anzeigen von Daten Die Stärke von ZigZag (Teil II). Beispiele für das Empfangen, Verarbeiten und Anzeigen von Daten
Im ersten Teil der Artikelserie habe ich einen modifizierten ZigZag-Indikator und eine Klasse zum Empfangen von Daten dieser Art von Indikatoren beschrieben. Hier werde ich zeigen, wie man Indikatoren entwickelt, die auf diesen Tools basieren, und ein EA für Tests schreiben, der gemäß den Signalen des ZigZag-Indikators handelt. Als Ergänzung wird der Artikel eine neue Version der Bibliothek EasyAndFast zur Entwicklung grafischer Benutzeroberflächen vorstellen.