English Русский Español Deutsch 日本語 Português
DoEasy 函数库中的价格(第六十四部分):市场深度,DOM 快照类和快照序列对象

DoEasy 函数库中的价格(第六十四部分):市场深度,DOM 快照类和快照序列对象

MetaTrader 5示例 | 4 五月 2021, 13:57
1 383 0
Artyom Trishkin
Artyom Trishkin

内容


概述

之前的文章中,我创建了市场深度(DOM)抽象定单对象,及其衍生类。 在激活 OnBookEvent() 处理程序的那一刻,一次调用 MarketBookGet() 函数期间得到的多个对象构成一个 DOM 快照。 由 MarketBookGet() 函数获得的数据会在 MqlBookInfo 结构数组中进行设置。 基于所获数据,我们能够创建 DOM 快照对象,它是为了存储来自 MqlBookInfo 结构数组中得到的所有 DOM 订单。 换言之,所提到的结构数组中的数据将形成 DOM 快照,其中每个结构成员均由单一 DOM 订单对象表达。 每次激活 OnBookEvent() 处理程序都会引发创建一个 DOM 快照,然后将其输入到 DOM 快照序列类的对象当中。
指向 CObject 类及其子代实例的标准库动态指针数组用作存储 DOM 快照对象的列表。 列表的大小受限于指定的对象数量。 默认情况下,列表的大小不会超过 20 万个 DOM 快照对象,它应能覆盖大约一两个交易日。 为程序中用到的每个品种创建这种 DOM 快照序列列表。 作为结果,每个这样的列表都存储在 DOM 数据集合当中。</ s5>

在此,我将创建两个类 — 单一品种的 DOM 快照对象类,和单一品种的 DOM 快照序列类。 在下一篇文章中,我会创建并测试 DOM 快照序列集合类。


改进库类

在 \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
   
  };
//+------------------------------------------------------------------+

以及与新添加的索引相对应的文本消息

//--- 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"},
   
  };
//+---------------------------------------------------------------------+

在序列列表中搜索必要的 DOM 快照对象时,为了能够指定按时间排序的标准,我们需要往 DOM 订单对象里添加一个新属性 — 快照接收时间(以毫秒为单位)。 订单本身没有这个属性,但我们能够跟踪接收 DOM 快照的时间。 DOM 快照序列列表包含单一整数型属性(获取快照的时间,以毫秒为单位),为了避免为引入新的枚举,我们将此属性添加到 DOM 订单对象属性之中。 获取快照的时间分配给单一快照对象中的每笔订单。 当在序列列表中进行搜索和排序时,我们将采用这个新近更新的常量。

在 \MQL5\Include\DoEasy\Defines.mqh 里,输入 DOM 快照序列参数,如此我们就可以在列表中设置必要的数据天数和最大快照数量:

//--- 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
//+------------------------------------------------------------------+

我不打算再用第一个参数(天数)— 稍后,我将尝试将数据链接到即时报价数据天数。 当前,我将仅使用第二个参数-DOM快照数据的最大可能数量。

在同一文件里,添加新的整数型 DOM 订单对象属性(以毫秒为单位的时间),并将对象整数型属性的数量增加到 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
//+------------------------------------------------------------------+

由于我添加了一个新的整数型属性,因此我还应该添加一个按该整数型属性进行排序的新条件

//+------------------------------------------------------------------+
//| 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
  };
//+------------------------------------------------------------------+

当前开发的 DOM 快照序列对象类中,在 DOM 快照对象进行排序时,指定该常数作为参数。

因此在 \MQL5\Include\DoEasy\Services\Select.mqh 中保存的 CSelect 类文件里需要一个搜索并排序 DOM 订单对象的方法。 在第三篇文章里中曾进行过详细讲述。 现在,我将简单讲述该类的所有必要修改,以便按 DOM 订单对象的属性规划搜索和排序。

将 DOM 抽象订单对象类包含到文件之中:

//+------------------------------------------------------------------+
//|                                                       Select.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/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"
//+------------------------------------------------------------------+

在类主体的末尾声明所有所需的方法

//+------------------------------------------------------------------+
//| 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);
//---
  };
//+------------------------------------------------------------------+

在类主体之外实现它们:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

该方法的操作逻辑与我之前为其他函数库对象类创建的其他方法逻辑相似。 故此,有关该方法的操作我将不再赘述。 您可在此处找到所有必要的数据。

由于我引入了一个新参数 — 获取 DOM 快照的时间,因此将在 DOM 抽象订单对象中设置该参数。 MqlBookInfo 结构定义了一个 DOM 订单,但缺少时间参数。 这意味着我们需要自己为每个 DOM 订单对象定义接收快照的时间。

为了达成此目标,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

该方法简单地在对象新属性中设置以毫秒为单位的获取时间。

在 DOM 抽象订单类的参数型构造函数中初始化获取快照的时间

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

在接收 DOM 快照时,会为存在于单个 DOM 快照中的每笔订单设置时间。

在 DOM 抽象订单类文件 MarketBookOrd.mqh,及其衍生类文件 MarketBookBuy.mqhMarketBookBuyMarket.mqhMarketBookSell.mqhMarketBookSellMarket.mqh 里针对虚拟对象描述方法略微进行了一些修改:

//--- 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);

每个方法若得到标志,表示需要在对象描述中显示品种名称。 默认情况下,订单对象描述中不显示品种。 原因是订单对象并非独立的,可以这么说,它是我在本文中开发的 DOM 快照类的一部分。 当显示 DOM 快照对象描述,及其所有订单描述时,再显示每笔订单的品种看起来有些多余,因为在 DOM 快照对象描述的标题之中已经显示了该品种。

这些方法的改进对于上述所有类而言都是相同的。

对于 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));
  }
//+------------------------------------------------------------------+

对于 CMarketBookBuyCMarketBookBuyMarketCMarketBookSell 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)+"]";
  }
//+------------------------------------------------------------------+

对于 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)+"]";
  }
//+------------------------------------------------------------------+

对于 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)+"]";
  }
//+------------------------------------------------------------------+

对于 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)+"]";
  }
//+------------------------------------------------------------------+

相应地,在所有衍生类的所有这些方法的声明中添加标志

//--- Return the object short name
   virtual string    Header(const bool symbol=false);

默认情况下,在对象描述中不显示品种。


市场深度快照对象类

现在,开发 DOM 快照对象类的一切准备就绪。 实际上,这是激活 OnBookEvent() 处理程序时,需要传递给 MqlBookInfo 结构数组的 DOM 请求列表。 不过,该类中的每个数组请求都由 CMarketBookOrd 类对象表示 — 其后代。 它们都被添加到 CArrayObj 列表之中,其为指向标准库 CObject 类及其后代实例的指针的动态数组类。 除了存储 DOM 请求对象的列表之外,该类还提供处理对象及其列表的功能,这些功能是所有函数库对象的标准功能 — 按其各种属性进行搜索和排序 — 从而便利地在程序中操控 DOM 收集任意统计数据信息。

在 \MQL5\Include\DoEasy\Objects\Book\ 目录下,创建含有 CMBookSnapshot 类的新文件 MarketBookSnapshot.mqh
所有 CBaseObj 库对象的基准对象类都应用作基类

DOM 抽象订单对象的衍生对象类的文件也应包含在文件之中

我们来研究一下类及其方法的实现清单:

//+------------------------------------------------------------------+
//|                                           MarketBookSnapshot.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\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;   }
  };
//+------------------------------------------------------------------+

在此,我们可以看到与所有库对象类相似的常见排列方式:类成员变量在私密部分中声明,而公开部分含有按指定订单对象属性返回列表的标准方法,而比较两个 DOM 快照对象的方法,在列表中排序并搜索它们(稍后对象会被存储到 DOM 快照序列对象的列表),描述 DOM 快照对象的方法,以及两个构造函数 — 默认的,和一个参数化(在创建含有所有已知属性的新 DOM 快照对象时,将采用参数型构造函数,而默认属性将用于快速创建新对象,并添加必需的属性,以便按指定属性值在列表里搜索)。 简化的方法访问对象属性,并可用来设置和返回我们稍后所需的一些对象属性。

我们来看一下类方法的实现。

在参数型类构造器中,查看获得的 MqlBookInfo 结构数组,创建相应类型的 DOM 订单对象,并将其添加到列表之中。

//+------------------------------------------------------------------+
//| 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;
     }
  }
//+------------------------------------------------------------------+

该方法返回 DOM 快照对象的简称:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMBookSnapshot::Header(void)
  {
   return CMessage::Text(MSG_MBOOK_SNAP_TEXT_SNAPSHOT)+" \""+this.Symbol();
  }
//+------------------------------------------------------------------+

此处,我们仅创建一个由文本消息组成的字符串,其对象和品种描述大致如下所示:

EURUSD DOM snapshot

该方法在日志中显示 DOM 快照对象的简述:

//+------------------------------------------------------------------+
//| Display a short description of the object in the journal         |
//+------------------------------------------------------------------+
void CMBookSnapshot::PrintShort(void)
  {
   ::Print(this.Header()," ("+TimeMSCtoString(this.m_time),")");
  }
//+------------------------------------------------------------------+

在日志中,该方法打印一个字符串,包含对象名称加上 DOM 快照时间(以毫秒为单位),例如:

"EURUSD" DOM snapshot (2021.02.09 22:16:24.557)

在日志中显示 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());
     }
  }
//+------------------------------------------------------------------+

首先显示含有 DOM 快照描述的标头,然后循环显示所有 DOM 订单对象的描述。

由于 DOM 快照对象列表中的订单对象无法获取时间,因此我将实现为列表中所有订单对象设置指定时间(以毫秒为单位)的方法:

//+------------------------------------------------------------------+
//| 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);
     }
  }
//+------------------------------------------------------------------+

在遍历列表里所有 DOM 订单对象的循环中,获取下一个订单对象,并将指定的时间分配至 DOM 快照对象属性。 因此,DOM 列表中的所有订单对象都含有相同的接收时间。 这是合乎逻辑的,因为我们是在 OnBookEvent() 处理程序激活时才获取它们的。 为 DOM 快照对象及其所有订单设置激活时间。

DOM 快照对象已准备就绪。 在 OnBookEvent() 处理程序的每次激活时获取一个新的 DOM 快照,并创建相应的对象,现在是将这些对象放置到列表当中的时候了。
所有这些对象都将存储在 DOM 序列对象类之中。

市场深度快照序列对象类

就其“意识形态”而言,DOM 快照序列类与品种的时间序列类,或即时报价数据类相似。 在此个类中,可以从运行环境中获取数据,而在 DOM 快照列表类中,我们无法获取历史数据 — 它必须从实时中累积。 因此,该类不会拥有列表的创建方法,而仅含有列表更新方法。

在 \MQL5\Include\DoEasy\Objects\Book\ 里,创建包含 CMBookSeries 类的新文件 MBookSeries.mqh
所有 CBaseObj 库对象的基准对象类都应用作基类

DOM 快照对象类的文件应包含在该文件中

我们来研究一下类清单,然后再分析其方法:

//+------------------------------------------------------------------+
//|                                                  MBookSeries.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 "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);
  };
//+------------------------------------------------------------------+

在此我们可以看到:

  • 按指定属性接收对象属性和对象列表的标准方法,
  • 设置某些属性的方法,
  • 比较两个列表对象,并仅按品种名称对它们进行排序的方法,
  • 返回对象名称和类构造函数的方法。

我们来看一下类方法的实现。

列表品种在参数型构造函数的初始化清单里设置,而列表会在方法主体中被清除。 列表已被设置按时间排序的标志(以毫秒为单位),并指定了所需的 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);
  }
//+------------------------------------------------------------------+

更新 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;
  }
//+------------------------------------------------------------------+

该方法会在激活 OnBookEvent() 处理程序时调用。 该方法接收处理程序的激活时间。 使用 MarketBookGet() 获取 DOM 结构数组。 使用该结构创建新的 DOM 快照对象,并将其添加到快照序列列表之中。
整个逻辑在方法代码的注释中进行了详解。 我相信,它很清楚。

将品种名称放置到快照序列列表的方法:

//+------------------------------------------------------------------+
//| Set a symbol                                                     |
//+------------------------------------------------------------------+
void CMBookSeries::SetSymbol(const string symbol)
  {
   if(this.m_symbol==symbol)
      return;
   this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol);
  }
//+------------------------------------------------------------------+

这里的一切都是透明的。 如果传递的是 NULL 或空字符串,则设置为当前品种。 否则,按照传递给该方法的那个值设置。

该方法定义 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);
  }
//+------------------------------------------------------------------+

如果传递的是零值,则设置默认的天数,否则,按照传递给该方法的那个数值设置。 该方法尚未在任何地方使用。

该方法返回指定时间的 DOM 快照对象:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

此处,我们创建一个临时的 DOM 快照对象为其设置所需的时间,以及列表已排序标志,并使用 Search() 方法获取所需时间对象在列表中的索引确保删除临时对象,并依据列表中的索引返回检测到的对象指针

该方法返回依据索引指定的 DOM 快照时间(以毫秒为单位):

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+

依据指定索引获取指向 DOM 快照对象的指针,并返回其时间(以毫秒为单位),若失败则返回 NULL

该方法返回 DOM 快照序列名称:

//+------------------------------------------------------------------+
//| Return the name of the DOM snapshot series                       |
//+------------------------------------------------------------------+
string CMBookSeries::Header(void)
  {
   return CMessage::Text(MSG_MBOOK_SERIES_TEXT_MBOOKSERIES)+" \""+this.m_symbol+"\"";
  }
//+------------------------------------------------------------------+

该方法返回由对象说明和品种组成的字符串,例如:

Series of "EURUSD" DOM snapshots

该方法在日志中显示 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);
  }
//+------------------------------------------------------------------+

首先创建含有快照序列说明、请求的数据天数和 DOM 快照实际收集天数的标头。 然后,在循环中逐一显示快照对象的所有订单。

DOM 快照对象和对象序列类的创建至此完毕。

测试

为了执行测试,我们借用上一篇文章中的 EA,并将其保存在 \MQL5\Experts\TestDoEasy\Part64\ 之下,命名为 TestDoEasyPart64.mq5

在 EA 中,为当前品种创建 DOM 快照序列对象,且当前品种上每次激活 OnBoolEvent() 处理程序时添加一个新的 DOM 快照对象。 在图表注释中显示有关添加到列表的快照对象数量和当前快照的价格两端订单(最高卖出和最低买入)的数据。 首次接收 DOM 数据时,将其打印在终端日志中。

从 EA 清单中删除与订单对象类的关联 — 它们现在已包含在我今天创建的新类文件之中:

//+------------------------------------------------------------------+
//|                                             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

代之,添加 DOM 快照序列类文件的包含

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart64.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\MBookSeries.mqh>
//--- enums

在 EA 全局变量清单中,声明 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;
//+------------------------------------------------------------------+

创建 DOM 快照序列列表的整套操作,在 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;
        }
     }
  }
//+------------------------------------------------------------------+

所有代码在注释中均有讲述。 我希望,不必对其解释。
如果您有任何疑问,请随时在评论中提问。

编译 EA,并在品种图表中启动它,并在设置中初步定义了两个操作的指定品种和当前时间帧:


日志显示关于所创建 DOM 快照序列的数据第一个快照

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]

在品种图表中显示:最后的 DOM 快照的编号、品种的订单数量、当前快照中的订单数量、以及添加到 DOM 快照列表中的 DOM 快照总数:

该示意图显示了已经运行了一段时间的 EA 上的数据(已在列表中添加了 5019 个快照)

下一步是什么?

在下一篇文章中,我将创建 DOM 快照序列的集合,若启用了广播功能,用户能够全盘操控任意品种的 DOM 有效订阅。

以下是该函数库当前版本的所有文件,以及 MQL5 的测试 EA 文件,供您测试和下载。
操控 DOM 的类正在开发当中,因此,在现阶段强烈建议不要在自定义程序中使用它们。
请您在评论中留下问题和建议。

返回内容目录

*该系列的前几篇文章:

DoEasy 函数库中的价格(第六十二部分):实时更新即时报价序列,为操控市场深度做准备
DoEasy 函数库中的价格(第六十三部分):市场深度及其抽象请求类

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/9044

附加的文件 |
MQL5.zip (3897 KB)
DoEasy 函数库中的价格(第六十五部分):市场深度集合并操控 MQL5.com 信号的类 DoEasy 函数库中的价格(第六十五部分):市场深度集合并操控 MQL5.com 信号的类
在本文中,我将创建所有品种的市场深度集合类,并着手开发创建信号对象类来操控 MQL5.com 信号服务的功能。
神经网络变得轻松(第十一部分):自 GPT 获取 神经网络变得轻松(第十一部分):自 GPT 获取
也许,GPT-3 是目前已有语言类神经网络中最先进的模型之一,它的最大变体可包含 1750 亿个参数。 当然,我们不打算在家用 PC 上创建如此庞然之物。 然而,我们可以看看在我们的操作中能够采用哪种体系解决方案,以及如何从中受益。
神经网络变得轻松(第十二部分):舍弃 神经网络变得轻松(第十二部分):舍弃
作为研究神经网络的下一步,我建议研究在神经网络训练过程中提高收敛性的方法。 有若干种这样的方法。 在本文中,我们将研究其中之一,名为“舍弃”。
DoEasy 函数库中的价格(第六十三部分):市场深度及其抽象请求类 DoEasy 函数库中的价格(第六十三部分):市场深度及其抽象请求类
在本文中,我将着手开发操控市场深度的功能。 我还将创建市场深度抽象订单对象,及其衍生类。