
Trabajando con los precios en la biblioteca DoEasy (Parte 64): Profundidad del mercado, clases del objeto de instantánea y del objeto de serie de instantáneas del DOM
Contenido
- Concepto
- Mejorando las clases de la biblioteca
- Clase del objeto de instantánea del DOM
- Clase del objeto de serie de instantáneas del DOM
- Prueba
- ¿Qué es lo próximo?
Concepto
En el artículo anterior, creamos la clase del objeto de una orden abstracta del DOM y las clases herederas de este objeto. El conjunto de estos objetos constituye una instantánea (snapshot en inglés) del DOM que se obtiene al invocar una vez la función MarketBookGet(), en el momento de la activación del manejador OnBookEvent(). Los datos obtenidos por la función MarketBookGet() se registran en la matriz de estructuras MqlBookInfo. A base de estos datos obtenidos, podemos crear un objeto de instantánea del DOM que va a almacenar todas las órdenes del DOM obtenidas en la matriz de estructuras MqlBookInfo. En otras palabras, los datos en esta matriz de estructuras van a constituir una instantánea del DOM, donde cada miembro de la estructura será representado por un objeto de orden del DOM. Cada activación ordinaria del manejador OnBookEvent() va a provocar la creación de una instantánea ordinaria del DOM. A su vez, estas instantáneas van a introducirse en el objeto de la clase de la serie de instantáneas del DOM.
La clase de la matriz dinámica de punteros a las instancias de la clase CObject y sus herederos de la Biblioteca estándar nos va a servir de una lista para almacenar los objetos de instantánea del DOM. El tamaño de esta lista será limitada por un número establecido de objetos. Por defecto, el tamaño de esta lista no superará 200 000 objetos de instantánea del DOM, lo cual debe cubrir una o dos sesiones comerciales. Estas listas de serie de instantáneas del DOM serán creadas para cada símbolo usado en el programa. Al final, cada una de estas listas va a almacenarse en una colección de datos del DOM.
En este artículo, vamos a crear dos clases: la clase del objeto de instantánea del DOM de un símbolo y la clase de serie de instantáneas del DOM de un símbolo. En el siguiente artículo, crearemos y probaremos la clase de colección de estas series de instantánea del DOM.
Mejorando las clases de la biblioteca
Añadimos los índices de nuevos mensajes de la biblioteca al archivo \MQL5\Include\DoEasy\Data.mqh:
//--- 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 //--- CMarketBookSnapshot MSG_MBOOK_SNAP_TEXT_SNAPSHOT, // DOM snapshot //--- CMBookSeries MSG_MBOOK_SERIES_TEXT_MBOOKSERIES, // DOM snapshot series }; //+------------------------------------------------------------------+
y añadimos los mensajes de texto correspondientes a los índices nuevamente añadidos:
//--- 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"}, //--- CMarketBookSnapshot {"Снимок стакана цен","Depth of Market Snapshot"}, //--- CMBookSeries {"Серия снимков стакана цен","Series of shots of the Depth of Market"}, }; //+---------------------------------------------------------------------+
Para poder especificar los criterios de ordenación por hora durante la búsqueda de objetos de instantánea necesarios del DOM en la lista de serie, tenemos que añadir una propiedad nueva para el objeto de orden del DOM, a saber, la hora de obtención de la instantánea en milisegundos. La orden no tiene esta propiedad, pero podemos monitorear la obtención de la instantánea del DOM. Además, para no introducir nuevas enumeraciones para la lista de serie de las instantáneas del DOM, donde habrá sólo una propiedad entera —la hora de obtención de la instantánea en milisegundos— añadiremos esta propiedad a las propiedades del objeto de orden del DOM. A cada orden en un objeto de instantánea se le asignará la hora de obtención de esta instantánea. Y para la búsqueda y ordenación en la lista de serie vamos a usar esta constante nuevamente añadida.
En el archivo \MQL5\Include\DoEasy\Defines.mqh escribiremos los parámetros de las series de las instantáneas del DOM que son necesarios para especificar el número de días de datos y el número máximo posible de las instantáneas en la lista:
//--- Tick series parameters #define TICKSERIES_DEFAULT_DAYS_COUNT (1) // Required number of days for tick data in default series #define TICKSERIES_MAX_DATA_TOTAL (200000) // Maximum number of stored tick data of a single symbol //--- Parameters of the DOM snapshot series #define MBOOKSERIES_DEFAULT_DAYS_COUNT (1) // The default required number of days for DOM snapshots in the series #define MBOOKSERIES_MAX_DATA_TOTAL (200000) // Maximum number of stored DOM snapshots of a single symbol //+------------------------------------------------------------------+
El primer parámetro (número de días) no vamos a usar de momento. En el futuro, intentaremos vincular estos datos con el número de días de datos de tick, mientras tanto vamos a usar sólo el segundo parámetro —el número máximo posible de los datos de las instantáneas del DOM.
En el mimo archivo, vamos a añadir una nueva propiedad entera del objeto de orden del DOM (en milisegundos),
y aumentaremos la cantidad de las propiedades enteras del objeto a 4:
//+------------------------------------------------------------------+ //| 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 MBOOK_ORD_PROP_TIME_MSC, // Time of making a DOM snapshot in milliseconds }; #define MBOOK_ORD_PROP_INTEGER_TOTAL (4) // Total number of integer properties #define MBOOK_ORD_PROP_INTEGER_SKIP (0) // Number of integer DOM properties not used in sorting //+------------------------------------------------------------------+
Como hemos añadido una nueva propiedad entera, tenemos que añadir un nuevo criterio de ordenación según las propiedades enteras:
//+------------------------------------------------------------------+ //| 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_MBOOK_ORD_TIME_MSC, // Sort by time of making a DOM snapshot in milliseconds //--- 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 }; //+------------------------------------------------------------------+
Precisamente esta constante será especificada como parámetro según el cual habrá que ordenar los objetos de instantánea del DOM en la clase nueva creada del objeto de serie de instantáneas del DOM.
Pues bien, aquí llegamos a la necesidad de crear los métodos para buscar y ordenar los objetos de orden del DOM en el archivo de la clase CSelect, que se almacena en \MQL5\Include\DoEasy\Services\Select.mqh. Pueden encontrar su descripción detallada en el tercer artículo. Ahora, simplemente describiremos todas las mejoras necesarias de esta clase con el fin de organizar la búsqueda y ordenación según los objetos de orden del DOM.
Vamos a incluir la clase del objeto de orden abstracta del DOM en el archivo:
//+------------------------------------------------------------------+ //| Select.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/es/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/es/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> #include "..\Objects\Orders\Order.mqh" #include "..\Objects\Events\Event.mqh" #include "..\Objects\Accounts\Account.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\PendRequest\PendRequest.mqh" #include "..\Objects\Series\SeriesDE.mqh" #include "..\Objects\Indicators\Buffer.mqh" #include "..\Objects\Indicators\IndicatorDE.mqh" #include "..\Objects\Indicators\DataInd.mqh" #include "..\Objects\Ticks\DataTick.mqh" #include "..\Objects\Book\MarketBookOrd.mqh" //+------------------------------------------------------------------+
Declaramos todos los métodos necesarios al final del cuerpo de la clase:
//+------------------------------------------------------------------+ //| Methods of working with DOM data | //+------------------------------------------------------------------+ //--- Return the list of DOM data with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the DOM data index in the list with the maximum value of (1) integer, (2) real and (3) string property of data static int FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property); static int FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property); static int FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property); //--- Return the DOM data index in the list with the minimum value of (1) integer, (2) real and (3) string property of data static int FindMBookMin(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property); static int FindMBookMin(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property); static int FindMBookMin(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property); //--- }; //+------------------------------------------------------------------+
Escribiremos su implementación fuera del cuerpo de la clase:
//+------------------------------------------------------------------+ //| Methods of working with DOM data | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Return the list of DOM data with one of integer | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); int total=list_source.Total(); for(int i=0; i<total; i++) { CMarketBookOrd *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; long obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Return the list of DOM data with one of real | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CMarketBookOrd *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; double obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Return the list of DOM data with one of string | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::ByMBookProperty(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CMarketBookOrd *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; string obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Return the DOM data index in the list | //| with the maximum integer property value | //+------------------------------------------------------------------+ int CSelect::FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_INTEGER property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CMarketBookOrd *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMarketBookOrd *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); long obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the DOM data index in the list | //| with the maximum real property value | //+------------------------------------------------------------------+ int CSelect::FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CMarketBookOrd *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMarketBookOrd *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); double obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the DOM data index in the list | //| with the maximum string property value | //+------------------------------------------------------------------+ int CSelect::FindMBookMax(CArrayObj *list_source,ENUM_MBOOK_ORD_PROP_STRING property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CMarketBookOrd *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMarketBookOrd *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); string obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the DOM data index in the list | //| with the minimum integer property value | //+------------------------------------------------------------------+ int CSelect::FindMBookMin(CArrayObj* list_source,ENUM_MBOOK_ORD_PROP_INTEGER property) { int index=0; CMarketBookOrd *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMarketBookOrd *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); long obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the DOM data index in the list | //| with the minimum real property value | //+------------------------------------------------------------------+ int CSelect::FindMBookMin(CArrayObj* list_source,ENUM_MBOOK_ORD_PROP_DOUBLE property) { int index=0; CMarketBookOrd *min_obj=NULL; int total=list_source.Total(); if(total== 0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMarketBookOrd *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); double obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the DOM data index in the list | //| with the minimum string property value | //+------------------------------------------------------------------+ int CSelect::FindMBookMin(CArrayObj* list_source,ENUM_MBOOK_ORD_PROP_STRING property) { int index=0; CMarketBookOrd *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMarketBookOrd *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); string obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+
La lógica del funcionamiento de los métodos es idéntica a la lógica del funcionamiento de otros métodos parecidos de esta clase que han sido creados antes para otros objetos de la biblioteca. Por eso, no vamos a perder tiempo en describir el funcionamiento de los métodos. Lo único es que siempre pueden repasar los temas estudiados más de una vez si vuelven a consultar la descripción del funcionamiento de estos métodos.
Como hemos introducido un parámetro nuevo —la hora de obtención de la instantánea del DOM— vamos a escribir esta hora en el objeto de la orden abstracta del DOM. En la estructura MqlBookInfo, que describe una orden del DOM no hay parámetro de la hora. Por eso, nosotros tendremos que añadir la hora de obtención de la instantánea a cada objeto de orden del DOM.
Para eso, añadimos un método público nuevo al archivo de la clase de la orden abstracta del DOM \MQL5\Include\DoEasy\Objects\Book\MarketBookOrd.mqh:
public: //+-------------------------------------------------------------------+ //|Methods of a simplified access to the DOM request object properties| //+-------------------------------------------------------------------+ //--- Set a snapshot time - all orders of a single DOM snapshot have the same name void SetTime(const long time_msc) { this.SetProperty(MBOOK_ORD_PROP_TIME_MSC,time_msc); } //--- Return order (1) status, (2) type and (3) order volume
El método simplemente establece el valor transmitido de la hora en milisegundos en la propiedad nueva del objeto.
En el constructor paramétrico de la clase de la orden abstracta del DOM, inicializamos la hora de la obtención de la instantánea usando cero:
//+------------------------------------------------------------------+ //| 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)); //--- Order time is not present in the parameters and is considered in the DOM snapshot class. Reset the time this.SetProperty(MBOOK_ORD_PROP_TIME_MSC,0); } //+------------------------------------------------------------------+
La hora para cada una de las órdenes que figura en una instantánea del DOM se establecerá en el momento de la obtención de la instantánea del DOM.
Además, en el archivo de la clase de la orden abstracta del DOM MarketBookOrd.mqh y en los archivos de las clases de sus herederos MarketBookBuy.mqh, MarketBookBuyMarket.mqh, MarketBookSell.mqh y MarketBookSellMarket.mqh, han sido introducidos pequeñas modificaciones en los métodos virtuales de la descripción de los objetos:
//--- Display a short description of the object in the journal virtual void PrintShort(const bool symbol=false); //--- Return the object short name virtual string Header(const bool symbol=false);
A cada uno de los métodos se le han sido añadidas las banderas que indican en la necesidad de visualizar el nombre del símbolo en la descripción del objeto. Por defecto, el símbolo no se visualiza en la descripción del objeto de orden. Eso se debe a que el objeto de orden no actúa como un objeto independiente, sino forma parte de la instantánea del DOM cuya clase vamos a hacer en este artículo. Entonces, al mostrar la descripción del objeto de instantánea del DOM, donde aparte de la descripción del objeto se muestra la descripción de todas las órdenes que forman su parte, la visualización del símbolo para cada orden parece algo excesivo, ya que el símbolo ya se visualiza en el encabezado del objeto de instantánea del DOM.
La mejora de estos métodos es igual para todas las clases arriba mencionadas.
Para la clase CMarketBookOrd:
//+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookOrd::Header(const bool symbol=false) { return this.TypeDescription()+(symbol ? " \""+this.Symbol()+"\"" : ""); } //+------------------------------------------------------------------+ //| Display a short description of the object in the journal | //+------------------------------------------------------------------+ void CMarketBookOrd::PrintShort(const bool symbol=false) { ::Print(this.Header(symbol)); } //+------------------------------------------------------------------+
Para la clase CMarketBookBuy, CMarketBookBuyMarket, CMarketBookSell y CMarketBookSellMarket:
//+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookBuy::Header(const bool symbol=false) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY)+(symbol ? " \""+this.Symbol() : "")+ ": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]"; } //+------------------------------------------------------------------+
Para la clase CMarketBookBuyMarket:
//+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookBuyMarket::Header(const bool symbol=false) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_BUY_MARKET)+(symbol ? " \""+this.Symbol() : "")+ ": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]"; } //+------------------------------------------------------------------+
Para la clase CMarketBookSell:
//+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookSell::Header(const bool symbol=false) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL)+(symbol ? " \""+this.Symbol() : "")+ ": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]"; } //+------------------------------------------------------------------+
Para la clase CMarketBookSellMarket:
//+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMarketBookSellMarket::Header(const bool symbol=false) { return CMessage::Text(MSG_MBOOK_ORD_TYPE_SELL_MARKET)+(symbol ? " \""+this.Symbol() : "")+ ": "+::DoubleToString(this.Price(),this.Digits())+" ["+::DoubleToString(this.VolumeReal(),2)+"]"; } //+------------------------------------------------------------------+
Por tanto, en la declaración de estos métodos, en todas las clases herederas, han sido añadidas las banderas:
//--- Return the object short name virtual string Header(const bool symbol=false);
Por defecto, el símbolo no va a visualizarse en la descripción del objeto
Clase del objeto de instantánea del DOM
Bien, ya está todo preparado para crear la clase del objeto de instantánea del DOM. En esencia, se trata de una lista de órdenes del DOM obtenida en la matriz de estructuras MqlBookInfo al ser activado el manejador OnBookEvent(). Lo único es que cada una de las órdenes ubicadas en la matriz será representada en esta clase por el objeto de la clase CMarketBookOrd —por sus herederos. Todos ellos van a colocarse en la lista CArrayObj, que constituye la clase de la matriz dinámica de punteros a las instancias de la clase CObject y sus herederos de la Biblioteca estándar. Aparte de la lista que almacenará los objetos de orden del DOM, la clase va a proporcionar las posibilidades estándar para todos los objetos de la biblioteca de trabajar con estos objetos y con sus listas (búsqueda y ordenación según diferentes propiedades), para una conveniente recopilación de datos estadísticos durante el trabajo con el DOM en nuestros programas.
En la carpeta de la biblioteca \MQL5\Include\DoEasy\Objects\Book\ creamos archivo nuevo MarketBookSnapshot.mqh de la clase CMBookSnapshot.
De clase base servirá la clase del objeto básico de todos los objetos de la biblioteca CBaseObj.
El archivo debe incluir los archivos de las clases de objetos herederos del objeto de la orden abstracta del DOM.
Vamos a echar un vistazo al listado de la clase y a la implementación de sus métodos:
//+------------------------------------------------------------------+ //| MarketBookSnapshot.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/es/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/es/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\..\Services\Select.mqh" #include "MarketBookBuy.mqh" #include "MarketBookSell.mqh" #include "MarketBookBuyMarket.mqh" #include "MarketBookSellMarket.mqh" //+------------------------------------------------------------------+ //| "DOM snapshot" class | //+------------------------------------------------------------------+ class CMBookSnapshot : public CBaseObj { private: string m_symbol; // Symbol long m_time; // Snapshot time int m_digits; // Symbol's Digits CArrayObj m_list; // List of DOM order objects public: //--- Return (1) itself and (2) the list of DOM order objects CMBookSnapshot *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &m_list; } //--- Return the list of DOM order objects by selected (1) double, (2) integer and (3) string property satisfying the compared condition CArrayObj *GetList(ENUM_MBOOK_ORD_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByMBookProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_MBOOK_ORD_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMBookProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_MBOOK_ORD_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByMBookProperty(this.GetList(),property,value,mode); } //--- (1) Return the DOM order object by index in the list and (2) the order list size CMarketBookOrd *GetMBookByListIndex(const uint index) { return this.m_list.At(index); } int DataTotal(void) const { return this.m_list.Total(); } //--- The comparison method for searching and sorting DOM snapshot objects by time virtual int Compare(const CObject *node,const int mode=0) const { const CMBookSnapshot *compared_obj=node; return(this.Time()<compared_obj.Time() ? -1 : this.Time()>compared_obj.Time() ? 1 : 0); } //--- Return the DOM snapshot change string Header(void); //--- Display (1) description and (2) short description of a DOM snapshot void Print(void); void PrintShort(void); //--- Constructors CMBookSnapshot(){;} CMBookSnapshot(const string symbol,const long time,MqlBookInfo &book_array[]); //+----------------------------------------------------------------------+ //|Methods of a simplified access to the DOM snapshot object properties | //+----------------------------------------------------------------------+ //--- Set (1) a symbol, (2) a DOM snapshot time and (3) the specified time for all DOM orders void SetSymbol(const string symbol) { this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); } void SetTime(const long time_msc) { this.m_time=time_msc; } void SetTimeToOrders(const long time_msc); //--- Return (1) a DOM symbol, (2) symbol's Digits and (3) a snapshot time string Symbol(void) const { return this.m_symbol; } int Digits(void) const { return this.m_digits; } long Time(void) const { return this.m_time; } }; //+------------------------------------------------------------------+
Aquí, podemos observar una organización común de la clase, como la de los demás objetos de la biblioteca. En la sección privada, tenemos declaradas las variables–miembros de la clase. En la sección pública, están declarados los métodos estándar para los objetos de la biblioteca para devolver las listas según las propiedades especificadas de los objetos de orden; el método para comparar dos objetos de instantánea del DOM para buscar y ordenar estos objetos en la lista en la que luego vamos a colocarlos (en la lista del objeto de serie de las instantáneas del DOM); los métodos para describir el objeto de instantánea del DOM; dos constructores —constructor predefinido y constructor paramétrico (el constructor paramétrico se usará al crear nuevos objetos de instantánea del DOM para los que se conocen todas sus propiedades; por defecto él va a servir para crear rápidamente un objeto nuevo y añadirle una propiedad necesaria con el fin de buscar los objetos en la lista con un valor especificado de esta propiedad). Los métodos del acceso simplificado a las propiedades del objeto sirven para establecer y devolver algunas propiedades del objeto que serán necesarias más tarde.
Vamos a analizar la implementación de los métodos de la clase.
En el constructor paramétrico, revisamos la matriz de estructuras transmitida MqlBookInfo, y de acuerdo con el tipo de las órdenes, creamos los tipos correspondientes de los objetos de orden del DOM y los añadimos a la lista.
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CMBookSnapshot::CMBookSnapshot(const string symbol,const long time,MqlBookInfo &book_array[]) : m_time(time) { //--- Set a symbol this.SetSymbol(symbol); //--- Clear the list this.m_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(this.m_symbol,book_array[i]); break; case BOOK_TYPE_SELL : mbook_ord=new CMarketBookSell(this.m_symbol,book_array[i]); break; case BOOK_TYPE_BUY_MARKET : mbook_ord=new CMarketBookBuyMarket(this.m_symbol,book_array[i]); break; case BOOK_TYPE_SELL_MARKET : mbook_ord=new CMarketBookSellMarket(this.m_symbol,book_array[i]); break; default: break; } if(mbook_ord==NULL) continue; //--- Set the DOM snapshot time for the order mbook_ord.SetTime(this.m_time); //--- Set the sorted list flag for the list (by the price value) and add the current order object to it this.m_list.Sort(SORT_BY_MBOOK_ORD_PRICE); if(!this.m_list.InsertSort(mbook_ord)) delete mbook_ord; } } //+------------------------------------------------------------------+
Método para devolver el nombre breve del objeto de instantánea del DOM:
//+------------------------------------------------------------------+ //| Return the object short name | //+------------------------------------------------------------------+ string CMBookSnapshot::Header(void) { return CMessage::Text(MSG_MBOOK_SNAP_TEXT_SNAPSHOT)+" \""+this.Symbol(); } //+------------------------------------------------------------------+
Aquí, simplemente se crea una cadena compuesta del mensaje de texto con la descripción del objeto y del símbolo, que tendrá aproximadamente el siguiente aspecto:
EURUSD DOM snapshot
Método que muestra en el diario la descripción breve del objeto de instantánea del DOM:
//+------------------------------------------------------------------+ //| Display a short description of the object in the journal | //+------------------------------------------------------------------+ void CMBookSnapshot::PrintShort(void) { ::Print(this.Header()," ("+TimeMSCtoString(this.m_time),")"); } //+------------------------------------------------------------------+
El método muestra en el diario una cadena compuesta del nombre del objeto y de la hora de la instantánea del DOM en milisegundos, por ejemplo:
"EURUSD" DOM snapshot (2021.02.09 22:16:24.557)
Método que muestra en el diario las propiedades del objeto de instantánea del DOM:
//+------------------------------------------------------------------+ //| Display object properties in the journal | //+------------------------------------------------------------------+ void CMBookSnapshot::Print(void) { ::Print(this.Header()," ("+TimeMSCtoString(this.m_time),"):"); this.m_list.Sort(SORT_BY_MBOOK_ORD_PRICE); for(int i=this.m_list.Total()-1;i>WRONG_VALUE;i--) { CMarketBookOrd *ord=this.m_list.At(i); if(ord==NULL) continue; ::Print(" - ",ord.Header()); } } //+------------------------------------------------------------------+
Primero, se muestra el encabezado con la descripción de la instantánea del DOM. Luego, en el ciclo por la lista de todos los objetos de orden del DOM, se muestran sus descripciones.
Ya que los objetos de orden que se encuentran en la lista del objeto de instantánea del DOM no tienen la posibilidad de obtener su hora, escribiremos en esta clase el método que establece para todos los objetos de orden en la lista la hora en milisegundos registrada en este objeto
//+------------------------------------------------------------------+ //| Set the specified time to all DOM orders | //+------------------------------------------------------------------+ void CMBookSnapshot::SetTimeToOrders(const long time_msc) { int total=this.m_list.Total(); for(int i=0;i<total;i++) { CMarketBookOrd *ord=this.m_list.At(i); if(ord==NULL) continue; ord.SetTime(time_msc); } } //+------------------------------------------------------------------+
En el ciclo por la lista de todos los objetos de orden del DOM, obtenemos el objeto de orden y le establecemos la hora registrada en las propiedades del objeto de instantánea del DOM. De esta manera, todos los objetos de orden ubicados en la lista de esta instantánea del DOM tienen la misma hora de su obtención, lo cual es lógico. Los obtenemos cuando se activa el manejador OnBookEvent(), y asignamos la hora de activación al objeto de instantánea del DOM y a todas sus órdenes.
El objeto de instantánea del DOM está preparado. Ahora tenemos que ubicar estos objetos en la lista, porque cuando se activa el manejador OnBookEvent(), vamos a obtener una nueva instantánea del DOM y crear el objeto correspondiente.
Vamos a almacenar todos estos objetos en la clase del objeto de serie de instantáneas del DOM.
Clase del objeto de serie de instantáneas del DOM
La clase de la serie de instantáneas del DOM, según su «ideología», parece a las clases de las series temporales de los símbolos o de datos de tick. A diferencia de estas clases, donde se puede obtener los datos desde el entorno, en la clase de lista de las instantáneas del DOM no podemos obtener datos históricos: tendremos que acumularlos en modo de tiempo real. Por eso, la clase no va a tener el método para crear la lista, sólo tendrá el método de su actualización.
En la carpeta de la biblioteca \MQL5\Include\DoEasy\Objects\Book\ creamos archivo nuevo MBookSeries.mqh de la clase CMBookSeries.
De clase base servirá la clase del objeto básico de todos los objetos de la biblioteca CBaseObj.
El archivo debe incluir el archivo de la clase del objeto de instantánea del DOM.
Vamos a examinar el listado de la clase, luego analizaremos sus métodos:
//+------------------------------------------------------------------+ //| MBookSeries.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/es/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/es/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "MarketBookSnapshot.mqh" //+------------------------------------------------------------------+ //| "DOM snapshot series" class | //+------------------------------------------------------------------+ class CMBookSeries : public CBaseObj { private: string m_symbol; // Symbol uint m_amount; // Number of used DOM snapshots in the series uint m_required; // Required number of days for DOM snapshot series CArrayObj m_list; // DOM snapshot series list MqlBookInfo m_book_info[]; // DOM structure array public: //--- Return (1) itself and (2) the series list CMBookSeries *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &m_list; } //--- Return the DOM snapshot list by selected (1) double, (2) integer and (3) string properties fitting the compared condition CArrayObj *GetList(ENUM_MBOOK_ORD_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByMBookProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_MBOOK_ORD_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMBookProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_MBOOK_ORD_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByMBookProperty(this.GetList(),property,value,mode); } //--- Return the DOM snapshot object by (1) index in the list, (2) time and (3) actual list size CMBookSnapshot *GetMBookByListIndex(const uint index) const { return this.m_list.At(index); } CMBookSnapshot *GetLastMBook(void) const { return this.m_list.At(this.DataTotal()-1); } CMBookSnapshot *GetMBook(const long time_msc); int DataTotal(void) const { return this.m_list.Total(); } //--- Set a (1) symbol, (2) a number of days for DOM snapshots void SetSymbol(const string symbol); void SetRequiredUsedDays(const uint required=0); //--- The comparison method for searching and sorting DOM snapshot series objects by symbol virtual int Compare(const CObject *node,const int mode=0) const { const CMBookSeries *compared_obj=node; return(this.Symbol()==compared_obj.Symbol() ? 0 : this.Symbol()>compared_obj.Symbol() ? 1 : -1); } //--- Return the name of the DOM snapshot series string Header(void); //--- Display (1) description and (2) short description of a DOM snapshot series void Print(void); void PrintShort(void); //--- Constructors CMBookSeries(){;} CMBookSeries(const string symbol,const uint required=0); //+------------------------------------------------------------------+ //| Methods of working with objects and accessing their properties | //+------------------------------------------------------------------+ //--- Return (1) a symbol, a number of (2) used and (3) requested DOM snapshots in the series and //--- (4) the time of a DOM snapshot specified by the index in milliseconds string Symbol(void) const { return this.m_symbol; } ulong AvailableUsedData(void) const { return this.m_amount; } ulong RequiredUsedDays(void) const { return this.m_required; } long MBookTime(const int index) const; //--- update the list of DOM snapshot series bool Refresh(const long time_msc); }; //+------------------------------------------------------------------+
Bien, ¿qué es lo que vemos aquí?
- métodos estándar para los objetos de la biblioteca para obtener las propiedades del objeto y de las listas de objetos según propiedades especificadas,
- métodos para establecer algunas propiedades,
- método de comparación de dos objetos de lista para ordenarlos sólo según el nombre del símbolo,
- métodos de devolución del nombre del objeto y constructores de la clase.
Vamos a analizar la implementación de los métodos de la clase.
En el constructor paramétrico (en su lista de inicialización), se establece el símbolo de la lista. Se limpia en el cuerpo del método, se le asigna la bandera de una lista ordenada según la hora en milisegundos y se establece la cantidad necesaria de días de los datos de las instantáneas del DOM.
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CMBookSeries::CMBookSeries(const string symbol,const uint required=0) : m_symbol(symbol) { this.m_list.Clear(); this.m_list.Sort(SORT_BY_MBOOK_ORD_TIME_MSC); this.SetRequiredUsedDays(required); } //+------------------------------------------------------------------+
Método para actualizar la lista de instantáneas del DOM
//+------------------------------------------------------------------+ //| Update the list of DOM snapshot series | //+------------------------------------------------------------------+ bool CMBookSeries::Refresh(const long time_msc) { //--- Get DOM entries to the structure array if(!::MarketBookGet(this.m_symbol,this.m_book_info)) return false; //--- Create a new DOM snapshot object CMBookSnapshot *book=new CMBookSnapshot(this.m_symbol,time_msc,this.m_book_info); if(book==NULL) return false; //--- Set the flag of a list sorted by time for the list and add the created DOM snapshot to it this.m_list.Sort(SORT_BY_MBOOK_ORD_TIME_MSC); if(!this.m_list.InsertSort(book)) { delete book; return false; } //--- Set time in milliseconds to all DOM snapshot order objects book.SetTimeToOrders(time_msc); //--- If the number of snapshots in the list exceeds the default maximum number, //--- remove the calculated number of snapshot objects from the end of the list if(this.DataTotal()>MBOOKSERIES_MAX_DATA_TOTAL) { int total_del=this.m_list.Total()-MBOOKSERIES_MAX_DATA_TOTAL; for(int i=0;i<total_del;i++) this.m_list.Delete(i); } return true; } //+------------------------------------------------------------------+
El método va a invocarse cuando se active el manejador OnBookEvent(). Por tanto, al método se le transmite la hora de la activación del manejador. Usando MarketBookGet() obtenemos la matriz de estructuras del DOM. A base de esta estructura, creamos un nuevo objeto de instantánea del DOM y lo añadimos a la lista de serie de instantáneas.
La lógica al completo se describe en los comentarios al código. Creo que la lógica está clara.
Método para establecer el nombre del símbolo para la lista de serie de instantáneas:
//+------------------------------------------------------------------+ //| Set a symbol | //+------------------------------------------------------------------+ void CMBookSeries::SetSymbol(const string symbol) { if(this.m_symbol==symbol) return; this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); } //+------------------------------------------------------------------+
Aquí, todo es transparente: si ha sido transmitido NULL o una cadena vacía, se establece el símbolo actual; de lo contrario, el que ha sido transmitido al método.
Método para establecer el número de días para la serie la serie de instantáneas del DOM:
//+------------------------------------------------------------------+ //| Set the number of days for DOM snapshots in the series | //+------------------------------------------------------------------+ void CMBookSeries::SetRequiredUsedDays(const uint required=0) { this.m_required=(required<1 ? MBOOKSERIES_DEFAULT_DAYS_COUNT : required); } //+------------------------------------------------------------------+
Si ha sido transmitido el valor cero, se establece el número de días especificado por defecto; de lo contrario, el que ha sido transmitido al método. De momento, este método no se usa en ningún sitio.
Método para devolver el objeto de instantánea del DOM según la hora especificada:
//+------------------------------------------------------------------+ //| Return the DOM snapshot object by its time | //+------------------------------------------------------------------+ CMBookSnapshot *CMBookSeries::GetMBook(const long time_msc) { CMBookSnapshot *book=new CMBookSnapshot(); if(book==NULL) return NULL; book.SetTime(time_msc); this.m_list.Sort(); int index=this.m_list.Search(book); delete book; return this.m_list.At(index); } //+------------------------------------------------------------------+
Aquí: creamos un objeto de instantánea temporal del DOM, le asignamos la hora necesaria, la bandera de una lista ordenada, y usando el método Search() obtenemos el índice del objeto en la lista con la hora igual a la buscada. Eliminamos necesariamente el objeto temporal y devolvemos el puntero al objeto encontrado según el índice en la lista.
Método para devolver la hora en milisegundos de la instantánea del DOM especificada según el índice:
//+------------------------------------------------------------------+ //| Returns the time in milliseconds | //| of a DOM snapshot specified by index | //+------------------------------------------------------------------+ long CMBookSeries::MBookTime(const int index) const { CMBookSnapshot *book=this.m_list.At(index); return(book!=NULL ? book.Time() : 0); } //+------------------------------------------------------------------+
Obtenemos el puntero al objeto de instantánea del DOM según el índice especificado y devolvemos su hora en milisegundos, o NULL en caso de fallo.
Método para devolver el nombre de la serie de instantáneas del DOM:
//+------------------------------------------------------------------+ //| Return the name of the DOM snapshot series | //+------------------------------------------------------------------+ string CMBookSeries::Header(void) { return CMessage::Text(MSG_MBOOK_SERIES_TEXT_MBOOKSERIES)+" \""+this.m_symbol+"\""; } //+------------------------------------------------------------------+
El método devuelve una cadena compuesta de la descripción del objeto y símbolo, por ejemplo:
Series of "EURUSD" DOM snapshots
Método que muestra en el diario la descripción de la serie de instantáneas del DOM:
//+------------------------------------------------------------------+ //| Display the description of the DOM snapshot series in the journal| //+------------------------------------------------------------------+ void CMBookSeries::Print(void) { string txt= ( CMessage::Text(MSG_TICKSERIES_REQUIRED_HISTORY_DAYS)+(string)this.RequiredUsedDays()+", "+ CMessage::Text(MSG_LIB_TEXT_TS_ACTUAL_DEPTH)+(string)this.DataTotal() ); ::Print(this.Header(),": ",txt); } //+------------------------------------------------------------------+
Primero, se crea el encabezado con la descripción de la serie de instantáneas, número solicitado de días de los datos y el número real recopilado de las instantáneas del DOM. Luego, se muestran cíclicamente las descripciones de todas las órdenes que forman parte del objeto de instantánea.
Con esto, damos por terminada la creación de las clases del objeto de instantánea y del objeto de serie de instantáneas del DOM.
Prueba
Para la simulación, vamos a usar el asesor del artículo anterior
y guardarlo en la nueva carpeta \MQL5\Experts\TestDoEasy\Part64\ con el nombre nuevo TestDoEasyPart64.mq5.
Vamos a crear el objeto de serie de instantáneas del DOM para el símbolo actual en el asesor. Cada vez que se active el manejador OnBoolEvent() para el símbolo actual, vamos a añadir el nuevo objeto de instantánea a la lista. En el comentario del gráfico, mostramos los datos sobre el número de los objetos de instantáneas añadidos a la lista y dos ordenes extremas de la instantánea actual: la máxima de venta y la mínima de compra. Al obtener los datos del DOM por primera vez, los visualizamos en el diario del terminal.
Eliminamos del listado del EA la inclusión de las clases de los objetos de órdenes. Ahora, están incluidas en los archivos de nuevas clases que hemos creado hoy:
//+------------------------------------------------------------------+ //| TestDoEasyPart63.mq5 | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/es/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/es/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
En vez de ellas, añadimos la inclusión del archivo de la clase de serie de las instantáneas del DOM:
//+------------------------------------------------------------------+ //| TestDoEasyPart64.mq5 | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/es/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/es/users/artmedia70" #property version "1.00" //--- includes #include <DoEasy\Engine.mqh> #include <DoEasy\Objects\Book\MBookSeries.mqh> //--- enums
En la lista de variables globales del EA, declaramos el objeto de la clase de la serie de instantáneas del DOM:
//--- global variables CEngine engine; SDataButt butt_data[TOTAL_BUTT]; string prefix; double lot; double withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal); ushort magic_number; uint stoploss; uint takeprofit; uint distance_pending; uint distance_stoplimit; uint distance_pending_request; uint bars_delay_pending_request; uint slippage; bool trailing_on; bool pressed_pending_buy; bool pressed_pending_buy_limit; bool pressed_pending_buy_stop; bool pressed_pending_buy_stoplimit; bool pressed_pending_close_buy; bool pressed_pending_close_buy2; bool pressed_pending_close_buy_by_sell; bool pressed_pending_sell; bool pressed_pending_sell_limit; bool pressed_pending_sell_stop; bool pressed_pending_sell_stoplimit; bool pressed_pending_close_sell; bool pressed_pending_close_sell2; bool pressed_pending_close_sell_by_buy; bool pressed_pending_delete_all; bool pressed_pending_close_all; bool pressed_pending_sl; bool pressed_pending_tp; double trailing_stop; double trailing_step; uint trailing_start; uint stoploss_to_modify; uint takeprofit_to_modify; int used_symbols_mode; string array_used_symbols[]; string array_used_periods[]; bool testing; uchar group1; uchar group2; double g_point; int g_digits; //--- CMBookSeries book_series; //+------------------------------------------------------------------+
Todo el trabajo de la creación de la lista de la serie de instantáneas del DOM se realiza en el manejador OnBoolEvent():
//+------------------------------------------------------------------+ //| 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; //--- Work by the current symbol if(symbol==sym.Name()) { //--- Set a symbol and a required number of data days for the DOM snapshot series object book_series.SetSymbol(sym.Name()); book_series.SetRequiredUsedDays(); //--- Update the DOM snapshot series if(!book_series.Refresh(sym.Time())) return; //--- Get the last DOM snapshot object from the DOM snapshot series object CMBookSnapshot *book=book_series.GetLastMBook(); if(book==NULL) return; //--- Get the very first and last DOM order objects from the DOM snapshot object CMarketBookOrd *ord_0=book.GetMBookByListIndex(0); CMarketBookOrd *ord_N=book.GetMBookByListIndex(book.DataTotal()-1); if(ord_0==NULL || ord_N==NULL) return; //--- Display the time of the current DOM snapshot in the chart comment, //--- the maximum number of displayed orders in DOM for a symbol, //--- the obtained number of orders in the current DOM snapshot, //--- the total number of DOM snapshots set in the series list and //--- the highest and lowest orders of the current DOM snapshot Comment ( DFUN,sym.Name(),": ",TimeMSCtoString(book.Time()), ", symbol book size=",sym.TicksBookdepth(), ", last book data total: ",book.DataTotal(), ", series books total: ",book_series.DataTotal(), "\nMax: ",ord_N.Header(),"\nMin: ",ord_0.Header() ); //--- Display the first DOM snapshot in the journal if(first) { //--- series description book_series.Print(); //--- snapshot description book.Print(); first=false; } } } //+------------------------------------------------------------------+
Todas las cadenas del código están comentadas y espero que no requieran aclaraciones adicionales.
En cualquier caso, el lector podrá escribir cualquier duda en los comentarios al artículo.
Compilamos el EA y lo iniciamos en el gráfico de cualquier símbolo, estableciendo previamente en los ajustes el uso de dos símbolos especificados y marco temporal actual:
En el diario, se mostrarán los datos sobre la serie de instantáneas que ha sido creada y sobre la primera instantánea:
Account 8550475: Artyom Trishkin (MetaQuotes Software Corp.) 10428.13 USD, 1:100, Hedge, MetaTrader 5 demo --- Initializing "DoEasy" library --- Working with predefined symbol list. The number of used symbols: 2 "AUDUSD" "EURUSD" Working with the current timeframe only: H1 AUDUSD symbol timeseries: - Timeseries "AUDUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5121 EURUSD symbol timeseries: - Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 6046 Tick series "AUDUSD": Requested number of days: 1, Historical data created: 176033 Tick series "EURUSD": Requested number of days: 1, Historical data created: 181969 Subscribed to Depth of Market AUDUSD Subscribed to Depth of Market EURUSD Library initialization time: 00:00:12.516 The "EURUSD" DOM snapshot series: Requested number of days: 1, Actual history depth: 1 "EURUSD" DOM snapshot (2021.02.09 22:16:24.557): - Sell order: 1.21198 [250.00] - Sell order: 1.21193 [100.00] - Sell order: 1.21192 [50.00] - Sell order: 1.21191 [30.00] - Sell order: 1.21190 [6.00] - Buy order: 1.21188 [36.00] - Buy order: 1.21186 [50.00] - Buy order: 1.21185 [100.00] - Buy order: 1.21180 [250.00]
En el gráfico, se mostrarán los datos sobre la hora de la última instantánea del DOM, número de órdenes para el símbolo, número de órdenes en la instantánea actual y número total de instantáneas del DOM añadidas a la lista de instantáneas:
En la imagen se muestran los datos para el EA que ya estaba operando algún tiempo (5019 instantáneas han sido añadidas a la lista)
¿Qué es lo próximo?
En el siguiente artículo, vamos a crear una colección de las series de instantáneas del DOM. Eso nos permitirá trabajar de forma plenamente operativa con los DOMs de cualquier símbolo que tenga activada la suscripción al DOM y permitida su transmisión.
Más abajo se adjuntan todos los archivos de la versión actual de la biblioteca y el archivo del asesor de prueba para MQL5. Puede descargarlo todo y ponerlo a prueba por sí mismo.
Cabe mencionar que las clases para trabajar con el DOM se encuentran en el proceso del desarrollo. Por tanto, no se recomienda usarlas en sus programas en esta fase.
Si tiene preguntas, observaciones o sugerencias, podrá concretarlas en los comentarios al artículo.
Artículos de esta serie:
Trabajando con los precios en la biblioteca DoEasy (Parte 61): Actualización de las series de tick en tiempo real, preparando para trabajar con la Profundidad del mercado
Trabajando con los precios en la biblioteca DoEasy (Parte 63): Profundidad del mercado, clase de orden abstracta de la Profundidad del mercado
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/9044





- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso