
Bibliothek für ein leichtes und schnelles Entwickeln vom Programmen für den MetaTrader (Teil IX): Kompatibilität mit MQL4 - Datenvorbereitung
Inhalt
In den vorherigen Teilen der Artikelserie haben wir die folgenden Werkzeuge für die plattformübergreifende Bibliothek MetaTrader 5 und MetaTrader 4 vorbereitet:
- Zur Erstellung von User-Case-Funktionen, die einen schnellen Zugriff von Programmen auf beliebige Daten zu beliebigen Aufträgen und Positionen von Hedging- und Netting-Konten ermöglichen.
- Zur Verfolgung von Ereignissen bei Orders und Positionen — Platzieren, Entfernen und Aktivieren von offenen Orders sowie Öffnen, Schließen und Ändern von Positionen und Orders.
Jetzt ist es an der Zeit, die Bibliothekskompatibilität mit MQL4 zu implementieren, da wir Handelsklassen entwickeln werden und die
Bibliothek sowohl in MQL5 als auch in MQL4 korrekt funktionieren sollte.
In diesem Artikel werden wir damit beginnen, die Bibliothek zu verbessern, um ihren plattformübergreifenden Charakter zu
implementieren.
MQL4 vs MQL5
Kopieren Sie den gesamten Bibliotheksordner in das entsprechende MetaTrader 4-Verzeichnis \MQL4\Include\DoEasy. Wir nehmen die Test-EAs aus den entsprechenden Ordnern mit MQL5 EAs und speichern sie mit der Erweiterung *.mq4 im EA-Verzeichnis \MQL4\Experts\TestDoEasy (in den der Artikelnummer entsprechenden Ordner, der in diesem Fall Part09 ist).
Suchen Sie das Bibliotheksverzeichnis \MQL4\Include\DoEasy im Navigator des Editors, klicken Sie mit der rechten Maustaste darauf und
wählen Sie Kompilieren.
Dadurch werden alle Bibliotheksdateien kompiliert, was zu über zweitausend Kompilierungsfehlern führt:
Wenn wir die angezeigten Fehler analysieren, werden wir sehen, dass ihre überwiegende Mehrheit Konstanten und Enumerationen von MQL5 betreffen, mit denen MQL4 nichts anzufangen weiß. Das bedeutet, dass wir MQL4 über die in der Bibliothek verwendeten Konstanten informieren müssen. Es gibt auch die Fehler einer anderen Art, wie das Fehlen bestimmter Funktionen, was bedeutet, dass wir ihre Betriebslogik mit MQL4-Funktionen umsetzen werden.
Außerdem sind die Auftragssysteme von MQL4 und MQL5 sehr unterschiedlich. Wir müssen für MQL4 eine eigene Ereignisbehandlung implementieren, der sich von dem in MQL5 implementierten unterscheidet, da die Liste der historischen Aufträge in MQL4 viel weniger Daten über Aufträge (und keine Daten über Geschäfte) liefert, was bedeutet, dass wir keine Daten über Aufträge und Geschäfte direkt aus den Klemmenlisten übernehmen können. Hier müssen wir die aufgetretenen Ereignisse in den Listen der aktiven und historischen Marktaufträge logisch vergleichen und die aufgetretenen Ereignisse anhand des Vergleichs definieren.Verbessern der Bibliothek
Erstellen Sie im Stammverzeichnis der Bibliothek DoEasy die neue Include-Datei ToMQL4.mqh. Hier werden alle notwendigen Konstanten und Aufzählungen für MQL4 beschrieben. Einbinden in die Datei Defines.mqh für die MQL4-Kompilierung am Anfang von Defines.mqh:
//+------------------------------------------------------------------+ //| Defines.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/de/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/de/users/artmedia70" //+------------------------------------------------------------------+ //| Include-Dateien | //+------------------------------------------------------------------+ #ifdef __MQL4__ #include "ToMQL4.mqh" #endif //+------------------------------------------------------------------+
Danach kann die gesamte MQL4-Bibliothek sehen, was während der Kompilierung in die Datei ToMQL4.mqh geschrieben wird.
Gehen wir zum Anfang der Fehlerliste in der Registerkarte Fehler der Editor-Toolbox, indem wir NumPad POS1 (Home) drücken oder einfach bis zum Anfang nach oben scrollen. Machen Sie einen Doppelklick auf den allerersten Fehler:
Der Editor bewegt uns zum Fehlerzeile in der Datei Defines.mqh:
//+------------------------------------------------------------------+ //| Liste der möglichen Handelsereignisse auf dem Konto | //+------------------------------------------------------------------+ enum ENUM_TRADE_EVENT { TRADE_EVENT_NO_EVENT = 0, // No trading event TRADE_EVENT_PENDING_ORDER_PLASED, // Pending-Order platziert TRADE_EVENT_PENDING_ORDER_REMOVED, // Pending-Order entfernt //--- Mitglieder der Enumeration stimmen mit den Mitgliedern der Enumeration ENUM_DEAL_TYPE überein //--- (constant order below should not be changed, no constants should be added/deleted) TRADE_EVENT_ACCOUNT_CREDIT = DEAL_TYPE_CREDIT, // Charging credit (3) TRADE_EVENT_ACCOUNT_CHARGE, // Weitere Lastschrift
Natürlich weiß MQL4 nichts über Deals und deren Typisierung. Dies sollte behoben werden. Öffnen Sie einfach die MQL5-Referenz und suchen Sie mittels DEAL_TYPE_CREDIT nach Daten zu Eigenschaften der Deals:
ID |
Beschreibung |
Typ |
DEAL_TICKET |
Ticket des Deals. Eindeutige Nummer für jeden Deal |
long |
DEAL_ORDER |
Order-Nummer des Deals |
long |
DEAL_TIME |
Deal-Zeit |
datetime |
DEAL_TIME_MSC |
Ausführungszeit des Deals in Millisekunden sein 01.01.1970 |
long |
DEAL_TYPE |
Deal-Typ |
|
DEAL_ENTRY |
Deal-Richtung - Markteintritt, -austritt oder -umkehr |
|
DEAL_MAGIC |
Magicnummer des Deals (siehe ORDER_MAGIC) |
long |
DEAL_REASON |
Ursache oder Quelle für die Ausführung des Deals |
|
DEAL_POSITION_ID |
Die ID der Position, die das Geschäft eröffnet, geändert oder geschlossen hat. Jede Position hat eine eindeutige ID, die allen Deals zugeordnet ist, die während der Lebensdauer der Position mit dem Symbol ausgeführt werden. |
long |
In der Tabelle sind wir am meisten an ENUM_DEAL_TYPE
interessiert. Folgen wir dem Link und erhalten wir die Liste aller Dealtypen:
ID |
Beschreibung |
DEAL_TYPE_BUY |
Kaufen |
DEAL_TYPE_SELL |
Verkaufen |
DEAL_TYPE_BALANCE |
Saldo |
DEAL_TYPE_CREDIT |
Gutschrift |
DEAL_TYPE_CHARGE |
Zusätzliche Lastschrift |
DEAL_TYPE_CORRECTION |
Korrektur |
DEAL_TYPE_BONUS |
Bonus |
DEAL_TYPE_COMMISSION |
Zusätzliche Kommission |
DEAL_TYPE_COMMISSION_DAILY |
Tägliche Kommission |
DEAL_TYPE_COMMISSION_MONTHLY |
Monatliche Kommission |
DEAL_TYPE_COMMISSION_AGENT_DAILY |
Tägliche Kommission des Agenten |
DEAL_TYPE_COMMISSION_AGENT_MONTHLY |
Monatliche Kommission des Agenten |
DEAL_TYPE_INTEREST |
Zinssatz |
DEAL_TYPE_BUY_CANCELED |
Stornierter Kauf-Deal. Es kann eine Situation geben, in der ein zuvor abgeschlossener Kauf-Deal storniert wird. In diesem Fall wird die Art des zuvor ausgeführten Deals (DEAL_TYPE_BUY) geändert in DEAL_TYPE_BUY_CANCELED, und sein Gewinn/Verlust wird auf Null gestellt. Zuvor erzielte Gewinne/Verluste werden mit Hilfe einer getrennten Saldenoperation berechnet bzw. entnommen. |
DEAL_TYPE_SELL_CANCELED |
Stornierter Verkaufs-Deal. Es kann eine Situation geben, in der ein zuvor abgeschlossenes Verkaufs-Deal storniert wird. In diesem Fall wird die Art des zuvor ausgeführten Deals (DEAL_TYPE_SELL) wird in DEAL_TYPE_SELL_CANCELED geändert, und sein Gewinn/Verlust wird auf Null gestellt. Zuvor erzielte Gewinne/Verluste werden mit Hilfe einer getrennten Saldenoperation berechnet bzw. entnommen. |
DEAL_DIVIDEND |
Dividendenzahlung |
DEAL_DIVIDEND_FRANKED |
Befreite (nicht zu verteuernde) Dividendenzahlung |
DEAL_TAX |
Steuerlastschrift |
Fügen wir die Dealtypen aus der Enumeration ENUM_DEAL_TYPE zur Datei ToMQL4.mqh hinzu:
//+------------------------------------------------------------------+ //| ToMQL4.mqh | //| Copyright 2017, Artem A. Trishkin, Skype artmedia70 | //| https://www.mql5.com/de/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70" #property link "https://www.mql5.com/de/users/artmedia70" #property strict #ifdef __MQL4__ //+------------------------------------------------------------------+ //| MQL5 deal types | //+------------------------------------------------------------------+ enum ENUM_DEAL_TYPE { DEAL_TYPE_BUY, DEAL_TYPE_SELL, DEAL_TYPE_BALANCE, DEAL_TYPE_CREDIT, DEAL_TYPE_CHARGE, DEAL_TYPE_CORRECTION, DEAL_TYPE_BONUS, DEAL_TYPE_COMMISSION, DEAL_TYPE_COMMISSION_DAILY, DEAL_TYPE_COMMISSION_MONTHLY, DEAL_TYPE_COMMISSION_AGENT_DAILY, DEAL_TYPE_COMMISSION_AGENT_MONTHLY, DEAL_TYPE_INTEREST, DEAL_TYPE_BUY_CANCELED, DEAL_TYPE_SELL_CANCELED, DEAL_DIVIDEND, DEAL_DIVIDEND_FRANKED, DEAL_TAX }; //+------------------------------------------------------------------+ #endif
Speichern Sie die Datei und kompilieren Sie alle Bibliotheksdateien erneut. Es gibt jetzt weniger Fehler:
Gehen Sie erneut an den Anfang der Fehlerliste und klicken Sie auf den ersten Fehler. Jetzt ist es ENUM_POSITION_TYPE, also fügen wir das hinzu:
//+------------------------------------------------------------------+ //| ToMQL4.mqh | //| Copyright 2017, Artem A. Trishkin, Skype artmedia70 | //| https://www.mql5.com/de/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70" #property link "https://www.mql5.com/de/users/artmedia70" #property strict #ifdef __MQL4__ //+------------------------------------------------------------------+ //| MQL5 deal type | //+------------------------------------------------------------------+ enum ENUM_DEAL_TYPE { DEAL_TYPE_BUY, DEAL_TYPE_SELL, DEAL_TYPE_BALANCE, DEAL_TYPE_CREDIT, DEAL_TYPE_CHARGE, DEAL_TYPE_CORRECTION, DEAL_TYPE_BONUS, DEAL_TYPE_COMMISSION, DEAL_TYPE_COMMISSION_DAILY, DEAL_TYPE_COMMISSION_MONTHLY, DEAL_TYPE_COMMISSION_AGENT_DAILY, DEAL_TYPE_COMMISSION_AGENT_MONTHLY, DEAL_TYPE_INTEREST, DEAL_TYPE_BUY_CANCELED, DEAL_TYPE_SELL_CANCELED, DEAL_DIVIDEND, DEAL_DIVIDEND_FRANKED, DEAL_TAX }; //+------------------------------------------------------------------+ //| Open position direction | //+------------------------------------------------------------------+ enum ENUM_POSITION_TYPE { POSITION_TYPE_BUY, POSITION_TYPE_SELL }; //+------------------------------------------------------------------+ #endif
Nach dem Kompilieren erhalten wir noch weniger Fehler. Gehen Sie zum ersten Fehler in der Liste, definieren Sie den Grund und fügen Sie die folgende Enumeration hinzu:
//+------------------------------------------------------------------+ //| ToMQL4.mqh | //| Copyright 2017, Artem A. Trishkin, Skype artmedia70 | //| https://www.mql5.com/de/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70" #property link "https://www.mql5.com/de/users/artmedia70" #property strict #ifdef __MQL4__ //+------------------------------------------------------------------+ //| MQL5 deal types | //+------------------------------------------------------------------+ enum ENUM_DEAL_TYPE { DEAL_TYPE_BUY, DEAL_TYPE_SELL, DEAL_TYPE_BALANCE, DEAL_TYPE_CREDIT, DEAL_TYPE_CHARGE, DEAL_TYPE_CORRECTION, DEAL_TYPE_BONUS, DEAL_TYPE_COMMISSION, DEAL_TYPE_COMMISSION_DAILY, DEAL_TYPE_COMMISSION_MONTHLY, DEAL_TYPE_COMMISSION_AGENT_DAILY, DEAL_TYPE_COMMISSION_AGENT_MONTHLY, DEAL_TYPE_INTEREST, DEAL_TYPE_BUY_CANCELED, DEAL_TYPE_SELL_CANCELED, DEAL_DIVIDEND, DEAL_DIVIDEND_FRANKED, DEAL_TAX }; //+------------------------------------------------------------------+ //| Open position direction | //+------------------------------------------------------------------+ enum ENUM_POSITION_TYPE { POSITION_TYPE_BUY, POSITION_TYPE_SELL }; //+------------------------------------------------------------------+ //| Order status | //+------------------------------------------------------------------+ enum ENUM_ORDER_STATE { ORDER_STATE_STARTED, ORDER_STATE_PLACED, ORDER_STATE_CANCELED, ORDER_STATE_PARTIAL, ORDER_STATE_FILLED, ORDER_STATE_REJECTED, ORDER_STATE_EXPIRED, ORDER_STATE_REQUEST_ADD, ORDER_STATE_REQUEST_MODIFY, ORDER_STATE_REQUEST_CANCEL }; //+------------------------------------------------------------------+ #endif
Durch die nächste Kompilierung haben wir den falschen Auftragstyp ORDER_TYPE_BUY_STOP_LIMIT
erhalten.
MQL4 verfügt bereits über die Enumeration ENUM_ORDER_TYPE.
Wir können ihr keine neuen Konstanten hinzufügen. Fügen wir sie daher als Makro-Substitutionen hinzu.
In MQL5 wird die Konstante ORDER_TYPE_BUY_STOP_LIMIT aus der ENUM_ORDER_TYPE Enumeration auf 6 gesetzt, während in MQL4 ein solcher Auftragstyp existiert. Diese Saldenoperation wird wie ORDER_TYPE_SELL_STOP_LIMIT in MQL5 auf 7 gesetzt, während in MQL4 diese Auftragsart eine Gutschrift ist.
Setzen wir daher höhere Werte für die Konstante ORDER_TYPE_CLOSE_BY für das Schließen einer Order: ORDER_TYPE_CLOSE_BY+1 und entsprechend ORDER_TYPE_CLOSE_BY+2:
//+------------------------------------------------------------------+ //| ToMQL4.mqh | //| Copyright 2017, Artem A. Trishkin, Skype artmedia70 | //| https://www.mql5.com/de/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70" #property link "https://www.mql5.com/de/users/artmedia70" #property strict #ifdef __MQL4__ //+------------------------------------------------------------------+ //| MQL5 deal types | //+------------------------------------------------------------------+ enum ENUM_DEAL_TYPE { DEAL_TYPE_BUY, DEAL_TYPE_SELL, DEAL_TYPE_BALANCE, DEAL_TYPE_CREDIT, DEAL_TYPE_CHARGE, DEAL_TYPE_CORRECTION, DEAL_TYPE_BONUS, DEAL_TYPE_COMMISSION, DEAL_TYPE_COMMISSION_DAILY, DEAL_TYPE_COMMISSION_MONTHLY, DEAL_TYPE_COMMISSION_AGENT_DAILY, DEAL_TYPE_COMMISSION_AGENT_MONTHLY, DEAL_TYPE_INTEREST, DEAL_TYPE_BUY_CANCELED, DEAL_TYPE_SELL_CANCELED, DEAL_DIVIDEND, DEAL_DIVIDEND_FRANKED, DEAL_TAX }; //+------------------------------------------------------------------+ //| Open position direction | //+------------------------------------------------------------------+ enum ENUM_POSITION_TYPE { POSITION_TYPE_BUY, POSITION_TYPE_SELL }; //+------------------------------------------------------------------+ //| Order status | //+------------------------------------------------------------------+ enum ENUM_ORDER_STATE { ORDER_STATE_STARTED, ORDER_STATE_PLACED, ORDER_STATE_CANCELED, ORDER_STATE_PARTIAL, ORDER_STATE_FILLED, ORDER_STATE_REJECTED, ORDER_STATE_EXPIRED, ORDER_STATE_REQUEST_ADD, ORDER_STATE_REQUEST_MODIFY, ORDER_STATE_REQUEST_CANCEL }; //+------------------------------------------------------------------+ //| Order types | //+------------------------------------------------------------------+ #define ORDER_TYPE_CLOSE_BY (8) #define ORDER_TYPE_BUY_STOP_LIMIT (9) #define ORDER_TYPE_SELL_STOP_LIMIT (10) //+------------------------------------------------------------------+ #endif
Kompilieren wir die gesamte Bibliothek. Nach der Implementierung von Makro-Substitutionen von StopLimit-Ordertypen zeigt der Fehler die Funktionen an, die den korrekten Preis bei einer Orderplatzierung zurückgeben, nämlich die Enumeration ENUM_ORDER_TYPE ohne die Werte 9 und 10, da wir den Wert des Ordertyps in dem Switch-Operator mit dem Aufzählungstyp ENUM_ORDER_TYPE verwenden:
//+------------------------------------------------------------------+ //| Rückgabe des Preises der korrekten Order-Platzierung | //| relative zum StopLevel | //+------------------------------------------------------------------+ double CorrectPricePending(const string symbol_name,const ENUM_ORDER_TYPE order_type,const double price_set,const double price=0,const int spread_multiplier=2) { double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT),pp=0; int lv=StopLevel(symbol_name,spread_multiplier), dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS); switch(order_type) { case ORDER_TYPE_BUY_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : price); return NormalizeDouble(fmin(pp-lv*pt,price_set),dg); case ORDER_TYPE_BUY_STOP : case ORDER_TYPE_BUY_STOP_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : price); return NormalizeDouble(fmax(pp+lv*pt,price_set),dg); case ORDER_TYPE_SELL_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : price); return NormalizeDouble(fmax(pp+lv*pt,price_set),dg); case ORDER_TYPE_SELL_STOP : case ORDER_TYPE_SELL_STOP_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : price); return NormalizeDouble(fmin(pp-lv*pt,price_set),dg); default : Print(DFUN,TextByLanguage("Неправильный тип ордера: ","Invalid order type: "),EnumToString(order_type)); return 0; } } //+------------------------------------------------------------------+ //| Rückgabe des Preises der korrekten Order-Platzierung | //| relative zum StopLevel | //+------------------------------------------------------------------+ double CorrectPricePending(const string symbol_name,const ENUM_ORDER_TYPE order_type,const int distance_set,const double price=0,const int spread_multiplier=2) { double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT),pp=0; int lv=StopLevel(symbol_name,spread_multiplier), dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS); switch(order_type) { case ORDER_TYPE_BUY_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : price); return NormalizeDouble(fmin(pp-lv*pt,pp-distance_set*pt),dg); case ORDER_TYPE_BUY_STOP : case ORDER_TYPE_BUY_STOP_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : price); return NormalizeDouble(fmax(pp+lv*pt,pp+distance_set*pt),dg); case ORDER_TYPE_SELL_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : price); return NormalizeDouble(fmax(pp+lv*pt,pp+distance_set*pt),dg); case ORDER_TYPE_SELL_STOP : case ORDER_TYPE_SELL_STOP_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : price); return NormalizeDouble(fmin(pp-lv*pt,pp-distance_set*pt),dg); default : Print(DFUN,TextByLanguage("Неправильный тип ордера: ","Invalid order type: "),EnumToString(order_type)); return 0; } } //+------------------------------------------------------------------+
Die Lösung ist einfach — order_type in switch wird umgewandelt in ganze Zahlen:
//+------------------------------------------------------------------+ //| Rückgabe des Preises der korrekten Order-Platzierung | //| relative zum StopLevel | //+------------------------------------------------------------------+ double CorrectPricePending(const string symbol_name,const ENUM_ORDER_TYPE order_type,const double price_set,const double price=0,const int spread_multiplier=2) { double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT),pp=0; int lv=StopLevel(symbol_name,spread_multiplier), dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS); switch((int)order_type) { case ORDER_TYPE_BUY_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : price); return NormalizeDouble(fmin(pp-lv*pt,price_set),dg); case ORDER_TYPE_BUY_STOP : case ORDER_TYPE_BUY_STOP_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : price); return NormalizeDouble(fmax(pp+lv*pt,price_set),dg); case ORDER_TYPE_SELL_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : price); return NormalizeDouble(fmax(pp+lv*pt,price_set),dg); case ORDER_TYPE_SELL_STOP : case ORDER_TYPE_SELL_STOP_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : price); return NormalizeDouble(fmin(pp-lv*pt,price_set),dg); default : Print(DFUN,TextByLanguage("Неправильный тип ордера: ","Invalid order type: "),EnumToString(order_type)); return 0; } } //+------------------------------------------------------------------+ //| Rückgabe des Preises der korrekten Order-Platzierung | //| relative zum StopLevel | //+------------------------------------------------------------------+ double CorrectPricePending(const string symbol_name,const ENUM_ORDER_TYPE order_type,const int distance_set,const double price=0,const int spread_multiplier=2) { double pt=SymbolInfoDouble(symbol_name,SYMBOL_POINT),pp=0; int lv=StopLevel(symbol_name,spread_multiplier), dg=(int)SymbolInfoInteger(symbol_name,SYMBOL_DIGITS); switch((int)order_type) { case ORDER_TYPE_BUY_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : price); return NormalizeDouble(fmin(pp-lv*pt,pp-distance_set*pt),dg); case ORDER_TYPE_BUY_STOP : case ORDER_TYPE_BUY_STOP_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_ASK) : price); return NormalizeDouble(fmax(pp+lv*pt,pp+distance_set*pt),dg); case ORDER_TYPE_SELL_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : price); return NormalizeDouble(fmax(pp+lv*pt,pp+distance_set*pt),dg); case ORDER_TYPE_SELL_STOP : case ORDER_TYPE_SELL_STOP_LIMIT : pp=(price==0 ? SymbolInfoDouble(symbol_name,SYMBOL_BID) : price); return NormalizeDouble(fmin(pp-lv*pt,pp-distance_set*pt),dg); default : Print(DFUN,TextByLanguage("Неправильный тип ордера: ","Invalid order type: "),EnumToString(order_type)); return 0; } } //+------------------------------------------------------------------+
Kompilieren wir. Jetzt gibt es einen Fehler in der Datei Order.mqh — MQL4 kennt nicht diese Konstanten: ORDER_FILLING_RETURN,
ORDER_TIME_GTC,
ORDER_REASON_SL,
ORDER_REASON_TP und ORDER_REASON_EXPERT.
//+------------------------------------------------------------------+ //| 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_ORDER : 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_ORDER : 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_POSITION : res=::PositionGetInteger(POSITION_REASON); break; case ORDER_STATUS_MARKET_ORDER : 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 } //+------------------------------------------------------------------+
Fügen wir Makro-Substitutionen am Ende der ToMQL4.mqh-Datei hinzu (ich werde hier, um Platz zu sparen, keine vollständige Liste geben):
//+------------------------------------------------------------------+ //| Order types, execution policy, lifetime, reasons | //+------------------------------------------------------------------+ #define ORDER_TYPE_CLOSE_BY (8) #define ORDER_TYPE_BUY_STOP_LIMIT (9) #define ORDER_TYPE_SELL_STOP_LIMIT (10) #define ORDER_FILLING_RETURN (2) #define ORDER_TIME_GTC (0) #define ORDER_REASON_EXPERT (3) #define ORDER_REASON_SL (4) #define ORDER_REASON_TP (5) //+------------------------------------------------------------------+ #endif
Eine weitere Zusammenstellung führt uns zu der fehlenden MQL5-Funktion HistoryOrderGetTicket() in der Datei HistoryCollection.mqh der Methode CHistoryCollection::OrderSearch(). Die Codeanalyse schlägt vor, hier bedingte Kompilierungsanweisungen anzuwenden. Lassen Sie uns die Methode ergänzen:
//+------------------------------------------------------------------+ //| Liefert den Typ und das Ticket der "verlorenen" Auftrags zurück | //+------------------------------------------------------------------+ ulong CHistoryCollection::OrderSearch(const int start,ENUM_ORDER_TYPE &order_type) { ulong order_ticket=0; #ifdef __MQL5__ for(int i=start-1;i>=0;i--) { ulong ticket=::HistoryOrderGetTicket(i); if(ticket==0) continue; ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::HistoryOrderGetInteger(ticket,ORDER_TYPE); if(this.IsPresentOrderInList(ticket,type)) continue; order_ticket=ticket; order_type=type; } #else for(int i=start-1;i>=0;i--) { if(!::OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue; ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)::OrderType(); ulong ticket=::OrderTicket(); if(ticket==0 || type<ORDER_TYPE_BUY_LIMIT || type>ORDER_TYPE_SELL_STOP) continue; if(this.IsPresentOrderInList(ticket,type)) continue; order_ticket=ticket; order_type=type; } #endif return order_ticket; } //+------------------------------------------------------------------+
Alles, was für MQL5 gedacht ist sind eingerahmt von der Direktive #ifdef __MQL5__. Der Code wird für MQL4 nach der #else Direktive bis zu #endif hinzugefügt.
Der nächste Fehler befindet sich im Klassenkonstruktor CEvent. Ergänzen wir den Code mit den gleichen bedingten Kompilierungsanweisungen:
//+------------------------------------------------------------------+ //| Konstruktor | //+------------------------------------------------------------------+ CEvent::CEvent(const ENUM_EVENT_STATUS event_status,const int event_code,const ulong ticket) : m_event_code(event_code),m_digits(0) { this.m_long_prop[EVENT_PROP_STATUS_EVENT] = event_status; this.m_long_prop[EVENT_PROP_TICKET_ORDER_EVENT] = (long)ticket; this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; this.m_digits_acc=#ifdef __MQL4__ 2 #else (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #endif; this.m_chart_id=::ChartID(); } //+------------------------------------------------------------------+
Wenn wir ein Hedging-Konto überprüfen, sehen wir uns dem Fehlen
eines konstanten Fehlers gegenüber, daher einfach
return true auf
einmal, da alle Konten im MetaTrader 4 Hedging-Konten sind.
Auch beim Empfangen der Anzahl der Dezimalstellen in der Kontowährung, return
2, da MQL4 diesen Wert nicht erhalten kann.
Die nächste Kompilierung führt uns zur Methode CEventsCollection::NewDealEventHedge() — ein Ereignis für ein MetaTrader 5 Hedging-Konto zu erhalten. Es funktioniert mit Deals, die in MQL4 fehlen. Vorübergehendes Deaktivieren der Methode durch Einschließen des gesamten Methodencodes im Rahmen der bedingten Kompilierung:
Fügen wir die Direktive am Anfang der Methode ein.
//+------------------------------------------------------------------+ //| Create a hedging account event | //+------------------------------------------------------------------+ void CEventsCollection::NewDealEventHedge(COrder* deal,CArrayObj* list_history,CArrayObj* list_market) { #ifdef __MQL5__ double ask=::SymbolInfoDouble(deal.Symbol(),SYMBOL_ASK); double bid=::SymbolInfoDouble(deal.Symbol(),SYMBOL_BID); //--- Markteintritt
und am Ende der Methode
#endif } //+------------------------------------------------------------------+
Als Nächstes erhalten wir den Fehler in der Methode CEventsCollection::NewDealEventNetto() — das Erstellen eines Ereignisses für ein
Netting-Konto. Die Lösung ist die gleiche wie im vorherigen Fall — umgeben wir den gesamten Methodencode NewDealEventNetto() mit der
Direktive zur bedingten Kompilierung.
Kompilieren und behandeln wir den Fehler der unbekannten Konstanten DEAL_ENTRY_IN in der Methode CEventsCollection::GetListAllDealsInByPosID(). Hinzufügen der notwendigen Enumeration zur Datei ToMQL4.mqh (wir könnten die bedingte Kompilierung wieder verwenden, um den Code zu deaktivieren, aber wir können diese Aufzählung später benötigen):
//+------------------------------------------------------------------+ //| MQL5 deal types | //+------------------------------------------------------------------+ enum ENUM_DEAL_TYPE { DEAL_TYPE_BUY, DEAL_TYPE_SELL, DEAL_TYPE_BALANCE, DEAL_TYPE_CREDIT, DEAL_TYPE_CHARGE, DEAL_TYPE_CORRECTION, DEAL_TYPE_BONUS, DEAL_TYPE_COMMISSION, DEAL_TYPE_COMMISSION_DAILY, DEAL_TYPE_COMMISSION_MONTHLY, DEAL_TYPE_COMMISSION_AGENT_DAILY, DEAL_TYPE_COMMISSION_AGENT_MONTHLY, DEAL_TYPE_INTEREST, DEAL_TYPE_BUY_CANCELED, DEAL_TYPE_SELL_CANCELED, DEAL_DIVIDEND, DEAL_DIVIDEND_FRANKED, DEAL_TAX }; //+------------------------------------------------------------------+ //| Position change method | //+------------------------------------------------------------------+ enum ENUM_DEAL_ENTRY { DEAL_ENTRY_IN, DEAL_ENTRY_OUT, DEAL_ENTRY_INOUT, DEAL_ENTRY_OUT_BY }; //+------------------------------------------------------------------+ //| Open position direction | //+------------------------------------------------------------------+ enum ENUM_POSITION_TYPE { POSITION_TYPE_BUY, POSITION_TYPE_SELL }; //+------------------------------------------------------------------+
Als Nächstes kommen wir zu dem bereits bekannten Fehler, bei Prüfen eine Hedging-Kontos, aber jetzt sitzt er im Konstruktor der Klasse Event Collection. Reparieren wir es:
//+------------------------------------------------------------------+ //| Konstruktor | //+------------------------------------------------------------------+ CEventsCollection::CEventsCollection(void) : m_trade_event(TRADE_EVENT_NO_EVENT),m_trade_event_code(TRADE_EVENT_FLAG_NO_EVENT) { this.m_list_events.Clear(); this.m_list_events.Sort(SORT_BY_EVENT_TIME_EVENT); this.m_list_events.Type(COLLECTION_EVENTS_ID); this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; this.m_chart_id=::ChartID(); ::ZeroMemory(this.m_tick); } //+------------------------------------------------------------------+
Als Nächstes implementieren wir die gleiche Korrektur im Klassenkonstruktor CEngine:
//+------------------------------------------------------------------+ //| CEngine Konstruktor | //+------------------------------------------------------------------+ CEngine::CEngine() : m_first_start(true),m_acc_trade_event(TRADE_EVENT_NO_EVENT) { ::ResetLastError(); if(!::EventSetMillisecondTimer(TIMER_FREQUENCY)) Print(DFUN,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError()); this.m_list_counters.Sort(); this.m_list_counters.Clear(); this.CreateCounter(COLLECTION_COUNTER_ID,COLLECTION_COUNTER_STEP,COLLECTION_PAUSE); this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; } //+------------------------------------------------------------------+
Alles ist eingestellt. Jetzt kann die ganze Bibliothek ohne Fehler kompiliert werden. Jetzt müssen wir es starten. Jetzt müssen wir ihn starten. Da wir einige Methoden mit bedingter Kompilierung deaktiviert haben, müssen wir sie für die Arbeit mit MetaTrader 4 entwickeln.
In MQL5 sind Saldenoperationen Deals. Sie finden Sie in der Liste der historischen Aufträge und Deals. In MQL4 sind Saldenoperationen Aufträge vom Typ ORDER_TYPE_BALANCE (6) und ORDER_TYPE_CREDIT (7). Deshalb habe ich eine eigene Klasse eines Objekts für Saldenoperationen für MQL4 erstellt, die in der Liste der historischen Orders und Positionen gespeichert ist.
Wir erstellen die neue Klasse CHistoryBalance in Verzeichnis \MQL4\Include\DoEasy\Objects\Orders in der Datei HistoryBalance.mqh. COrder sollte eine Basisklasse sein:
//+------------------------------------------------------------------+ //| HistoryBalance.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/de/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/de/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include-Dateien | //+------------------------------------------------------------------+ #include "Order.mqh" //+------------------------------------------------------------------+ //| Historical balance operation | //+------------------------------------------------------------------+ class CHistoryBalance : public COrder { public: //--- Konstructor CHistoryBalance(const ulong ticket) : COrder(ORDER_STATUS_BALANCE,ticket) {} //--- Unterstützte Deal-Eigenschaften (1) real, (2) integer virtual bool SupportProperty(ENUM_ORDER_PROP_INTEGER property); virtual bool SupportProperty(ENUM_ORDER_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_ORDER_PROP_STRING property); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| Integer-Eigenschaft unterstützt, sonst 'false' | //+------------------------------------------------------------------+ bool CHistoryBalance::SupportProperty(ENUM_ORDER_PROP_INTEGER property) { if(property==ORDER_PROP_TICKET || property==ORDER_PROP_TIME_OPEN || property==ORDER_PROP_STATUS || property==ORDER_PROP_TYPE || property==ORDER_PROP_REASON ) return true; return false; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| Double-Eigenschaft, sonst 'false' | //+------------------------------------------------------------------+ bool CHistoryBalance::SupportProperty(ENUM_ORDER_PROP_DOUBLE property) { return(property==ORDER_PROP_PROFIT ? true : false); } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| String-Eigenschaft, sonst 'false' | //+------------------------------------------------------------------+ bool CHistoryBalance::SupportProperty(ENUM_ORDER_PROP_STRING property) { if(property==ORDER_PROP_SYMBOL || property==ORDER_PROP_EXT_ID) return false; return true; } //+------------------------------------------------------------------+
Die Klasse enthält für uns nichts Neues. Wir haben bereits alle historischen Orderklassen im zweiten Teil der Bibliotheksbeschreibung besprochen.
Wir haben zwei Arten von Saldenoperationen — Saldenoperation und die Gutschrift. Dementsprechend haben ihre Typen die Zahlenwerte 6 und 7. Wir werden für beide Typen eine einzige Klasse der Saldenoperationen verwenden und einen bestimmten Typ in der Auftragseigenschaft "Ursache" klären.
Fügen wir der Datei ToMQL4.mqh die zwei fehlenden "Ursachen" der Orders hinzu:
//+------------------------------------------------------------------+ //| Order types, execution policy, lifetime, reasons | //+------------------------------------------------------------------+ #define ORDER_TYPE_CLOSE_BY (8) #define ORDER_TYPE_BUY_STOP_LIMIT (9) #define ORDER_TYPE_SELL_STOP_LIMIT (10) #define ORDER_FILLING_RETURN (2) #define ORDER_TIME_GTC (0) #define ORDER_REASON_EXPERT (3) #define ORDER_REASON_SL (4) #define ORDER_REASON_TP (5) #define ORDER_REASON_BALANCE (6) #define ORDER_REASON_CREDIT (7) //+------------------------------------------------------------------+
Da wir eine neue Klasse haben, die von der abstrakten Orderklasse abgeleitet ist, müssen wir die fehlende Funktionsweise in COrder hinzufügen.
Ersetzen wir in der Methode COrder::OrderPositionID() die Rückgabe der Magicnummer für MQL4
//+------------------------------------------------------------------+ //| Rückgabe der Positions-ID | //+------------------------------------------------------------------+ long COrder::OrderPositionID(void) const { #ifdef __MQL4__ return ::OrderMagicNumber(); #else
durch die Rückgabe des Tickets (eine Art PositionID für MQL4-Positionen soll später implementiert werden):
//+------------------------------------------------------------------+ //| Rückgabe der Positions-ID | //+------------------------------------------------------------------+ long COrder::OrderPositionID(void) const { #ifdef __MQL4__ return ::OrderTicket(); #else
Die Methode, die den Auftragsstatus in MQL4 zurückgibt, gibt immer ORDER_STATE_FILLED aus der Enumeration
ENUM_ORDER_STATE zurück, was bei Remote-Pending-Orders nicht der Fall ist. Implementieren wir die Prüfung des Auftragsstatus,
und wenn es sich um einen Remote-Pending-Order handelt, geben wir ORDER_STATE_CANCELED zurück.
//+------------------------------------------------------------------+ //| Rückgabe des des Auftragsstatus | //+------------------------------------------------------------------+ long COrder::OrderState(void) const { #ifdef __MQL4__ return(this.Status()==ORDER_STATUS_HISTORY_ORDER ? ORDER_STATE_FILLED : ORDER_STATE_CANCELED); #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_STATE); break; case ORDER_STATUS_MARKET_ORDER : case ORDER_STATUS_MARKET_PENDING : res=::OrderGetInteger(ORDER_STATE); break; case ORDER_STATUS_MARKET_POSITION : case ORDER_STATUS_DEAL : default : res=0; break; } return res; #endif } //+------------------------------------------------------------------+
Fügen wir die beiden neu hinzugefügten "Ursachen" zu der Methode hinzu, die die Auftragsursache für MQL4 zurückgibt:
//+------------------------------------------------------------------+ //| Grund oder Quelle der Order | //+------------------------------------------------------------------+ long COrder::OrderReason(void) const { #ifdef __MQL4__ return ( this.TypeOrder()==ORDER_TYPE_BALANCE ? ORDER_REASON_BALANCE : this.TypeOrder()==ORDER_TYPE_CREDIT ? ORDER_REASON_CREDIT : this.OrderCloseByStopLoss() ? ORDER_REASON_SL : this.OrderCloseByTakeProfit() ? ORDER_REASON_TP : this.OrderMagicNumber()!=0 ? ORDER_REASON_EXPERT : WRONG_VALUE ); #else
In unserem Fall gibt die Methode, die das unausgeführtes Volumen zurückgibt, für MQL4 immer eine Order-Losgröße zurück, was für Positionen falsch ist. Für Remot-Pending-Order werden wir eine Lot-Order zurückgeben, aber für Positionen Null:
//+------------------------------------------------------------------+ //| Rückgabe des nicht ausgeführten Volumens | //+------------------------------------------------------------------+ double COrder::OrderVolumeCurrent(void) const { #ifdef __MQL4__ return(this.Status()==ORDER_STATUS_HISTORY_PENDING ? ::OrderLots() : 0); #else
Fügen Sie Beschreibungen der beiden neuen "Ursachen" in der Methode hinzu, die die Ursachenbeschreibung der Order zurückgibt. Bei der Saldenoperationo und der Gutschrift überprüfen wir den Gewinn. Wenn er Null überschreitet, werden die Gelder eingezahlt, andernfalls werden die Gelder abgehoben:
//+------------------------------------------------------------------+ //| Reason description | //+------------------------------------------------------------------+ 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") : this.Comment()=="cancelled" ? TextByLanguage("Отменён","Cancelled") : this.Reason()==ORDER_REASON_BALANCE ? ( this.Profit()>0 ? TextByLanguage("Пополнение баланса","Deposit of funds on the account balance") : TextByLanguage("Снятие средств с баланса","Withdrawal from the balance") ) : this.Reason()==ORDER_REASON_CREDIT ? ( this.Profit()>0 ? TextByLanguage("Начисление кредитных средств","Received credit funds") : TextByLanguage("Изъятие кредитных средств","Withdrawal of credit") ) : TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") ); #else
Außerdem wurden einige kleinere Änderungen vorgenommen. Sie sind zu unbedeutend, um hier beschrieben zu werden. Sie beziehen sich hauptsächlich auf einen Text, der im Journal von MQL5/MQL4 angezeigt wird. Alle Bearbeitungen sind in den Bibliotheksdateien verfügbar, die dem Artikel beigefügt sind.
Nun verbessern wir die Klasse der historischen Kollektion in der Datei HistoryCollection.mqh.
Zuerst muss die
neue Klassendatei eingebunden werden:
//+------------------------------------------------------------------+ //| Include-Dateien | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Orders\HistoryOrder.mqh" #include "..\Objects\Orders\HistoryPending.mqh" #include "..\Objects\Orders\HistoryDeal.mqh" #ifdef __MQL4__ #include "..\Objects\Orders\HistoryBalance.mqh" #endif //+------------------------------------------------------------------+
Da wir die Klasse CHistoryBalance nur für die MQL4-Version der Bibliothek benötigen, ist die Datei dieser Klasse in den Anweisungen zur
bedingten Kompilierung für MQL4 enthalten.
Jetzt haben wir eine neue Klasse der Saldenoperationen. Um sie zu entwickeln und in die Kollektion zu stellen, müssen wir die
Prüfung von Auftragstypen auf die Art eines Saldos und einer Kreditoperation hinzufügen und sie in der Methode Refresh() der
Klasse CHistoryCollection für MQL4 zur Kollektion hinzufügen:
//+------------------------------------------------------------------+ //| Aktualisieren der Liste der Aufträge und Deals | //+------------------------------------------------------------------+ void CHistoryCollection::Refresh(void) { #ifdef __MQL4__ int total=::OrdersHistoryTotal(),i=m_index_order; for(; i<total; i++) { if(!::OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue; ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)::OrderType(); //--- Closed positions if(order_type<ORDER_TYPE_BUY_LIMIT) { CHistoryOrder *order=new CHistoryOrder(::OrderTicket()); if(order==NULL) continue; if(!this.m_list_all_orders.InsertSort(order)) { ::Print(DFUN,TextByLanguage("Не удалось добавить ордер в список","Could not add order to the list")); delete order; } } //--- Balance/credit operations else if(order_type>ORDER_TYPE_SELL_STOP) { CHistoryBalance *order=new CHistoryBalance(::OrderTicket()); if(order==NULL) continue; if(!this.m_list_all_orders.InsertSort(order)) { ::Print(DFUN,TextByLanguage("Не удалось добавить ордер в список","Could not add order to the list")); delete order; } } else { //--- Entfernte Pending-Order CHistoryPending *order=new CHistoryPending(::OrderTicket()); if(order==NULL) continue; if(!this.m_list_all_orders.InsertSort(order)) { ::Print(DFUN,TextByLanguage("Не удалось добавить ордер в список","Could not add order to the list")); delete order; } } } //--- int delta_order=i-m_index_order; this.m_index_order=i; this.m_delta_order=delta_order; this.m_is_trade_event=(this.m_delta_order!=0 ? true : false); //--- __MQL5__ #elseLassen Sie uns einige Korrekturen in der historischen Orderklasse vornehmen:
//+------------------------------------------------------------------+ //| Return 'true' if an order supports the passed | //| Double-Eigenschaft, sonst 'false' | //+------------------------------------------------------------------+ bool CHistoryOrder::SupportProperty(ENUM_ORDER_PROP_DOUBLE property) { if( #ifdef __MQL5__ property==ORDER_PROP_PROFIT || property==ORDER_PROP_PROFIT_FULL || property==ORDER_PROP_SWAP || property==ORDER_PROP_COMMISSION || property==ORDER_PROP_PRICE_CLOSE || ( property==ORDER_PROP_PRICE_STOP_LIMIT && ( this.TypeOrder()<ORDER_TYPE_BUY_STOP_LIMIT || this.TypeOrder()>ORDER_TYPE_SELL_STOP_LIMIT ) ) #else property==ORDER_PROP_PRICE_STOP_LIMIT && this.Status()==ORDER_STATUS_HISTORY_ORDER #endif ) return false; return true; } //+------------------------------------------------------------------+
Bisher wurde der Preis einer StopLimit-Order in MQL5 nicht
an das Journal weitergegeben. Deshalb habe ich einen Check implementiert:
wenn die geprüfte Eigenschaft ein
StopLimit-Orderpreis ist, und wenn ein Auftragstyp nicht vom Typ
StopLimit ist, wird die Eigenschaft nicht verwendet. Andernfalls handelt es sich um eine StopLimit-Order und die Eigenschaft ist
notwendig.
In MQL4 wird ein StopLimit-Orderpreis nicht für
Positionen verwendet.
Damit ist die Verbesserung der ersten Stufe der Kompatibilität mit MQL4 abgeschlossen.
Tests
Zu Testzwecken nehmen wir den ES TestDoEasyPart03_1.mq5 aus \MQL5\Experts\TestDoEasy\Part03 und speichern ihn unter dem Namen TestDoEasyPart09.mq4
im Ordner für MQL4 EAs
\MQL4\Experts\TestDoEasyPart09.
Der EA wird ohne Änderungen kompiliert, aber wenn wir einen Blick auf den Code werfen, stellt sich heraus, dass er die Liste der Deals verwendet, die in MQL4 fehlen:
//--- Enumerationen enum ENUM_TYPE_ORDERS { TYPE_ORDER_MARKET, // Marktorder TYPE_ORDER_PENDING, // Pending-Order TYPE_ORDER_DEAL // Deals }; //--- Eingabeparameter //+------------------------------------------------------------------+ //| Initialisierungsfunktion des Experten | //+------------------------------------------------------------------+ int OnInit() { //--- Aktualisieren der Historie history.Refresh(); //--- get the collection list within the date range CArrayObj* list=history.GetListByTime(InpTimeBegin,InpTimeEnd,SELECT_BY_TIME_CLOSE); if(list==NULL) { Print("Could not get collection list"); return INIT_FAILED; } int total=list.Total(); for(int i=0;i<total;i++) { //--- Abrufen des Auftrags aus der Liste COrder* order=list.At(i); if(order==NULL) continue; //--- Falls es ein Deal ist if(order.Status()==ORDER_STATUS_DEAL && InpOrderType==TYPE_ORDER_DEAL) order.Print(); //--- Falls es eine historische Marktorder ist if(order.Status()==ORDER_STATUS_HISTORY_ORDER && InpOrderType==TYPE_ORDER_MARKET) order.Print(); //--- Falles es eine entfernte Pending-Order ist if(order.Status()==ORDER_STATUS_HISTORY_PENDING && InpOrderType==TYPE_ORDER_PENDING) order.Print(); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Ersetzen wir einfach diese Deals durch Saldenoperationen. In diesem Fall verwenden wir die bedingte Kompilierung direkt im EA, was für das Endprodukt nicht korrekt ist, wo alle Aktionen zur Abgrenzung nach Sprachversionen für den Benutzer verborgen sein sollten. Aber in diesem Fall testen wir einfach die Ergebnisse der Bibliotheksverbesserung, also ist das keine große Sache.
Fügen wir kleinere Änderungen am EA-Code hinzu, die MQL5-Deals durch MQL4 Saldenoperationen ersetzen:
//+------------------------------------------------------------------+ //| TestDoEasyPart03_1.mq4 | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/de/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/de/users/artmedia70" #property version "1.00" //--- includes #include <DoEasy\Collections\HistoryCollection.mqh> //--- Enumerationen enum ENUM_TYPE_ORDERS { TYPE_ORDER_MARKET, // Marktorder TYPE_ORDER_PENDING, // Pending-Order #ifdef __MQL5__ TYPE_ORDER_DEAL // Deals #else TYPE_ORDER_BALANCE // Balance/Credit #endif }; //--- Eingabeparameter input ENUM_TYPE_ORDERS InpOrderType = TYPE_ORDER_MARKET; // Show type: input datetime InpTimeBegin = 0; // Start date of required range input datetime InpTimeEnd = END_TIME; // End date of required range //--- Globale Variablen CHistoryCollection history; //+------------------------------------------------------------------+ //| Initialisierungsfunktion des Experten | //+------------------------------------------------------------------+ int OnInit() { //--- Aktualisieren der Historie history.Refresh(); //--- get the collection list within the date range CArrayObj* list=history.GetListByTime(InpTimeBegin,InpTimeEnd,SELECT_BY_TIME_CLOSE); if(list==NULL) { Print("Could not get collection list"); return INIT_FAILED; } int total=list.Total(); for(int i=0;i<total;i++) { //--- Abrufen des Auftrags aus der Liste COrder* order=list.At(i); if(order==NULL) continue; //--- Falls es ein Deal ist #ifdef __MQL5__ if(order.Status()==ORDER_STATUS_DEAL && InpOrderType==TYPE_ORDER_DEAL) order.Print(); #else //--- if this is a balance/credit operation if(order.Status()==ORDER_STATUS_BALANCE && InpOrderType==TYPE_ORDER_BALANCE) order.Print(); #endif //--- Falls es eine historische Marktorder ist if(order.Status()==ORDER_STATUS_HISTORY_ORDER && InpOrderType==TYPE_ORDER_MARKET) order.Print(); //--- Falles es eine entfernte Pending-Order ist if(order.Status()==ORDER_STATUS_HISTORY_PENDING && InpOrderType==TYPE_ORDER_PENDING) order.Print(); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Deinitialisierungsfunktion des Experten | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Experten Funktion OnTick | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+
Kompilieren und starten wir den EA im Terminal (der Test EA aus dem dritten Artikel funktioniert nur in OnInit(), so dass er die gewünschte historische Kollektionsliste einmalig nach dem Start oder nach Änderung der Liste in den Einstellungen anzeigt).
Bevor wir den EA starten, wählen wir die Option "Ganze Historie" im Kontextmenü der Registerkarte "Kontohistorie" des Terminals, da in MetaTrader 4 die Menge der für Anwendungen verfügbaren Historie von einer in der Registerkarte ausgewählten Größe für die Historie abhängt.
In den Einstellungen wird Saldo/Guthaben ausgewählt und die allererste Einlage wird im Journal angezeigt:
Nun müssen wir prüfen, ob die Suche und Anzeige von geschlossenen Positionen korrekt ist. Seit ich vor kurzem ein MetaTrader 4 Konto eröffnet habe, gab es keinen Handel damit. Ich öffnete einen Verkauf, setzte StopLoss und TakeProfit ein und ging, um Kaffee zu machen. Als ich zurückkam, wurde die Position durch den Stop-Loss geschlossen, woraufhin sich der Markt in Richtung der Verkaufsposition zu bewegen begann. Ja, so ist es immer! :)
Aber jetzt gibt es eine geschlossene Position für den Test.
"Market Orders" wird in den Einstellungen ausgewählt:
Nun überprüfen wir die Liste der entfernten Pending-Orders. Ich habe ein paar Orders platziert und sie danach entfernt.
"Pending-Orders" ist in den
Einstellungen ausgewählt:
Die Liste der entfernten Pending-Orders wird ebenfalls angezeigt.
Was kommt als Nächstes?
Im nächsten Artikel werden wir die Möglichkeit implementieren, mit Marktpositionen und aktiven Pending-Orders in MQL4 zu arbeiten.
Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit den Dateien der Test-EAs angehängt, die Sie herunterladen und
testen können.
Stellen Sie Ihre Fragen, Kommentare und Vorschläge in den Kommentaren.
Frühere Artikel dieser Serie:
Teil 1. Konzept, Datenverwaltung.
Teil
2. Erhebung (Collection) historischer Aufträge und Deals.
Teil 3. Erhebung
(Collection) von Marktorders und Positionen, Organisieren der Suche
Teil 4.
Handelsereignisse. Konzept.
Teil 5. Klassen und Kollektionen von
Handelsereignissen. Senden von Ereignissen an das Programm.
Teil 6. Ereignisse
auf Netting-Konten.
Teil 7. Ereignis der Aktivierung einer StopLimit-Order,
Vorbereiten der Funktionsweise bei Änderungen von Orders und Positionen.
Teil
8. Ereignisse von Änderungen von Orders und Positionen.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/6651





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.