Preise in der DoEasy-Bibliothek (Teil 63): Markttiefe und deren abstrakte Anforderungsklasse
Inhalt
- Konzept
- Abstraktes Klasse des Auftragsobjekts der Markttiefe
- Abgeleitete Klassen der abstrakten Klasse des Auftragsobjekts
- Test
- Was kommt als Nächstes?
Konzept
In diesem Artikel beginne ich mit der Implementierung der Funktionen für die Arbeit mit der Markttiefe (Depth of Market, DOM). Konzeptionell werden sich die Klassen für die Arbeit mit dem DOM nicht von allen bisher implementierten Bibliotheksklassen unterscheiden. Gleichzeitig werden wir eine Form des DOM haben, die Daten über die im DOM gespeicherten Aufträge enthält. Die Daten werden von der Funktion MarketBookGet() bezogen, wenn der Handler OnBookEvent() aktiviert ist. Bei einer DOM-Änderung wird ein Ereignis für jedes der Symbole im Handler aktiviert, die das aktive Abonnement für DOM-Ereignisse haben.
Die Struktur der DOM-Klasse soll also wie folgt aussehen:
- Das Klassenobjekt der DOM-Aufträge — das Objekt, das die Daten eines Auftrags aus mehreren Aufträgen beschreibt, die vom DOM erhalten werden, wenn die Funktion OnBookEvent() für ein Symbol ausgelöst wird;
- Die Form der DOM-Objektklasse — das Objekt, das die Daten aller Aufträge beschreibt, die gleichzeitig aus dem DOM erhalten werden, wenn OnBookEvent() für ein einzelnes Symbol ausgelöst wird — p1 Menge der Objekte, die die aktuelle DOM-Form bilden;
- Zeitreihenklasse, bestehend aus der Objektfolge p2, die bei jeder Aktivierung von OnBookEvent() für ein einzelnes Symbol in die Zeitreihenliste eingetragen wird;
- Die Kollektionsklasse der Zeitreihen der DOM-Daten aller verwendeten Symbole mit aktiviertem Abonnement auf DOM-Ereignisse.
Heute werde ich die Order-Objektklasse (1) implementieren und das Abrufen von DOM-Daten bei der Aktivierung von OnBookEvent() für das aktuelle Symbol testen.
Die Eigenschaften jeder Order werden in der Struktur MqlBookInfo festgelegt, die Daten im DOM bereitstellt:
- Auftragstyp aus der Enumeration ENUM_BOOK_TYPE
- Auftragspreis
- Auftragsvolumen
- Erweiterte Genauigkeit des Auftragsvolumens
DOM kann vier Ordertypen (aus der Enumeration ENUM_BOOK_TYPE) aufweisen:
- Verkaufsauftrag
- Verkaufsauftrag als Marktorder
- Kaufauftrag
- Kaufauftrag als Marktorder
Wie wir sehen können, gibt es vier Ordertypen — zwei Kauf- und zwei Verkaufsarten. Um alle Auftragstypen in zwei Seiten aufzuteilen, sollten wir eine weitere Eigenschaft zu den bereits vorhandenen hinzufügen — den Auftragsstatus, der seine Richtung angibt — Kauf- oder Verkaufsauftrag. Dies wird uns erlauben, alle Aufträge schnell ihrer Seiten zuzuweisen — Angebot und Nachfrage.
Das Objekt einer einzelnen DOM-Anfrage wird ähnlich wie Auftragsobjekte (sowie viele andere Bibliotheksobjekte) aufgebaut sein — wir werden ein Basisobjekt des abstrakten DOM-Auftrags und vier abhängige Objekte mit der Auftragstypangabe haben. Das Konzept, solche Objekte zu konstruieren, wurde bereits zu Beginn der Bibliotheksentwicklung in den ersten und zweiten Artikeln berücksichtigt.
Bevor wir die Klassen für die Arbeit mit dem DOM implementieren, fügen wir neue Bibliotheksnachrichten hinzu und verbessern leicht die Tick-Daten-Objektklassen. Fügen wir neue Nachrichtenindizes in \MQL5\Include\DoEasy\Data.mqh hinzu:
MSG_SYM_EVENT_SYMBOL_ADD, // Added symbol to Market Watch window MSG_SYM_EVENT_SYMBOL_DEL, // Symbol removed from Market Watch window MSG_SYM_EVENT_SYMBOL_SORT, // Changed location of symbols in Market Watch window MSG_SYM_SYMBOLS_MODE_CURRENT, // Work with current symbol only MSG_SYM_SYMBOLS_MODE_DEFINES, // Work with predefined symbol list MSG_SYM_SYMBOLS_MODE_MARKET_WATCH, // Work with Market Watch window symbols MSG_SYM_SYMBOLS_MODE_ALL, // Work with full list of all available symbols MSG_SYM_SYMBOLS_BOOK_ADD, // Subscribed to Depth of Market MSG_SYM_SYMBOLS_BOOK_DEL, // Unsubscribed from Depth of Market MSG_SYM_SYMBOLS_MODE_BOOK, // Subscription to Depth of Market MSG_SYM_SYMBOLS_ERR_BOOK_ADD, // Error subscribing to DOM MSG_SYM_SYMBOLS_ERR_BOOK_DEL, // Error unsubscribing from DOM //--- CAccount
...
//--- CTickSeries MSG_TICKSERIES_TEXT_TICKSERIES, // Tick series MSG_TICKSERIES_ERR_GET_TICK_DATA, // Failed to get tick data MSG_TICKSERIES_FAILED_CREATE_TICK_DATA_OBJ, // Failed to create tick data object MSG_TICKSERIES_FAILED_ADD_TO_LIST, // Failed to add tick data object to list MSG_TICKSERIES_TEXT_IS_NOT_USE, // Tick series not used. Set the flag using SetAvailable() MSG_TICKSERIES_REQUIRED_HISTORY_DAYS, // Requested number of days //--- CMarketBookOrd MSG_MBOOK_ORD_TEXT_MBOOK_ORD, // Order in DOM MSG_MBOOK_ORD_VOLUME, // Volume MSG_MBOOK_ORD_VOLUME_REAL, // Extended accuracy volume MSG_MBOOK_ORD_STATUS_BUY, // Buy side MSG_MBOOK_ORD_STATUS_SELL, // Sell side MSG_MBOOK_ORD_TYPE_SELL, // Sell order MSG_MBOOK_ORD_TYPE_BUY, // Buy order MSG_MBOOK_ORD_TYPE_SELL_MARKET, // Sell order by Market MSG_MBOOK_ORD_TYPE_BUY_MARKET, // Buy order by Market }; //+------------------------------------------------------------------+
und die Nachrichtentexte, die den neu hinzugefügten Indizes entsprechen:
{"В окно \"Обзор рынка\" добавлен символ","Added symbol to \"Market Watch\" window"},
{"Из окна \"Обзор рынка\" удалён символ","Removed from \"Market Watch\" window"},
{"Изменено расположение символов в окне \"Обзор рынка\"","Changed arrangement of symbols in \"Market Watch\" window"},
{"Работа только с текущим символом","Work only with the current symbol"},
{"Работа с предопределённым списком символов","Work with predefined list of symbols"},
{"Работа с символами из окна \"Обзор рынка\"","Working with symbols from \"Market Watch\" window"},
{"Работа с полным списком всех доступных символов","Work with full list of all available symbols"},
{"Осуществлена подписка на стакан цен ","Subscribed to Depth of Market"},
{"Осуществлена отписка от стакан цен ","Unsubscribed from Depth of Market"},
{"Подписка на стакан цен","Subscription to Depth of Market"},
{"Ошибка при подписке на стакан цен",""},
{"Ошибка при отписке от стакан цен",""},
//--- CAccount
...
//--- CMarketBookOrd {"Заявка в стакане цен","Order in Depth of Market"}, {"Объем","Volume"}, {"Объем c повышенной точностью","Volume Real"}, {"Сторона Buy","Buy side"}, {"Сторона Sell","Sell side"}, {"Заявка на продажу","Sell order"}, {"Заявка на покупку","Buy order"}, {"Заявка на продажу по рыночной цене","Sell order at market price"}, {"Заявка на покупку по рыночной цене","Buy order at market price"}, }; //+---------------------------------------------------------------------+
Hinzufügen der Anzeige von Meldungen über den Fehler beim Abonnieren des DOM in der Datei \MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh der Symbolobjektklasse:
//+------------------------------------------------------------------+ //| Subscribe to the Depth of Market | //+------------------------------------------------------------------+ bool CSymbol::BookAdd(void) { this.m_book_subscribed=(#ifdef __MQL5__ ::MarketBookAdd(this.m_name) #else false #endif); this.m_long_prop[SYMBOL_PROP_BOOKDEPTH_STATE]=this.m_book_subscribed; if(this.m_book_subscribed) ::Print(CMessage::Text(MSG_SYM_SYMBOLS_BOOK_ADD)+" "+this.m_name); else ::Print(CMessage::Text(MSG_SYM_SYMBOLS_ERR_BOOK_ADD)+": "+CMessage::Text(::GetLastError())); return this.m_book_subscribed; } //+------------------------------------------------------------------+
und das Gleiche für das Storno des Abonnements
//+------------------------------------------------------------------+ //| Close the market depth | //+------------------------------------------------------------------+ bool CSymbol::BookClose(void) { //--- If the DOM subscription flag is off, subscription is disabled (or not enabled yet). Return 'true' if(!this.m_book_subscribed) return true; //--- Save the result of unsubscribing from the DOM bool res=( #ifdef __MQL5__ ::MarketBookRelease(this.m_name) #else true #endif ); //--- If unsubscribed successfully, reset the DOM subscription flag and write the status to the object property if(res) { this.m_long_prop[SYMBOL_PROP_BOOKDEPTH_STATE]=this.m_book_subscribed=false; ::Print(CMessage::Text(MSG_SYM_SYMBOLS_BOOK_DEL)+" "+this.m_name); } else { this.m_long_prop[SYMBOL_PROP_BOOKDEPTH_STATE]=this.m_book_subscribed=true; ::Print(CMessage::Text(MSG_SYM_SYMBOLS_ERR_BOOK_DEL)+": "+CMessage::Text(::GetLastError())); } //--- Return the result of unsubscribing from DOM return res; } //+------------------------------------------------------------------+
Aus der Methode für die Aktualisierung der Tick-Reihe der Klasse der Tick-Reihen in \MQL5\Include\DoEasy\Objects\Ticks\TickSeries.mqh, entfernen wir die Anzeige von Debugging-Kommentaren auf dem Symboldiagramm, die im vorherigen Artikel für Tests noch verblieben sind:
//+------------------------------------------------------------------+ //| Update the tick series list | //+------------------------------------------------------------------+ void CTickSeries::Refresh(void) { MqlTick ticks_array[]; if(IsNewTick()) { //--- Copy ticks from m_last_time time+1 ms to the end of history int err=ERR_SUCCESS; int total=::CopyTicksRange(this.Symbol(),ticks_array,COPY_TICKS_ALL,this.m_last_time+1,0); //--- If the ticks have been copied, create new tick data objects and add them to the list in the loop by their number if(total>0) { for(int i=0;i<total;i++) { //--- Create the tick object and add it to the list CDataTick *tick_obj=this.CreateNewTickObj(ticks_array[i]); if(tick_obj==NULL) break; //--- Write the last tick time for subsequent copying of newly arrived ticks long end_time=ticks_array[::ArraySize(ticks_array)-1].time_msc; if(this.Symbol()=="AUDUSD") Comment(DFUN,this.Symbol(),", copied=",total,", m_last_time=",TimeMSCtoString(m_last_time),", end_time=",TimeMSCtoString(end_time),", total=",DataTotal()); this.m_last_time=end_time; } //--- If the number of ticks in the list exceeds the default maximum number, //--- remove the calculated number of tick objects from the end of the list if(this.DataTotal()>TICKSERIES_MAX_DATA_TOTAL) { int total_del=m_list_ticks.Total()-TICKSERIES_MAX_DATA_TOTAL; for(int j=0;j<total_del;j++) this.m_list_ticks.Delete(j); } } } } //+------------------------------------------------------------------+
Die letzte Tick-Zeit wird jetzt sofort in der dafür vorgesehenen Variablen m_last_time gesetzt, weil ich im vorigen Artikel die Verifikationsdaten als Symbolchart-Kommentar mit den vorherigen und aktuellen Tick-Zeiten anzeigen musste. Jetzt brauchen wir sie nicht mehr und die Zeit wird sofort in der Variablen gespeichert:
//+------------------------------------------------------------------+ //| Update the tick series list | //+------------------------------------------------------------------+ void CTickSeries::Refresh(void) { MqlTick ticks_array[]; if(IsNewTick()) { //--- Copy ticks from m_last_time time+1 ms to the end of history int err=ERR_SUCCESS; int total=::CopyTicksRange(this.Symbol(),ticks_array,COPY_TICKS_ALL,this.m_last_time+1,0); //--- If the ticks have been copied, create new tick data objects and add them to the list in the loop by their number if(total>0) { for(int i=0;i<total;i++) { //--- Create the tick object and add it to the list CDataTick *tick_obj=this.CreateNewTickObj(ticks_array[i]); if(tick_obj==NULL) break; //--- Write the last tick time for subsequent copying of newly arrived ticks this.m_last_time=ticks_array[::ArraySize(ticks_array)-1].time_msc; } //--- If the number of ticks in the list exceeds the default maximum number, //--- remove the calculated number of tick objects from the end of the list if(this.DataTotal()>TICKSERIES_MAX_DATA_TOTAL) { int total_del=m_list_ticks.Total()-TICKSERIES_MAX_DATA_TOTAL; for(int j=0;j<total_del;j++) this.m_list_ticks.Delete(j); } } } } //+------------------------------------------------------------------+
Abstraktes Klasse des Auftragsobjekts der Markttiefe
Wie bei allen Bibliotheksobjekten mit den Enumerationen zur Definition von Objekt-Eigenschaftskonstanten müssen wir auch für DOM-Aufträge Enumerationen von Integer-, Real- und String-Objekteigenschaften erstellen.
Fügen wir die Enumerationen von DOM-Auftragsobjekteigenschaften und -parametern in \MQL5\Include\DoEasy\Defines.mqh hinzu. Da ich kein Ereignismodell für die Arbeit mit den einzelnen Aufträgen im DOM implementieren werde (zu einem Zeitpunkt zeigt das Auftragsbuch den aktuellen Zustand aller Aufträge an, und deren Änderung führt zu seinem nächsten Zustand und wird bei der nächsten Aktivierung von OnBookEvent() verarbeitet), fügen wir einfach die Konstante, die den Code des nächsten Ereignisses angibt, nach dem letzten Code des DOM-Ereignisses hinzu, um die Identität der Konstanten aller Objekte zu erhalten und sie auf die gleiche Form zu bringen:
//+------------------------------------------------------------------+ //| Data for working with DOM | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| List of possible DOM events | //+------------------------------------------------------------------+ #define MBOOK_ORD_EVENTS_NEXT_CODE (SERIES_EVENTS_NEXT_CODE+1) // The code of the next event after the last DOM event code //+------------------------------------------------------------------+
Definieren wir die Enumeration mit den zwei möglichen Zuständen eines einzelnen DOM-Auftrags — Kauf- oder Verkaufsseite:
//+------------------------------------------------------------------+ //| Abstract DOM type (status) | //+------------------------------------------------------------------+ enum ENUM_MBOOK_ORD_STATUS { MBOOK_ORD_STATUS_BUY, // Buy side MBOOK_ORD_STATUS_SELL, // Sell side }; //+------------------------------------------------------------------+
Wenn wir alle Aufträge im DOM nach diesen Eigenschaften sortieren, können wir alle Aufträge im DOM, die entweder zur Nachfrage oder zum Angebot gehören, schnell nach diesen Eigenschaften auswählen.
Als Nächstes fügen wir Enumerationen der Eigenschaften integer, real und string von DOM-Auftragsobjekt-Eigenschaften hinzu:
//+------------------------------------------------------------------+ //| Integer properties of DOM order | //+------------------------------------------------------------------+ enum ENUM_MBOOK_ORD_PROP_INTEGER { MBOOK_ORD_PROP_STATUS = 0, // Order status MBOOK_ORD_PROP_TYPE, // Order type MBOOK_ORD_PROP_VOLUME, // Order volume }; #define MBOOK_ORD_PROP_INTEGER_TOTAL (3) // Total number of integer properties #define MBOOK_ORD_PROP_INTEGER_SKIP (0) // Number of integer DOM properties not used in sorting //+------------------------------------------------------------------+ //| Real properties of DOM order | //+------------------------------------------------------------------+ enum ENUM_MBOOK_ORD_PROP_DOUBLE { MBOOK_ORD_PROP_PRICE = MBOOK_ORD_PROP_INTEGER_TOTAL, // Order price MBOOK_ORD_PROP_VOLUME_REAL, // Extended accuracy order volume }; #define MBOOK_ORD_PROP_DOUBLE_TOTAL (2) // Total number of real properties #define MBOOK_ORD_PROP_DOUBLE_SKIP (0) // Number of real properties not used in sorting //+------------------------------------------------------------------+ //| String properties of DOM order | //+------------------------------------------------------------------+ enum ENUM_MBOOK_ORD_PROP_STRING { MBOOK_ORD_PROP_SYMBOL = (MBOOK_ORD_PROP_INTEGER_TOTAL+MBOOK_ORD_PROP_DOUBLE_TOTAL), // Order symbol name }; #define MBOOK_ORD_PROP_STRING_TOTAL (1) // Total number of string properties //+------------------------------------------------------------------+
Implementieren wir die Enumeration möglicher Kriterien für die Sortierung von Aufträgen im DOM entsprechend der erstellten Eigenschaften:
//+------------------------------------------------------------------+ //| Possible sorting criteria of DOM orders | //+------------------------------------------------------------------+ #define FIRST_MB_DBL_PROP (MBOOK_ORD_PROP_INTEGER_TOTAL-MBOOK_ORD_PROP_INTEGER_SKIP) #define FIRST_MB_STR_PROP (MBOOK_ORD_PROP_INTEGER_TOTAL-MBOOK_ORD_PROP_INTEGER_SKIP+MBOOK_ORD_PROP_DOUBLE_TOTAL-MBOOK_ORD_PROP_DOUBLE_SKIP) enum ENUM_SORT_MBOOK_ORD_MODE { //--- Sort by integer properties SORT_BY_MBOOK_ORD_STATUS = 0, // Sort by order status SORT_BY_MBOOK_ORD_TYPE, // Sort by order type SORT_BY_MBOOK_ORD_VOLUME, // Sort by order volume //--- Sort by real properties SORT_BY_MBOOK_ORD_PRICE = FIRST_MB_DBL_PROP, // Sort by order price SORT_BY_MBOOK_ORD_VOLUME_REAL, // Sort by extended accuracy order volume //--- Sort by string properties SORT_BY_MBOOK_ORD_SYMBOL = FIRST_MB_STR_PROP, // Sort by symbol name }; //+------------------------------------------------------------------+
Jetzt ist es möglich, die abstrakte Auftrags-Objektklasse im DOM zu erstellen.
Legen wir in \MQL5\Include\DoEasy\Objects\ den neuen Ordner Book\ an, der die Datei MarketBookOrd.mqh der Klasse CMarketBookOrd abgeleitet vom Basisobjekt aller CBaseObj Bibliotheksobjekte enthält:
//+------------------------------------------------------------------+ //| MarketBookOrd.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\..\Services\DELib.mqh" #include "..\..\Objects\BaseObj.mqh" //+------------------------------------------------------------------+ //| DOM abstract order class | //+------------------------------------------------------------------+ class CMarketBookOrd : public CBaseObj { private: int m_digits; // Number of decimal places long m_long_prop[MBOOK_ORD_PROP_INTEGER_TOTAL]; // Integer properties double m_double_prop[MBOOK_ORD_PROP_DOUBLE_TOTAL]; // Real properties string m_string_prop[MBOOK_ORD_PROP_STRING_TOTAL]; // String properties //--- Return the index of the array the (1) double and (2) string properties are actually located at int IndexProp(ENUM_MBOOK_ORD_PROP_DOUBLE property) const { return(int)property-MBOOK_ORD_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_MBOOK_ORD_PROP_STRING property) const { return(int)property-MBOOK_ORD_PROP_INTEGER_TOTAL-MBOOK_ORD_PROP_DOUBLE_TOTAL; } public: //--- Set object's (1) integer, (2) real and (3) string properties void SetProperty(ENUM_MBOOK_ORD_PROP_INTEGER property,long value) { this.m_long_prop[property]=value; } void SetProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property,double value) { this.m_double_prop[this.IndexProp(property)]=value; } void SetProperty(ENUM_MBOOK_ORD_PROP_STRING property,string value) { this.m_string_prop[this.IndexProp(property)]=value; } //--- Return object’s (1) integer, (2) real and (3) string property from the properties array long GetProperty(ENUM_MBOOK_ORD_PROP_INTEGER property) const { return this.m_long_prop[property]; } double GetProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property) const { return this.m_double_prop[this.IndexProp(property)]; } string GetProperty(ENUM_MBOOK_ORD_PROP_STRING property) const { return this.m_string_prop[this.IndexProp(property)]; } //--- Return itself CMarketBookOrd *GetObject(void) { return &this;} //--- Return the flag of the object supporting this property virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property) { return true; } virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property) { return true; } virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_STRING property) { return true; } //--- Get description of (1) integer, (2) real and (3) string properties string GetPropertyDescription(ENUM_MBOOK_ORD_PROP_INTEGER property); string GetPropertyDescription(ENUM_MBOOK_ORD_PROP_DOUBLE property); string GetPropertyDescription(ENUM_MBOOK_ORD_PROP_STRING property); //--- Display the description of object properties in the journal (full_prop=true - all properties, false - supported ones only) void Print(const bool full_prop=false); //--- Display a short description of the object in the journal virtual void PrintShort(void); //--- Return the object short name virtual string Header(void); //--- Compare CMarketBookOrd objects by all possible properties (to sort the lists by a specified order object property) virtual int Compare(const CObject *node,const int mode=0) const; //--- Compare CMarketBookOrd objects by all properties (to search for equal request objects) bool IsEqual(CMarketBookOrd* compared_req) const; //--- Default constructor CMarketBookOrd(){;} protected: //--- Protected parametric constructor CMarketBookOrd(const ENUM_MBOOK_ORD_STATUS status,const MqlBookInfo &book_info,const string symbol); public: //+-------------------------------------------------------------------+ //|Methods of a simplified access to the DOM request object properties| //+-------------------------------------------------------------------+ //--- Return order (1) status, (2) type and (3) order volume ENUM_MBOOK_ORD_STATUS Status(void) const { return (ENUM_MBOOK_ORD_STATUS)this.GetProperty(MBOOK_ORD_PROP_STATUS); } ENUM_BOOK_TYPE TypeOrd(void) const { return (ENUM_BOOK_TYPE)this.GetProperty(MBOOK_ORD_PROP_TYPE); } long Volume(void) const { return this.GetProperty(MBOOK_ORD_PROP_VOLUME); } //--- Return (1) the price and (2) extended accuracy order volume double Price(void) const { return this.GetProperty(MBOOK_ORD_PROP_PRICE); } double VolumeReal(void) const { return this.GetProperty(MBOOK_ORD_PROP_VOLUME_REAL); } //--- Return (1) order symbol and (2) symbol's Digits string Symbol(void) const { return this.GetProperty(MBOOK_ORD_PROP_SYMBOL); } int Digits() const { return this.m_digits; } //--- Return the description of order (1) type (ENUM_BOOK_TYPE) and (2) status (ENUM_MBOOK_ORD_STATUS) virtual string TypeDescription(void) const { return this.StatusDescription(); } string StatusDescription(void) const; }; //+------------------------------------------------------------------+
Der Aufbau der Klasse ist absolut identisch mit anderen Klassen von Bibliotheksobjekten. Ich habe sie schon oft erwähnt. Die ausführlichen Beschreibungen finden Sie im ersten und nachfolgenden Artikel.
Werfen wir einen Blick auf die Implementierung der Klassenmethoden.
Im parametrischen Konstruktor der geschlossenen Klasse setzen wir alle Objekteigenschaften gemäß der vom DOM an den Konstruktor übergebenen Auftragsstruktur:
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CMarketBookOrd::CMarketBookOrd(const ENUM_MBOOK_ORD_STATUS status,const MqlBookInfo &book_info,const string symbol) { //--- Save symbol’s Digits this.m_digits=(int)::SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Save integer object properties this.SetProperty(MBOOK_ORD_PROP_STATUS,status); this.SetProperty(MBOOK_ORD_PROP_TYPE,book_info.type); this.SetProperty(MBOOK_ORD_PROP_VOLUME,book_info.volume); //--- Save real object properties this.SetProperty(MBOOK_ORD_PROP_PRICE,book_info.price); this.SetProperty(MBOOK_ORD_PROP_VOLUME_REAL,book_info.volume_real); //--- Save additional object properties this.SetProperty(MBOOK_ORD_PROP_SYMBOL,(symbol==NULL || symbol=="" ? ::Symbol() : symbol)); } //+------------------------------------------------------------------+
Der Konstruktor erhält beim Anlegen eines neuen DOM-Auftragsobjekts auch den in Nachfolgeobjekten der Klasse angegebenen Auftragsstatus.
Die Methode des Vergleichs zweier CMarketBookOrd-Objekte anhand einer angegebenen Eigenschaft zur Definition der Gleichheit der angegebenen Eigenschaften zweier Objekte:
//+------------------------------------------------------------------+ //| Compare CMarketBookOrd objects | //| by a specified property | //+------------------------------------------------------------------+ int CMarketBookOrd::Compare(const CObject *node,const int mode=0) const { const CMarketBookOrd *obj_compared=node; //--- compare integer properties of two objects if(mode<MBOOK_ORD_PROP_INTEGER_TOTAL) { long value_compared=obj_compared.GetProperty((ENUM_MBOOK_ORD_PROP_INTEGER)mode); long value_current=this.GetProperty((ENUM_MBOOK_ORD_PROP_INTEGER)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } //--- compare real properties of two objects else if(mode<MBOOK_ORD_PROP_DOUBLE_TOTAL+MBOOK_ORD_PROP_INTEGER_TOTAL) { double value_compared=obj_compared.GetProperty((ENUM_MBOOK_ORD_PROP_DOUBLE)mode); double value_current=this.GetProperty((ENUM_MBOOK_ORD_PROP_DOUBLE)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } //--- compare string properties of two objects else if(mode<MBOOK_ORD_PROP_DOUBLE_TOTAL+MBOOK_ORD_PROP_INTEGER_TOTAL+MBOOK_ORD_PROP_STRING_TOTAL) { string value_compared=obj_compared.GetProperty((ENUM_MBOOK_ORD_PROP_STRING)mode); string value_current=this.GetProperty((ENUM_MBOOK_ORD_PROP_STRING)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } return 0; } //+------------------------------------------------------------------+
Die Methode erhalten das Objekt, dessen Eigenschaft mit der gleichen Eigenschaft des aktuellen Objekts verglichen werden soll. Wenn der angegebene Eigenschaftswert des verglichenen Objekts kleiner als der aktuelle ist, wird -1 zurückgegeben, wenn größer +1, wenn die Eigenschaften gleich sind 0.
Die Methode zum Vergleich zweier CMarketBookOrd-Objekte anhand aller Eigenschaften. Sie ermöglicht die Bestimmung der vollständigen Identität von zwei verglichenen Objekten:
//+------------------------------------------------------------------+ //| Compare CMarketBookOrd objects by all properties | //+------------------------------------------------------------------+ bool CMarketBookOrd::IsEqual(CMarketBookOrd *compared_obj) const { int beg=0, end=MBOOK_ORD_PROP_INTEGER_TOTAL; for(int i=beg; i<end; i++) { ENUM_MBOOK_ORD_PROP_INTEGER prop=(ENUM_MBOOK_ORD_PROP_INTEGER)i; if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; } beg=end; end+=MBOOK_ORD_PROP_DOUBLE_TOTAL; for(int i=beg; i<end; i++) { ENUM_MBOOK_ORD_PROP_DOUBLE prop=(ENUM_MBOOK_ORD_PROP_DOUBLE)i; if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; } beg=end; end+=MBOOK_ORD_PROP_STRING_TOTAL; for(int i=beg; i<end; i++) { ENUM_MBOOK_ORD_PROP_STRING prop=(ENUM_MBOOK_ORD_PROP_STRING)i; if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; } return true; } //+------------------------------------------------------------------+
Jede nachfolgende Eigenschaft von zwei Objekten wird hier einzeln verglichen. Wenn die Objekte nicht gleich sind, wird false zurückgegeben. Nachdem die Überprüfung der Gleichheit aller Eigenschaften zweier Objekte abgeschlossen ist und kein false erhalten wurde, wird true zurückgegeben — beide Objekte sind vollständig identisch.
Die Methode, die alle Objekteigenschaften ins Journal schreibt:
//+------------------------------------------------------------------+ //| Display object properties in the journal | //+------------------------------------------------------------------+ void CMarketBookOrd::Print(const bool full_prop=false) { ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") ============="); int beg=0, end=MBOOK_ORD_PROP_INTEGER_TOTAL; for(int i=beg; i<end; i++) { ENUM_MBOOK_ORD_PROP_INTEGER prop=(ENUM_MBOOK_ORD_PROP_INTEGER)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("------"); beg=end; end+=MBOOK_ORD_PROP_DOUBLE_TOTAL; for(int i=beg; i<end; i++) { ENUM_MBOOK_ORD_PROP_DOUBLE prop=(ENUM_MBOOK_ORD_PROP_DOUBLE)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("------"); beg=end; end+=MBOOK_ORD_PROP_STRING_TOTAL; for(int i=beg; i<end; i++) { ENUM_MBOOK_ORD_PROP_STRING prop=(ENUM_MBOOK_ORD_PROP_STRING)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," (",this.Header(),") =============\n"); } //+------------------------------------------------------------------+
Text-Beschreibungen jeder nachfolgenden Eigenschaft werden in drei Schleifen nach Integer-, Real- und String-Objekteigenschaften angezeigt.
Die Methoden geben die Beschreibungen der angegebenen Objekteigenschaften integer, real und string zurück:
//+------------------------------------------------------------------+ //| Return description of object's integer property | //+------------------------------------------------------------------+ string CMarketBookOrd::GetPropertyDescription(ENUM_MBOOK_ORD_PROP_INTEGER property) { return ( property==MBOOK_ORD_PROP_STATUS ? CMessage::Text(MSG_ORD_STATUS)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.StatusDescription() ) : property==MBOOK_ORD_PROP_TYPE ? CMessage::Text(MSG_ORD_TYPE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.TypeDescription() ) : property==MBOOK_ORD_PROP_VOLUME ? CMessage::Text(MSG_MBOOK_ORD_VOLUME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : "" ); } //+------------------------------------------------------------------+ //| Return description of object's real property | //+------------------------------------------------------------------+ string CMarketBookOrd::GetPropertyDescription(ENUM_MBOOK_ORD_PROP_DOUBLE property) { int dg=(this.m_digits>0 ? this.m_digits : 1); return ( property==MBOOK_ORD_PROP_PRICE ? CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==MBOOK_ORD_PROP_VOLUME_REAL ? CMessage::Text(MSG_MBOOK_ORD_VOLUME_REAL)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : "" ); } //+------------------------------------------------------------------+ //| Return description of object's string property | //+------------------------------------------------------------------+ string CMarketBookOrd::GetPropertyDescription(ENUM_MBOOK_ORD_PROP_STRING property) { return(property==MBOOK_ORD_PROP_SYMBOL ? CMessage::Text(MSG_LIB_PROP_SYMBOL)+": \""+this.GetProperty(property)+"\"" : ""); } //+------------------------------------------------------------------+
Jede der Methoden erhält die Eigenschaft, deren Beschreibung zurückgegeben werden soll. Abhängig von der an die Methode übergebenen Eigenschaft wird eine Zeichenkette erstellt, die schließlich von der Methode zurückgegeben wird.
Die Methode gibt einen kurzen Objektnamen zurück:
//+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookOrd::Header(void) { return this.TypeDescription()+" \""+this.Symbol()+"\""; } //+------------------------------------------------------------------+
Die Methode gibt die Zeichenkette zurück, die aus der Beschreibung eines Auftragstyps und seinem Symbol besteht.
Die Methode zeigt die kurze Objektbeschreibung im Journal an:
//+------------------------------------------------------------------+ //| Display a short description of the object in the journal | //+------------------------------------------------------------------+ void CMarketBookOrd::PrintShort(void) { ::Print(this.Header()); } //+------------------------------------------------------------------+
Die Methode zeigt einfach die von der vorherigen Methode erstellte Zeichenkette im Journal an.
Die Methode gibt die Beschreibung des Auftragsstatus im DOM zurück:
//+------------------------------------------------------------------+ //| Return the order status description in DOM | //+------------------------------------------------------------------+ string CMarketBookOrd::StatusDescription(void) const { return ( Status()==MBOOK_ORD_STATUS_SELL ? CMessage::Text(MSG_MBOOK_ORD_STATUS_SELL) : Status()==MBOOK_ORD_STATUS_BUY ? CMessage::Text(MSG_MBOOK_ORD_STATUS_BUY) : "" ); } //+------------------------------------------------------------------+
Abhängig vom Auftrag "Status" wird der Text mit der Statusbeschreibung zurückgegeben.
Dies ist die gesamte Klasse des Auftragsobjekts im DOM.
Nun müssen wir vier Klassen erstellen, die von diesem abstrakten Auftragsobjekt erben. Die Nachfolgeklassen werden verwendet, um neue Auftragsobjekte aus DOM zu erzeugen. Der Status des erzeugten Auftragsobjekts wird in der Initialisierungsliste des Konstruktors der Nachfolgeklasse abhängig vom Auftragstyp angegeben.
Abgeleitete Klassen der abstrakten Klasse des Auftragsobjekts
Wir erstellen in \MQL5\Include\DoEasy\Objects\Book\ die Datei MarketBookBuy.mqh für die Klasse CMarketBookBuy. Die neu erstellte abstrakte Auftragsklasse CMarketBookOrd soll eine übergeordnete Klasse sein:
//+------------------------------------------------------------------+ //| MarketBookBuy.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "MarketBookOrd.mqh" //+------------------------------------------------------------------+ //| Buy order in DOM | //+------------------------------------------------------------------+ class CMarketBookBuy : public CMarketBookOrd { private: public: //--- Constructor CMarketBookBuy(const string symbol,const MqlBookInfo &book_info) : CMarketBookOrd(MBOOK_ORD_STATUS_BUY,book_info,symbol) {} //--- Supported order properties (1) real, (2) integer virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property); //--- Return the object short name virtual string Header(void); //--- Return the description of order type (ENUM_BOOK_TYPE) virtual string TypeDescription(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CMarketBookBuy::SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property) { return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CMarketBookBuy::SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property) { return true; } //+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookBuy::Header(void) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY)+" \""+this.Symbol()+ "\": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]"; } //+------------------------------------------------------------------+ //| Return the description of order type | //+------------------------------------------------------------------+ string CMarketBookBuy::TypeDescription(void) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY); } //+------------------------------------------------------------------+
Wenn wir ein neues DOM-Auftragsobjekt erstellen, setzen wir die "Kaufseite" im Konstruktor der übergeordneten Klasse.
In den virtuellen Methoden Rückgabe des Flags der Unterstützung der Integer- und Real-Eigenschaften, Rückgabe true — jede Eigenschaft wird vom Objekt unterstützt.
In der virtuellen Methode wird der Kurznamen des DOM-Auftragsobjekts als Zeichenkette in folgendem Format zurückgegeben
Typ "Symbol": Preis [VolumeReal] Zum Beispiel:
"EURUSD" buy order: 1.20123 [10.00]
In der virtuellen Methode wird die Beschreibung des DOM-Auftragsobjekttyps die Zeichenkette "Buy order" (Kaufauftrag) zurückgegeben.
Die übrigen drei von der abstrakten DOM-Basisklasse für Aufträge abgeleiteten Klassen sind bis auf den Auftragsstatus identisch mit der betrachteten Klasse. Jeder Klassenkonstruktor verfügt über den Status, der dem beschriebenen Auftragsobjekt entspricht, und über virtuelle Methoden, die die Zeichenketten zurückgeben, die dem Typ des DOM-Auftrags entsprechen, der von jedem der Objekte beschrieben wird. Alle diese Klassen befinden sich in demselben Ordner wie die oben beschriebene Klasse. Ich zeige hier ihre Auflistungen, damit Sie ihre virtuellen Methoden analysieren und vergleichen können.
MarketBookBuyMarket.mqh:
//+------------------------------------------------------------------+ //| MarketBookBuyMarket.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "MarketBookOrd.mqh" //+------------------------------------------------------------------+ //| Buy order by Market in DOM | //+------------------------------------------------------------------+ class CMarketBookBuyMarket : public CMarketBookOrd { private: public: //--- Constructor CMarketBookBuyMarket(const string symbol,const MqlBookInfo &book_info) : CMarketBookOrd(MBOOK_ORD_STATUS_BUY,book_info,symbol) {} //--- Supported order properties (1) real, (2) integer virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property); //--- Return the object short name virtual string Header(void); //--- Return the description of order type (ENUM_BOOK_TYPE) virtual string TypeDescription(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CMarketBookBuyMarket::SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property) { return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CMarketBookBuyMarket::SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property) { return true; } //+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookBuyMarket::Header(void) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY_MARKET)+" \""+this.Symbol()+ "\": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]"; } //+------------------------------------------------------------------+ //| Return the description of order type | //+------------------------------------------------------------------+ string CMarketBookBuyMarket::TypeDescription(void) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY_MARKET); } //+------------------------------------------------------------------+
MarketBookSell.mqh:
//+------------------------------------------------------------------+ //| MarketBookSell.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "MarketBookOrd.mqh" //+------------------------------------------------------------------+ //| Sell order in DOM | //+------------------------------------------------------------------+ class CMarketBookSell : public CMarketBookOrd { private: public: //--- Constructor CMarketBookSell(const string symbol,const MqlBookInfo &book_info) : CMarketBookOrd(MBOOK_ORD_STATUS_SELL,book_info,symbol) {} //--- Supported order properties (1) real, (2) integer virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property); //--- Return the object short name virtual string Header(void); //--- Return the description of order type (ENUM_BOOK_TYPE) virtual string TypeDescription(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CMarketBookSell::SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property) { return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CMarketBookSell::SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property) { return true; } //+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookSell::Header(void) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL)+" \""+this.Symbol()+ "\": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]"; } //+------------------------------------------------------------------+ //| Return the description of order type | //+------------------------------------------------------------------+ string CMarketBookSell::TypeDescription(void) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL); } //+------------------------------------------------------------------+
MarketBookSellMarket.mqh:
//+------------------------------------------------------------------+ //| MarketBookSellMarket.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "MarketBookOrd.mqh" //+------------------------------------------------------------------+ //| Sell order by Market in DOM | //+------------------------------------------------------------------+ class CMarketBookSellMarket : public CMarketBookOrd { private: public: //--- Constructor CMarketBookSellMarket(const string symbol,const MqlBookInfo &book_info) : CMarketBookOrd(MBOOK_ORD_STATUS_SELL,book_info,symbol) {} //--- Supported order properties (1) real, (2) integer virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property); virtual bool SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property); //--- Return the object short name virtual string Header(void); //--- Return the description of order type (ENUM_BOOK_TYPE) virtual string TypeDescription(void); }; //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| integer property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CMarketBookSellMarket::SupportProperty(ENUM_MBOOK_ORD_PROP_INTEGER property) { return true; } //+------------------------------------------------------------------+ //| Return 'true' if an order supports a passed | //| real property, otherwise return 'false' | //+------------------------------------------------------------------+ bool CMarketBookSellMarket::SupportProperty(ENUM_MBOOK_ORD_PROP_DOUBLE property) { return true; } //+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookSellMarket::Header(void) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL_MARKET)+" \""+this.Symbol()+ "\": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]"; } //+------------------------------------------------------------------+ //| Return the description of order type | //+------------------------------------------------------------------+ string CMarketBookSellMarket::TypeDescription(void) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL_MARKET); } //+------------------------------------------------------------------+
Das ist alles, was ich im aktuellen Artikel tun wollte.
Test
Um den Test durchzuführen, verwende ich den EA aus dem vorherigen Artikel und speichere sie in \MQL5\Experts\TestDoEasy\Part63\ als TestDoEasyPart63.mq5.
Nach dem Start des EA abonnieren wir DOMs von Symbolen, die in den Einstellungen für die Arbeit angegeben sind. Alle Ereignisse mit DOMs werden im OnBookEvent() registriert. Entsprechend stellen wir in dieser Funktion sicher, dass das Ereignis auf dem aktuellen Symbol aufgetreten ist. Außerdem holen wir uns den DOM-Snapshot und speichern alle vorhandenen Aufträge nach Preiswerten sortiert in der Liste ab. Als Nächstes zeigen wir den allerersten und den allerletzten Auftrag aus der Liste in den Chart-Kommentaren an. Wir werden also zwei extreme DOM-Aufträge anzeigen — einen Verkaufs- und einen Kaufauftrag. Im Journal zeigen wir die Liste aller erhaltenen DOM-Aufträge bei der allerersten OnBookEvent()-Aktivierung an.
Damit der EA die neu erstellten Klassen sehen kann, binden wir sie in die EA-Datei ein (derzeit kann nicht auf sie vom Hauptobjekt der CEngine-Bibliothek zugegriffen werden):
//+------------------------------------------------------------------+ //| TestDoEasyPart63.mq5 | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //--- includes #include <DoEasy\Engine.mqh> #include <DoEasy\Objects\Book\MarketBookBuy.mqh> #include <DoEasy\Objects\Book\MarketBookSell.mqh> #include <DoEasy\Objects\Book\MarketBookBuyMarket.mqh> #include <DoEasy\Objects\Book\MarketBookSellMarket.mqh> //--- enums
Nun müssen wir die Funktion OnBookEvent() im EA erstellen und die Behandlung eines DOM-Ereignisses darin implementieren:
//+------------------------------------------------------------------+ //| OnBookEvent function | //+------------------------------------------------------------------+ void OnBookEvent(const string& symbol) { static bool first=true; //--- Get a symbol object CSymbol *sym=engine.GetSymbolCurrent(); //--- If failed to get a symbol object or it is not subscribed to DOM, exit if(sym==NULL || !sym.BookdepthSubscription()) return; //--- create the list for storing DOM order objects CArrayObj *list=new CArrayObj(); if(list==NULL) return; //--- Work by the current symbol if(symbol==sym.Name()) { //--- Declare the DOM structure array MqlBookInfo book_array[]; //--- Get DOM entries to the structure array if(!MarketBookGet(sym.Name(),book_array)) return; //--- clear the list list.Clear(); //--- In the loop by the structure array int total=ArraySize(book_array); for(int i=0;i<total;i++) { //--- Create order objects of the current DOM snapshot depending on the order type CMarketBookOrd *mbook_ord=NULL; switch(book_array[i].type) { case BOOK_TYPE_BUY : mbook_ord=new CMarketBookBuy(sym.Name(),book_array[i]); break; case BOOK_TYPE_SELL : mbook_ord=new CMarketBookSell(sym.Name(),book_array[i]); break; case BOOK_TYPE_BUY_MARKET : mbook_ord=new CMarketBookBuyMarket(sym.Name(),book_array[i]); break; case BOOK_TYPE_SELL_MARKET : mbook_ord=new CMarketBookSellMarket(sym.Name(),book_array[i]); break; default: break; } if(mbook_ord==NULL) continue; //--- Set the sorted list flag for the list (by the price value) and add the current order object to it list.Sort(SORT_BY_MBOOK_ORD_PRICE); if(!list.InsertSort(mbook_ord)) delete mbook_ord; } //--- Get the very first and last DOM order objects from the list CMarketBookOrd *ord_0=list.At(0); CMarketBookOrd *ord_N=list.At(list.Total()-1); if(ord_0==NULL || ord_N==NULL) return; //--- Display the size of the current DOM snapshot in the chart comment, //--- the maximum number of displayed orders in DOM for a symbol and //--- the highest and lowest orders of the current DOM snapshot Comment ( DFUN,sym.Name(),": ",TimeMSCtoString(sym.Time()),", array total=",total,", book size=",sym.TicksBookdepth(),", list.Total: ",list.Total(),"\n", "Max: ",ord_N.Header(),"\nMin: ",ord_0.Header() ); //--- Display the first DOM snapshot in the journal if(first) { for(int i=list.Total()-1;i>WRONG_VALUE;i--) { CMarketBookOrd *ord=list.At(i); ord.PrintShort(); } first=false; } } //--- Delete the created list delete list; } //+------------------------------------------------------------------+
Die Code-Kommentare enthalten alle Details. Wenn Sie Fragen haben, können Sie diese gerne in den Kommentaren stellen.
Kompilieren Sie den EA und starten Sie ihn auf einem Symbolchart, nachdem Sie in den Einstellungen festgelegt haben, dass die beiden angegebenen Symbole und der aktuelle Zeitrahmen verwendet werden sollen.

Nachdem der EA gestartet wurde und das erste DOM-Änderungsereignis eingetroffen ist, werden die Parameter der aktuellen DOM-Snapshot-Liste in den Chart-Kommentaren zusammen mit zwei Aufträgen angezeigt - dem höchsten Kauf- und dem niedrigsten Verkaufsauftrag:

Das Journal zeigt die Liste aller Aufträge des aktuellen DOM-Snapshots an:
Subscribed to Depth of Market AUDUSD Subscribed to Depth of Market EURUSD Library initialization time: 00:00:11.391 "EURUSD" sell order: 1.20250 [250.00] "EURUSD" sell order: 1.20245 [100.00] "EURUSD" sell order: 1.20244 [50.00] "EURUSD" sell order: 1.20242 [36.00] "EURUSD" buy order: 1.20240 [16.00] "EURUSD" buy order: 1.20239 [20.00] "EURUSD" buy order: 1.20238 [50.00] "EURUSD" buy order: 1.20236 [100.00] "EURUSD" buy order: 1.20232 [250.00]
Was kommt als Nächstes?
Im nächsten Artikel werden wir damit fortfahren, die Funktionen für die Arbeit mit dem DOM zu erstellen.
Alle Dateien der aktuellen Version der Bibliothek sind unten zusammen mit der Test-EA-Datei für MQL5 zum Testen und Herunterladen angehängt.
Die Klassen für die Arbeit mit dem DOM befinden sich in der Entwicklung, daher wird ihre Verwendung in benutzerdefinierten Programmen in diesem Stadium nicht empfohlen.
Schreiben Sie Ihre Fragen und Vorschläge in den Kommentaren.
*Frühere Artikel dieser Serie:
Zeitreihen in der Bibliothek DoEasy (Teil 59): Objekt zum Speichern der Daten eines Ticks
Preise in der DoEasy-Bibliothek (Teil 60): Listen von Serien mit Symbol-Tickdaten
Preise in der DoEasy-Bibliothek (Teil 61): Kollektion der Tickserien eines Symbols
Preise in der DoEasy-Bibliothek (Teil 62): Aktualisieren der Tick-Serien in Echtzeit, Vorbereitung für die Arbeit mit Markttiefe
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/9010
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Neuronale Netze leicht gemacht (Teil 11): Ein Blick auf GPT
Nützliche und exotische Techniken für den automatisierten Handel
- 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.
Hallo Artyom,
Zunächst einmal herzlichen Glückwunsch zu dem Artikel, einfach fantastisch!!! Eine Frage, von dem, was ich sehen konnte, Sie nicht auf die Position eines bestimmten Auftrags (Limit-Order) auf einem bestimmten Preisniveau berühren... Zum Beispiel, wenn meine Bestellung ist vor der Warteschlange (erste) auf diesem Niveau, die Hälfte des Weges oder wirklich hinter allen Bestellungen.... Ich versuche, eine Strategie für ein sehr liquides Instrument und sehr niedrige Handelskosten zu automatisieren, bei der ich eine Position einnehmen und möglicherweise zum selben Preis wieder aussteigen könnte, wofür ich Zugriff auf die Position oder meinen Auftrag in der Warteschlange eines bestimmten Kursniveaus haben müsste... Ich scheine dies nirgendwo diskutiert zu finden.
Wissen Sie, wie ich diese Informationen abrufen könnte, sofern die Börse diese Informationen unterstützt?
Mit freundlichen Grüßen
André Oliveira
Ich danke Ihnen.
Ich habe die Frage ein wenig nicht verstanden - wahrscheinlich die Sprachbarriere ...
Hier liest die Bibliothek alle verfügbaren Daten, die sie aus dem Depth of Market lesen kann, indem sie die von MQL bereitgestellten Möglichkeiten nutzt.
Versuchen Sie bitte, Ihre Frage mit Beispielen zu erklären.
Ich danke Ihnen.
Ich habe die Frage ein wenig nicht verstanden - wahrscheinlich die Sprachbarriere ...
Hier liest die Bibliothek alle verfügbaren Daten, die sie aus dem Depth of Market lesen kann, indem sie die von MQL bereitgestellten Möglichkeiten nutzt.
Versuchen Sie bitte, Ihre Frage mit Beispielen zu erklären.
Vielen Dank für die Antwort Artyom, sicher, lassen Sie mich versuchen, besser zu erklären.... Zur Vereinfachung und zum besseren Verständnis stellen wir uns ein hypothetisches und sehr einfaches "Orderbuch" mit nur einer Preistiefe vor, d.h. Limit-Orders auf der Geldseite und Limit-Orders auf der Briefseite ... Für das Beispiel stellen wir uns ein hohes Volumen an Aufträgen auf beiden Seiten vor (sagen wir mal Geldkurs 1,34 und Briefkurs 1,35). Für dieses Beispiel stellen wir uns vor, dass dieses "Orderbuch" nur Aufträge zu diesen beiden Preisen hat... Nichts anderes.
Ich gebe dann eine einzige Order auf beiden Seiten ein (Geld- und Briefkurs), und meine Order wird auf jeder Seite ganz am Ende der Warteschlange platziert (letzte Kauforder auf der Seite 1,34 und letzte Verkaufsorder auf der Seite 1,35).
Da die Aufträge vor meinen Aufträgen verbraucht oder storniert werden, rücken meine Aufträge in der Warteschlange vor, und zusätzliche Limit-Aufträge können hinter meinen Aufträgen auf demselben Preisniveau platziert werden .... Ich wollte wissen, ob es eine Möglichkeit gibt, die Position meiner Aufträge in der Warteschlange zu einem bestimmten Zeitpunkt abzurufen. Siehe Bild im Anhang.
Ich danke Ihnen für Ihre Aufmerksamkeit und Ihr Bemühen, meine Frage zu verstehen, Artyom. Lassen Sie mich wissen, ob dies klar ist, ich kann versuchen, an weitere Beispiele zu denken, wenn dies nicht ein gutes ist.
Mit freundlichen Grüßen und nochmals vielen Dank für Ihre Kommentare zu diesem Thema.
André Oliveira
André Oliveira
Danke für die Antwort Artyom, sicher, lassen Sie mich versuchen, besser zu erklären.... Zur Vereinfachung und zum besseren Verständnis stellen wir uns ein hypothetisches und sehr einfaches "Orderbuch" mit nur einer Tiefe des Preisniveaus vor, d.h. Limit-Orders auf der Geldseite und Limit-Orders auf der Briefseite ... Für das Beispiel stellen wir uns ein hohes Volumen an Aufträgen auf beiden Seiten vor (sagen wir mal Geldkurs 1,34 und Briefkurs 1,35). Für dieses Beispiel stellen wir uns vor, dass dieses "Orderbuch" nur Aufträge zu diesen beiden Preisen enthält... Nichts anderes.
Ich gebe dann einen einzigen Auftrag auf beiden Seiten ein (Geld- und Briefkurs) und meine Aufträge werden auf beiden Seiten ganz am Ende der Warteschlange platziert (letzter Kaufauftrag bei 1,34 und letzter Verkaufsauftrag bei 1,35).
Da die Aufträge vor meinen Aufträgen verbraucht oder storniert werden, rücken meine Aufträge in der Warteschlange vor, und zusätzliche Limit-Aufträge können hinter meinen Aufträgen auf demselben Preisniveau platziert werden .... Ich wollte wissen, ob es eine Möglichkeit gibt, die Position meiner Aufträge in der Warteschlange zu einem bestimmten Zeitpunkt abzurufen. Siehe Bild im Anhang.
Ich danke Ihnen für Ihre Aufmerksamkeit und Ihr Bemühen, meine Frage zu verstehen, Artyom. Lassen Sie es mich wissen, wenn es klar ist, ich kann versuchen, an weitere Beispiele zu denken, wenn dies nicht gut ist.
Mit freundlichen Grüßen und nochmals vielen Dank für Ihre Kommentare zu diesem Thema.
André Oliveira
André Oliveira
Ich fürchte, dass wir die Warteschlange für Aufträge in der Markttiefe nicht sehen können. Korrigieren Sie mich, wenn ich falsch liege.
Ich fürchte, dass wir die Auftragswarteschlange in der Tiefe des Marktes nicht sehen können. Korrigieren Sie mich, wenn ich falsch liege.
Nochmals vielen Dank, dass Sie sich die Frage angesehen haben Artyom.... Sehen Sie, ich bin sehr neu in der mql5-Programmierung, aber zumindest in unserer brasilianischen Börse ist dies offenbar möglich, da dies im "Orderbuch" und in der "Liste der Orders" einer Handelsplattform namens Profit und einer anderen namens Tryd. implementiert wurde. Diese beiden Handelsplattformen sind auf manuelle Händler ausgerichtet und legen keinen Wert auf automatisierten Handel.
Auf dem beigefügten Screenshot wird "meine Order" in Gelb angezeigt und alle anderen Orders davor und dahinter... Tatsächlich werden alle Broker und Ordergrößen angezeigt... es ist ein sehr transparenter Prozess.
Bei anderen Börsen ist dies wahrscheinlich nicht üblich (ich vermute, da ich nicht viel Erfahrung mit anderen Börsen habe), und aus diesem Grund wird dies vielleicht nicht in der mql5-Sprache erforscht... Ich werde versuchen, herauszufinden, wie dies zu diesen Handelsplattformen exportiert wird (es muss eine Art API geben), ich dachte nur, dass dies vielleicht auch schon in mql5 erforscht wurde.
Artyom, vielen Dank für Ihre Anmerkungen, die ich sehr zu schätzen weiß. Ich gratuliere Ihnen zu Ihren Artikeln, sie haben eine sehr hohe Qualität des Inhalts und der Informationen.
Mit freundlichen Grüßen
André Oliveira
Nochmals vielen Dank, dass Sie sich die Frage angesehen haben Artyom.... Sehen Sie, ich bin sehr neu in der mql5-Programmierung, aber zumindest in unserer brasilianischen Börse ist dies offenbar möglich, da dies im "Orderbuch" und in der "Liste der Orders" einer Handelsplattform namens Profit und einer anderen namens Tryd. implementiert wurde. Diese beiden Handelsplattformen sind auf manuelle Händler ausgerichtet und legen keinen Wert auf automatisierten Handel.
Auf dem beigefügten Screenshot wird "meine Order" in Gelb angezeigt und alle anderen Orders davor und dahinter... tatsächlich werden alle Broker und Ordergrößen angezeigt... es ist ein sehr transparenter Prozess.
Bei anderen Börsen ist dies wahrscheinlich nicht üblich (ich vermute, da ich nicht viel Erfahrung mit anderen Börsen habe), und aus diesem Grund wird dies vielleicht nicht in der mql5-Sprache erforscht... Ich werde versuchen, herauszufinden, wie dies zu diesen Handelsplattformen exportiert wird (es muss eine Art API geben), ich dachte nur, dass dies vielleicht auch schon in mql5 erforscht wurde.
Artyom, vielen Dank für Ihre Anmerkungen, die ich sehr zu schätzen weiß. Ich gratuliere Ihnen zu Ihren Artikeln, sie haben einen sehr hochwertigen Inhalt und Informationen.
Mit besten Grüßen
André Oliveira
Ich werde versuchen, dieses Thema genauer zu betrachten. Aber erst, wenn ich Zeit habe. Leider habe ich nicht viel Zeit.