请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  量化策略 帖子:3364672 新帖:30

DoEasy 函数库中的价格(第六十五部分):市场深度集合并操控 MQL5.com 信号的类

执着技术派发表于:5 月 10 日 16:00回复(1)

内容

  • 概述
  • 改进库类
  • DOM 集合类
  • MQL5 信号对象类
  • 测试
  • 下一步是什么?

概述

我们已拥有了操控任何品种 DOM 的功能 — 在之前的文章中,我已创建了 DOM 抽象订单对象及其衍生类,DOM 快照类和 DOM 快照序列类。 如今,只剩下为 DOM 快照序列对象创建一个通用存储 — 快照序列集合类,它能存储所有这些序列,并可便利地访问存储在集合列表中的任意 DOM 快照,并支持指定序列尺寸的自动更新(添加新快照,和删除旧快照)。

除了创建 DOM 快照序列集合类之外,我还将启动新的函数库部分 — 其他库类。
我将从操控 MQL5.com 信号服务的功能开始,即,我将创建信号对象类来存储 MQL5.com 信号服务广播里单个信号的所有数据。


改进库类

我们现将新消息添加到函数库当中。 在 \MQL5\Include\DoEasy\Data.mqh 里,加入新的消息索引:

//--- CMBookSeries
   MSG_MBOOK_SERIES_TEXT_MBOOKSERIES,                 // DOM snapshot series
   MSG_MBOOK_SERIES_ERR_ADD_TO_LIST,                  // Error. Failed to add DOM snapshot series to the list
   
//--- CMBookSeriesCollection
   MSG_MB_COLLECTION_TEXT_MBCOLLECTION,               // DOM snapshot series collection
 
//--- CMQLSignal
   MSG_SIGNAL_MQL5_TEXT_SIGNAL,                       // Signal
   MSG_SIGNAL_MQL5_TEXT_SIGNAL_MQL5,                  // MQL5.com Signals service signal
   MSG_SIGNAL_MQL5_TRADE_MODE,                        // Account type
   MSG_SIGNAL_MQL5_DATE_PUBLISHED,                    // Publication date
   MSG_SIGNAL_MQL5_DATE_STARTED,                      // Monitoring start date
   MSG_SIGNAL_MQL5_DATE_UPDATED,                      // Date of the latest update of the trading statistics 
   MSG_SIGNAL_MQL5_ID,                                // ID
   MSG_SIGNAL_MQL5_LEVERAGE,                          // Trading account leverage
   MSG_SIGNAL_MQL5_PIPS,                              // Trading result in pips
   MSG_SIGNAL_MQL5_RATING,                            // Position in the signal rating
   MSG_SIGNAL_MQL5_SUBSCRIBERS,                       // Number of subscribers
   MSG_SIGNAL_MQL5_TRADES,                            // Number of trades
   MSG_SIGNAL_MQL5_SUBSCRIPTION_STATUS,               // Status of account subscription to a signal
   
   MSG_SIGNAL_MQL5_EQUITY,                            // Account equity
   MSG_SIGNAL_MQL5_GAIN,                              // Account growth in %
   MSG_SIGNAL_MQL5_MAX_DRAWDOWN,                      // Maximum drawdown
   MSG_SIGNAL_MQL5_PRICE,                             // Signal subscription price
   MSG_SIGNAL_MQL5_ROI,                               // Signal ROI (Return on Investment) in %

   MSG_SIGNAL_MQL5_AUTHOR_LOGIN,                      // Author login
   MSG_SIGNAL_MQL5_BROKER,                            // Broker (company) name
   MSG_SIGNAL_MQL5_BROKER_SERVER,                     // Broker server
   MSG_SIGNAL_MQL5_NAME,                              // Name
   MSG_SIGNAL_MQL5_CURRENCY,                          // Account currency
   
   MSG_SIGNAL_MQL5_TEXT_GAIN,                         // Growth
   MSG_SIGNAL_MQL5_TEXT_DRAWDOWN,                     // Drawdown
   
  };
//+------------------------------------------------------------------+

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

//--- CMBookSeries
   {"Серия снимков стакана цен","Series of shots of the Depth of Market"},
   {"Ошибка. Не удалось добавить серию снимков стакана цен в список","Error. Failed to add a shots series of the Depth of Market to the list"},
   
//--- CMBookSeriesCollection
   {"Коллекция серий снимков стакана цен","Collection of series of the Depth of Market shot"},   
   
//--- CMQLSignal
   {"Сигнал","Signal"},
   {"Сигнал сервиса сигналов MQL5.com","Signal from MQL5.com signal service"},
   {"Тип счета","Account type"},
   {"Дата публикации","Publication date"},
   {"Дата начала мониторинга","Monitoring starting date"},
   {"Дата последнего обновления торговой статистики","The date of the last update of the signal's trading statistics"},
   {"ID","ID"},
   {"Плечо торгового счета","Account leverage"},
   {"Результат торговли в пипсах","Profit in pips"},
   {"Позиция в рейтинге сигналов","Position in rating"},
   {"Количество подписчиков","Number of subscribers"},
   {"Количество трейдов","Number of trades"},
   {"Состояние подписки счёта на этот сигнал","Account subscription status for this signal"},

   {"Средства на счете","Account equity"},
   {"Прирост счета в процентах","Account gain"},
   {"Максимальная просадка","Account maximum drawdown"},
   {"Цена подписки на сигнал","Signal subscription price"},
   {"Значение ROI (Return on Investment) сигнала в %","Return on Investment (%)"},
   
   {"Логин автора","Author login"},
   {"Наименование брокера (компании)","Broker name (company)"},
   {"Сервер брокера","Broker server"},
   {"Имя","Name"},
   {"Валюта счета","Base currency"},
   
   {"Прирост","Gain"},
   {"Просадка","Drawdown"},
   
  };
//+---------------------------------------------------------------------+

由于我今天会开发一个新集合,因此我们需要为其设置 ID。 在 \MQL5\Include\DoEasy\Defines.mqh 文件的 ID 部分,加入 DOM 快照序列集合 ID:

//--- Collection list IDs
#define COLLECTION_HISTORY_ID          (0x777A)                   // Historical collection list ID
#define COLLECTION_MARKET_ID           (0x777B)                   // Market collection list ID
#define COLLECTION_EVENTS_ID           (0x777C)                   // Event collection list ID
#define COLLECTION_ACCOUNT_ID          (0x777D)                   // Account collection list ID
#define COLLECTION_SYMBOLS_ID          (0x777E)                   // Symbol collection list ID
#define COLLECTION_SERIES_ID           (0x777F)                   // Timeseries collection list ID
#define COLLECTION_BUFFERS_ID          (0x7780)                   // Indicator buffer collection list ID
#define COLLECTION_INDICATORS_ID       (0x7781)                   // Indicator collection list ID
#define COLLECTION_INDICATORS_DATA_ID  (0x7782)                   // Indicator data collection list ID
#define COLLECTION_TICKSERIES_ID       (0x7783)                   // Tick series collection list ID
#define COLLECTION_MBOOKSERIES_ID      (0x7784)                   // DOM series collection list ID
//--- Data parameters for file operations

我们来改进 DOM 快照序列对象类文件。 在某些实例当中,对象描述应一次性显示;而有时,我们需要一次性显示所有 DOM 快照序列的描述。 在此情况下,如果在每个序列的描述之前添加连字符,则该列表看起来更具视觉吸引力。 在 DOM 快照序列类 \MQL5\Include\DoEasy\Objects\Book\MBookSeries.mqh 文件中,于方法的描述中加入修改:

//--- Display (1) description and (2) short description of a DOM snapshot series
   void              Print(const bool dash=false);
   void              PrintShort(const bool dash=false);

//--- Constructors

简单地在对象描述之前使用指示必须显示连字符的标志

在方法的实现中添加相同的修改

//+------------------------------------------------------------------+
//| Display the description of the DOM snapshot series in the journal|
//+------------------------------------------------------------------+
void CMBookSeries::Print(const bool dash=false)
  {
   string txt=
     (
      CMessage::Text(MSG_TICKSERIES_REQUIRED_HISTORY_DAYS)+(string)this.RequiredUsedDays()+", "+
      CMessage::Text(MSG_LIB_TEXT_TS_ACTUAL_DEPTH)+(string)this.DataTotal()
     );
   ::Print((dash ? "- " : ""),this.Header(),": ",txt);
  }
//+------------------------------------------------------------------+
//| Display a short description of a DOM snapshot series             |
//+------------------------------------------------------------------+
void CMBookSeries::PrintShort(const bool dash=false)
  {
   ::Print((dash ? "- " : ""),this.Header());
  }
//+------------------------------------------------------------------+

默认情况下,该标志设置为 false,因此在对象描述之前不会显示连字符。


DOM 集合类

我们已拥有创建 DOM 集合所需的所有对象。 即,我们已拥有由 MqlBookInfo 结构表示终端中的所有 DOM 订单对象。 当 BookEvent 事件抵达,则会调用 OnBookEvent() 处理程序。 指定已发生 DOM 变化事件的品种作为其参数。 我们能够把所有收到的当前 DOM 数据放入 MqlBookInfo 结构数组。 函数库中此数据的集合由 DOM 快照对象描述,其订单对象正是我们在处理 DOM 变更事件时得到的。 在每次 DOM 变更期间,我们都会创建一个新的快照对象,并将其添加到列表之中。 这样的列表由 DOM 快照序列对象来表示。 我们为每个订阅的品种创建这样的列表,以便接收 DOM 事件。 列表是实时创建的(不幸的是,终端未提供品种的 DOM 变更历史记录)。 结果就是,我们现在需要把所有现存列表合并到单个 DOM 集合对象之中。

品种 DOM 集合用于存储不断更新的 DOM 快照列表,令我们能够在程序运行时为每个品种创建 DOM 变更的历史记录。 我们能够从集合列表里获取存在的任何快照的数据。 此外,我们将从每个快照中提取任意订单。 我们能够搜索所需的数据,按指定标准进行列表排序,并依据可用集合列表进行统计研究。

在 \MQL5\Include\DoEasy\Collections\ 下的 BookSeriesCollection.mqh 文件里,创建新类 CMBookSeriesCollection

所有 CBaseObj 库对象的基准对象类均作为基类,而所有必需的文件均应包含在类清单中

//+------------------------------------------------------------------+
//|                                         BookSeriesCollection.mqh |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                             https://MQL5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://MQL5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Objects\Book\MBookSeries.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
//+------------------------------------------------------------------+
//| Collection of symbol DOM series                                  |
//+------------------------------------------------------------------+
class CMBookSeriesCollection : public CBaseObj
  {
  }

我们来看一下类主体及其方法,并分析这些方法的实现及其目的:

//+------------------------------------------------------------------+
//| Collection of symbol DOM series                                  |
//+------------------------------------------------------------------+
class CMBookSeriesCollection : public CBaseObj
  {
private:
   CListObj                m_list;                                   // List of used symbol DOM series
//--- Return the DOM series index by a symbol name
   int                     IndexMBookSeries(const string symbol);
public:
//--- Return (1) itself, (2) DOM series collection list and (3) the number of DOM series in the list
   CMBookSeriesCollection *GetObject(void)                              { return &this;               }
   CArrayObj              *GetList(void)                                { return &this.m_list;        }
   int                     DataTotal(void)                        const { return this.m_list.Total(); }
//--- Return the pointer to the DOM series object (1) by symbol and (2) by index in the list
   CMBookSeries           *GetMBookseries(const string symbol);
   CMBookSeries           *GetMBookseries(const int index)              { return this.m_list.At(index);}
//--- Create symbol DOM series collection list
   bool                    CreateCollection(const CArrayObj *list_symbols,const uint required=0);
//--- Set the flag of using the DOM series of (1) a specified symbol and (2) all symbols
   void                    SetAvailableMBookSeries(const string symbol,const bool flag=true);
   void                    SetAvailableMBookSeries(const bool flag=true);
//--- Return the flag of using the DOM series of (1) a specified symbol and (2) all symbols
   bool                    IsAvailableMBookSeries(const string symbol);
   bool                    IsAvailableMBookSeries(void);

//--- Set the number of DOM history days of (1) a specified symbol and (2) all symbols
   bool                    SetRequiredUsedDays(const string symbol,const uint required=0);
   bool                    SetRequiredUsedDays(const uint required=0);

//--- Return the DOM snapshot object of a specified symbol (1) by index and (2) by time in milliseconds
   CMBookSnapshot         *GetMBook(const string symbol,const int index);
   CMBookSnapshot         *GetMBook(const string symbol,const long time_msc);

//--- Update the DOM series of a specified symbol
   bool                    Refresh(const string symbol,const long time_msc);

//--- Display (1) the complete and (2) short collection description in the journal
   void                    Print(void);
   void                    PrintShort(void);
   
//--- Constructor
                           CMBookSeriesCollection();
  };
//+------------------------------------------------------------------+

方法说明清晰地表明,集合本身由 m_list 表示,该集合存储由 CMBookSeries 类表达的不同品种的 DOM 快照序列对象。 这些品种的 DOM 快照对象均由 CMBookSnapshot 类表达。

我们来更详细地研究类方法的实现。

在类构造器当中清空集合列表为列表设置排序标志,并分配 DOM 序列集合列表 ID

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMBookSeriesCollection::CMBookSeriesCollection()
  {
   this.m_list.Clear();
   this.m_list.Sort();
   this.m_list.Type(COLLECTION_MBOOKSERIES_ID);
  }
//+------------------------------------------------------------------+

默认情况下,集合列表中存储的所有序列均按 DOM 快照的品种名称排序。

该方法创建品种的 DOM 序列集合列表:

//+------------------------------------------------------------------+
//| Create symbol DOM series collection list                         |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::CreateCollection(const CArrayObj *list_symbols,const uint required=0)
  {
//--- If an empty list of symbol objects is passed, exit
   if(list_symbols==NULL)
      return false;
//--- Get the number of symbol objects in the passed list
   int total=list_symbols.Total();
//--- Clear the DOM series collection list
   this.m_list.Clear();
//--- In a loop by all symbol objects
   for(int i=0;i<total;i++)
     {
      //--- get the next symbol object
      CSymbol *symbol_obj=list_symbols.At(i);
      //--- if failed to get a symbol object, move on to the next one in the list
      if(symbol_obj==NULL)
         continue;
      //--- Create a new DOM series object
      CMBookSeries *bookseries=new CMBookSeries(symbol_obj.Name(),required);
      //--- If failed to create the DOM series object, move on to the next symbol in the list
      if(bookseries==NULL)
         continue;
      //--- Set the sorted list flag for the DOM series collection list
      this.m_list.Sort();
      //--- If the object with the same symbol name is already present in the DOM series collection list, remove the DOM series object
      if(this.m_list.Search(bookseries)>WRONG_VALUE)
         delete bookseries;
      //--- otherwise, there is no object with such a symbol name in the collection yet
      else
        {
         //--- if failed to add the DOM series object to the collection list, remove the series object,
         //--- inform of that and return 'false'
         if(!this.m_list.Add(bookseries))
           {
            delete bookseries;
            ::Print(DFUN,"\"",symbol_obj.Name(),"\": ",CMessage::Text(MSG_MBOOK_SERIES_ERR_ADD_TO_LIST));
            return false;
           }
        } 
     }
//--- Collection created successfully, return 'true'
   return true;
  }
//+------------------------------------------------------------------+

方法的所有逻辑在其清单中都有详细描述。 简要地说,该方法接收程序中用到的所有品种列表,以及可在集合列表中存储的 DOM 快照数量。 依据传递给该方法的列表进行循环,从列表中接收下一个品种对象,依据该品种创建一个新的 DOM 快照序列对象,并将其添加到集合列表当中。 结果就是,我们得到不同品种的 DOM 快照序列对象的列表 — 存在于传递给该方法的列表之中。 所创建的每个快照序列列表最初都是空的。
在更新指定品种 DOM 快照序列列表的方法里,向列表集合里填充已创建列表:

//+------------------------------------------------------------------+
//| Update the snapshot series list of a specified symbol DOM        |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::Refresh(const string symbol,const long time_msc)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return false;
   return bookseries.Refresh(time_msc);
  }
//+------------------------------------------------------------------+

鉴于每个品种均可激活 OnBookEvent() 处理函数,因此更新方法仅针对集合中的一个品种,而非整个集合。 该方法接收发生 DOM 变更事件的品种名称,以及 DOM 变更事件的注册时间(以毫秒为单位)。 进而,我们按照传递给方法的品种来接收 DOM 快照序列对象,并返回 Refresh() 方法结果,即我们在上一篇文章中研究过的 DOM 快照序列对象。

按照品种名称返回 DOM 序列索引的方法:

//+------------------------------------------------------------------+
//| Return the DOM series index by a symbol name                     |
//+------------------------------------------------------------------+
int CMBookSeriesCollection::IndexMBookSeries(const string symbol)
  {
   const CMBookSeries *obj=new CMBookSeries(symbol==NULL || symbol=="" ? ::Symbol() : symbol);
   if(obj==NULL)
      return WRONG_VALUE;
   this.m_list.Sort();
   int index=this.m_list.Search(obj);
   delete obj;
   return index;
  }
//+------------------------------------------------------------------+

在此,我们采用输入中指定的品种创建一个新的临时 DOM 快照序列对象设置已排序列表标志(搜索仅在已排序的列表中执行),然后在列表中采用相同的品种获取对象索引。 确保删除临时对象,并返回获得的索引。 如果列表中存在指定品种的 DOM 快照序列对象,则 Search() 方法返回其索引,否则,该方法返回 -1。

返回指定品种 DOM 序列对象的方法:

//+------------------------------------------------------------------+
//| Return the specified symbol DOM series object                    |
//+------------------------------------------------------------------+
CMBookSeries *CMBookSeriesCollection::GetMBookseries(const string symbol)
  {
   int index=this.IndexMBookSeries(symbol);
   return this.m_list.At(index);
  }
//+------------------------------------------------------------------+

在此,我们利用上面指定的方法按照品种获取列表中的 DOM 快照序列对象的索引,并依据指定索引返回列表中的对象指针。 如果列表中不存在指定品种的对象(索引为 -1),则 At() 方法将返回 NULL

若要操控 DOM 的功能,我们需要订阅来接收每个品种的 DOM 变更事件。 此功能已存在于品种对象类中。 此外,DOM 快照序列对象含有标志,指示需要启用/禁用 DOM 变更事件的处理。 换言之,即使所订阅的 BookEvent 事件被激活,我们也能依据该标志暂时禁止处理此品种的 DOM。 利用以下方法设置标志,从而指示该品种需要处理 BookEvent 事件:

//+------------------------------------------------------------------+
//| Set the flag of using a series                                   |
//| of a specified symbol's DOM                                      |
//+------------------------------------------------------------------+
void CMBookSeriesCollection::SetAvailableMBookSeries(const string symbol,const bool flag=true)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return;
   bookseries.SetAvailable(flag);
  }
//+------------------------------------------------------------------+

此处,我们收到指定品种的 DOM 序列对象,并取传递给该方法的标志为其设置
默认标志值是 true

如果我们的程序用到多个品种,故而我们需要管理上面提到的 DOM 快照序列标志,那么一次性为程序中用到的所有品种定义标志值的方法可能会有所帮助:

//+------------------------------------------------------------------+
//|Set the flag of using the DOM series for all symbols              |
//+------------------------------------------------------------------+
void CMBookSeriesCollection::SetAvailableMBookSeries(const bool flag=true)
  {
   for(int i=0;i<this.m_list.Total();i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
         continue;
      bookseries.SetAvailable(flag);
     }
  }
//+------------------------------------------------------------------+

此处,按集合中 DOM 快照序列对象的总数循环获取下一个序列列表,并用传递给该方法的标志为其设置。 默认标志值是 true

与上述方法相反的方法则返回标志值,以便操控指定品种或所有品种的序列列表。

该方法返回正在处理的指定品种 DOM 序列的标志:

//+------------------------------------------------------------------+
//|Return the flag of using the DOM series of a specified symbol     |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::IsAvailableMBookSeries(const string symbol)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return false;
   return bookseries.IsAvailable();
  }
//+------------------------------------------------------------------+

此处,依据传递给方法的品种获取 DOM 快照的对象系列,然后返回为对象指定的标志值

该方法返回正在处理的所有品种 DOM 序列的标志:

//+------------------------------------------------------------------+
//| Return the flag of using the DOM series of all symbols           |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::IsAvailableMBookSeries(void)
  {
   bool res=true;
   int total=this.m_list.Total();
   for(int i=0;i<total;i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
         continue;
      res &=bookseries.IsAvailable();
     }
   return res;
  }
//+------------------------------------------------------------------+

仅当针对其 DOM 序列中的每个已用到品种均激活了该品种必须处理的指示标志时,该方法才返回 true。 此处,按照所有集合序列对象进行循环我们获得了下一个序列,并将序列标志值添加到变量。 如果至少一个品种的标志设置为 false,则该方法返回 false

该方法为指定品种的 DOM 历史记录设置快照数量:

//+------------------------------------------------------------------+
//| Set the number of snapshots in history                           |
//| of a specified symbol's DOM                                      |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::SetRequiredUsedDays(const string symbol,const uint required=0)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return false;
   bookseries.SetRequiredUsedDays(required);
   return true;
  }
//+------------------------------------------------------------------+


该方法用于限制每个品种的 DOM 快照总数,并避免在过时数据上花费额外的内存。 在此,我们获得指定品种的快照序列列表,并为其设置列表中快照的最大数量。 如果获取快照序列列表失败,则返回 false。 如果设置所需数字成功,则返回 true

该方法返回所有品种 DOM 历史记录中的快照数量:

//+------------------------------------------------------------------+
//|Set the number of snapshots in the DOM history of all symbols     |
//+------------------------------------------------------------------+
bool CMBookSeriesCollection::SetRequiredUsedDays(const uint required=0)
  {
   bool res=true;
   for(int i=0;i<this.m_list.Total();i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
        {
         res &=false;
         continue;
        }
      bookseries.SetRequiredUsedDays(required);
     }
   return res;
  }
//+------------------------------------------------------------------+

该方法可一次性为程序中用到的所有品种的 DOM 历史数据设置所需的相似数量。

按集合中序列对象的总数进行循环接收下一个 DOM 快照序列对象,并为其设置指定的数据量如果获取序列失败,则把结果设为 false。 因此,如果只要一个序列设置所需数量失败,则该方法返回 false。 直至循环完成,返回在 res 变量中获得的结果。

该方法按索引返回指定品种的 DOM 快照对象:

//+------------------------------------------------------------------+
//|Return the DOM snapshot object of a specified symbol by index     |
//+------------------------------------------------------------------+
CMBookSnapshot *CMBookSeriesCollection::GetMBook(const string symbol,const int index)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return NULL;
   return bookseries.GetMBookByListIndex(index);
  }
//+------------------------------------------------------------------+

此处,我们接收含有指定品种的 DOM 快照序列对象,并利用在上一篇文章中所述的 CMBookSeries 类的 GetMBookByListIndex() 方法按照指定索引返回 DOM 快照的指针

该方法按时间(以毫秒为单位)返回指定品种的 DOM 快照对象:

//+------------------------------------------------------------------+
//| Return the DOM snapshot object of a specified symbol             |
//| by time in milliseconds                                          |
//+------------------------------------------------------------------+
CMBookSnapshot *CMBookSeriesCollection::GetMBook(const string symbol,const long time_msc)
  {
   CMBookSeries *bookseries=this.GetMBookseries(symbol);
   if(bookseries==NULL)
      return NULL;
   return bookseries.GetMBook(time_msc);
  }
//+------------------------------------------------------------------+

此处,我们接收含有指定品种的 DOM 快照序列对象,并利用在上一篇文章中所述的 CMBookSeries 类的 GetMBook() 方法按照指定索引返回 DOM 快照的指针

该方法的独特之处在于,为了获得指向 DOM 快照对象的指针,我们需要知道其确切时间(以毫秒为单位)。

该方法在日志中显示 DOM 快照序列集合的完整描述:

//+------------------------------------------------------------------+
//| Display complete collection description to the journal           |
//+------------------------------------------------------------------+
void CMBookSeriesCollection::Print(void)
  {
   ::Print(CMessage::Text(MSG_MB_COLLECTION_TEXT_MBCOLLECTION),":");
   for(int i=0;i<this.m_list.Total();i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
         continue;
      bookseries.Print(true);
     }
  }
//+------------------------------------------------------------------+

首先,显示标题,然后在循环中获取集合里每个后续 DOM 序列对象,并显示其完整说明。 在快照序列对象的 Print() 方法中,我们要传递 true,以便在显示描述之前设置连字符。

该方法返回显示在日志里的集合列表简要:

//+------------------------------------------------------------------+
//| Display the short collection description in the journal          |
//+------------------------------------------------------------------+
void CMBookSeriesCollection::PrintShort(void)
  {
   ::Print(CMessage::Text(MSG_MB_COLLECTION_TEXT_MBCOLLECTION),":");
   for(int i=0;i<this.m_list.Total();i++)
     {
      CMBookSeries *bookseries=this.m_list.At(i);
      if(bookseries==NULL)
         continue;
      bookseries.PrintShort(true);
     }
  }
//+------------------------------------------------------------------+

该方法与上述方法相同,但显示 DOM 序列对象简述的方法除外。

我们来改进位于 \MQL5\Include\DoEasy\Engine.mqh 当中的 CEngine 函数库主对象。

将 DOM 快照序列集合类包含到文件之中:

//+------------------------------------------------------------------+
//|                                                       Engine.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 "Services\TimerCounter.mqh"
#include "Collections\HistoryCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\EventsCollection.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Collections\SymbolsCollection.mqh"
#include "Collections\ResourceCollection.mqh"
#include "Collections\TimeSeriesCollection.mqh"
#include "Collections\BuffersCollection.mqh"
#include "Collections\IndicatorsCollection.mqh"
#include "Collections\TickSeriesCollection.mqh"
#include "Collections\BookSeriesCollection.mqh"
#include "TradingControl.mqh"
//+------------------------------------------------------------------+

在类对象清单中,添加一个新对象 — DOM 快照序列集合类

//+------------------------------------------------------------------+
//| Library basis class                                              |
//+------------------------------------------------------------------+
class CEngine
  {
private:
   CHistoryCollection   m_history;                       // Collection of historical orders and deals
   CMarketCollection    m_market;                        // Collection of market orders and deals
   CEventsCollection    m_events;                        // Event collection
   CAccountsCollection  m_accounts;                      // Account collection
   CSymbolsCollection   m_symbols;                       // Symbol collection
   CTimeSeriesCollection m_time_series;                  // Timeseries collection
   CBuffersCollection   m_buffers;                       // Collection of indicator buffers
   CIndicatorsCollection m_indicators;                   // Indicator collection
   CTickSeriesCollection m_tick_series;                  // Collection of tick series
   CMBookSeriesCollection m_book_series;                 // Collection of DOM series
   CResourceCollection  m_resource;                      // Resource list
   CTradingControl      m_trading;                       // Trading management object
   CPause               m_pause;                         // Pause object
   CArrayObj            m_list_counters;                 // List of timer counters
   int                  m_global_error;                  // Global error code
   bool                 m_first_start;                   // First launch flag
   bool                 m_is_hedge;                      // Hedge account flag
   bool                 m_is_tester;                     // Flag of working in the tester
   bool                 m_is_market_trade_event;         // Account trading event flag
   bool                 m_is_history_trade_event;        // Account history trading event flag
   bool                 m_is_account_event;              // Account change event flag
   bool                 m_is_symbol_event;               // Symbol change event flag
   ENUM_TRADE_EVENT     m_last_trade_event;              // Last account trading event
   int                  m_last_account_event;            // Last event in the account properties
   int                  m_last_symbol_event;             // Last event in the symbol properties
   ENUM_PROGRAM_TYPE    m_program;                       // Program type
   string               m_name;                          // Program name

添加新的 BookEvent 事件处理程序。 在为品种集合设置用到的品种列表的方法中,不光传递即时报价序列的天数还要附加传递 DOM 快照最大数量

//--- (1) Timer, event handler (2) NewTick, (3) Calculate, (4) BookEvent, (4) Deinit
   void                 OnTimer(SDataCalculate &data_calculate);
   void                 OnTick(SDataCalculate &data_calculate,const uint required=0);
   int                  OnCalculate(SDataCalculate &data_calculate,const uint required=0);
   bool                 OnBookEvent(const string &symbol);
   void                 OnDeinit(void);
   
//--- Set the list of used symbols in the symbol collection and create the collection of symbol timeseries
   bool                 SetUsedSymbols(const string &array_symbols[],const uint required_ticks=0,const uint required_books=0);

在操控即时报价序列集合的方法清单中,添加简化即时报价序列集合操控的新方法,并编写操控 DOM 序列集合的方法

//--- Return (1) the tick series collection, (2) the list of tick series from the tick series collection
   CTickSeriesCollection *GetTickSeriesCollection(void)                                { return &this.m_tick_series;                                  }
   CArrayObj           *GetListTickSeries(void)                                        { return this.m_tick_series.GetList();                         }

//--- Create (1) a specified tick series and (2) all tick series
   bool                 TickSeriesCreate(const string symbol,const uint required=0)    { return this.m_tick_series.CreateTickSeries(symbol,required); }
   bool                 TickSeriesCreateAll(const uint required=0)                     { return this.m_tick_series.CreateTickSeriesAll(required);     }

//--- Update (1) a tick series of a specified symbol, (2) all symbols and (3) all symbols except the current one
   void                 TickSeriesRefresh(const string symbol)                         { this.m_tick_series.Refresh(symbol);                          }
   void                 TickSeriesRefreshAll(void)                                     { this.m_tick_series.Refresh();                                }
   void                 TickSeriesRefreshAllExceptCurrent(void)                        { this.m_tick_series.RefreshExpectCurrent();                   }

//--- Return (1) the DOM series collection and (2) the list of DOM series from the DOM series collection
   CMBookSeriesCollection *GetMBookSeriesCollection(void)                              { return &this.m_book_series;                         }
   CArrayObj           *GetListMBookSeries(void)                                       { return this.m_book_series.GetList();                }

//--- Update the DOM series of a specified symbol
   void                 MBookSeriesRefresh(const string symbol,const long time_msc)    { this.m_book_series.Refresh(symbol,time_msc);        }

//--- Return the DOM series of a specified symbol
   CMBookSeries        *GetMBookSeries(const string symbol)                            { return this.m_book_series.GetMBookseries(symbol);   }

所有这些方法简单地调用相应集合的同名方法。

在类主体之外实现函数库的 OnBookEvent() 处理程序:

//+------------------------------------------------------------------+
//| BookEvent event handler                                          |
//+------------------------------------------------------------------+
bool CEngine::OnBookEvent(const string &symbol)
  {
   CSymbol *sym=this.m_symbols.GetSymbolObjByName(symbol);
   if(sym==NULL || !sym.BookdepthSubscription())
      return false;
   return this.m_book_series.Refresh(sym.Name(),sym.Time());
  }
//+------------------------------------------------------------------+

鉴于 OnBookEvent() 处理程序总是在 DOM 变改事件期间由单个品种激活,因此我们可在处理程序自身内部定义品种。
该方法接收发生 DOM 变更事件的品种名称。 接下来,我们从品种集合类中接收相应的品种对象,并返回 DOM 快照相应序列的更新结果。 此外,我们在新创建 DOM 快照的 Refresh() 方法里指定需设置的时间(以毫秒为单位)。

我们来改进设置品种集合中已用到品种列表的方法:

//+------------------------------------------------------------------+
//| Set the list of used symbols in the symbol collection            |
//| and create the collections of timeseries, tick series            |
//| and symbol DOM series                                            |
//+------------------------------------------------------------------+
bool CEngine::SetUsedSymbols(const string &array_symbols[],const uint required_ticks=0,const uint required_books=0)
  {
   bool res=this.m_symbols.SetUsedSymbols(array_symbols);
   CArrayObj *list=this.GetListAllUsedSymbols();
   if(list==NULL)
      return false;
   res&=this.m_time_series.CreateCollection(list);
   res&=this.m_tick_series.CreateCollection(list,required_ticks);
   res&=this.m_book_series.CreateCollection(list,required_books);
   return res;
  }
//+------------------------------------------------------------------+

现在,该方法会接收即时报价序列的天数,和序列中 DOM 快照的最大数量
在此,我们添加了为所有品种创建 DOM 快照序列集合

到此,操控 DOM 序列类的改进完毕。
将来,我可能会返回该主题进行更深入的改进,但现在,我们去处理其他必要的函数库功能。

MQL5.com 信号服务是一项交易跟单服务,可令您在自己的交易帐户上自动复制提供者的交易。
在此,MQL5 信号对象是交易帐户,该帐户交易操作受到监视并公开传输 — 作为信号源。
信号源拥有其自己的参数,可利用 SignalBaseGetInteger(),SignalBaseGetDouble() 和 SignalBaseGetString() 函数获得。 此外,还有订阅参数 — 特定帐户的信号复制。 这些参数可利用 SignalInfoGetDouble(),SignalInfoGetInteger() 和 SignalInfoGetString() 函数获得。

MQL5 信号对象用来描述终端中可供订阅的一个信号源。 一个帐户仅能订阅一个信号,但我们仍然可以得到所有可供订阅的信号(MQL5 信号对象)的完整列表,并能够按任何属性对其进行排序、比较和订阅选定的信号。 对于愿意从 MQL5.com 信号服务中受益的用户来说,这是非常便利和有用的功能。

MQL5 信号对象类

在 \MQL5\Include\DoEasy\Defines.mqh 里,加入 MQL5 对象的整数型实数型字符串型属性枚举:

//+------------------------------------------------------------------+
//| Data for working with MQL5.com signals                           |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| The list of possible signal events                               |
//+------------------------------------------------------------------+
#define SIGNAL_MQL5_EVENTS_NEXT_CODE  (MBOOK_ORD_EVENTS_NEXT_CODE+1)   // The code of the next event after the last signal event code
//+------------------------------------------------------------------+
//| MQL5 signal integer properties                                   |
//+------------------------------------------------------------------+
enum ENUM_SIGNAL_MQL5_PROP_INTEGER
  {
   SIGNAL_MQL5_PROP_TRADE_MODE = 0,                   // Account type
   SIGNAL_MQL5_PROP_DATE_PUBLISHED,                   // Signal publication date 
   SIGNAL_MQL5_PROP_DATE_STARTED,                     // Start date of signal monitoring
   SIGNAL_MQL5_PROP_DATE_UPDATED,                     // Date of the latest update of the signal trading statistics
   SIGNAL_MQL5_PROP_ID,                               // Signal ID
   SIGNAL_MQL5_PROP_LEVERAGE,                         // Trading account leverage
   SIGNAL_MQL5_PROP_PIPS,                             // Trading result in pips
   SIGNAL_MQL5_PROP_RATING,                           // Position in the signal rating
   SIGNAL_MQL5_PROP_SUBSCRIBERS,                      // Number of subscribers
   SIGNAL_MQL5_PROP_TRADES,                           // Number of trades
   SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS,              // Status of account subscription to a signal
  };
#define SIGNAL_MQL5_PROP_INTEGER_TOTAL (11)           // Total number of integer properties
#define SIGNAL_MQL5_PROP_INTEGER_SKIP  (0)            // Number of integer DOM properties not used in sorting
//+------------------------------------------------------------------+
//| MQL5 signal real properties                                      |
//+------------------------------------------------------------------+
enum ENUM_SIGNAL_MQL5_PROP_DOUBLE
  {
   SIGNAL_MQL5_PROP_BALANCE = SIGNAL_MQL5_PROP_INTEGER_TOTAL, // Account balance
   SIGNAL_MQL5_PROP_EQUITY,                           // Account equity
   SIGNAL_MQL5_PROP_GAIN,                             // Account growth in %
   SIGNAL_MQL5_PROP_MAX_DRAWDOWN,                     // Maximum drawdown
   SIGNAL_MQL5_PROP_PRICE,                            // Signal subscription price
   SIGNAL_MQL5_PROP_ROI,                              // Signal's ROI (Return on Investment) in %
  };
#define SIGNAL_MQL5_PROP_DOUBLE_TOTAL  (6)            // Total number of real properties
#define SIGNAL_MQL5_PROP_DOUBLE_SKIP   (0)            // Number of real properties not used in sorting
//+------------------------------------------------------------------+
//| MQL5 signal string properties                                    |
//+------------------------------------------------------------------+
enum ENUM_SIGNAL_MQL5_PROP_STRING
  {
   SIGNAL_MQL5_PROP_AUTHOR_LOGIN = (SIGNAL_MQL5_PROP_INTEGER_TOTAL+SIGNAL_MQL5_PROP_DOUBLE_TOTAL), // Signal author's login
   SIGNAL_MQL5_PROP_BROKER,                           // Broker (company) name
   SIGNAL_MQL5_PROP_BROKER_SERVER,                    // Broker server
   SIGNAL_MQL5_PROP_NAME,                             // Signal name
   SIGNAL_MQL5_PROP_CURRENCY,                         // Signal account currency
  };
#define SIGNAL_MQL5_PROP_STRING_TOTAL  (5)            // Total number of string properties
//+------------------------------------------------------------------+

我并不打算引入可能的 mql5 信号事件的列表。 代之,我只会引入一个常量,该常量指定 MQL5 信号事件代码之后的下一个事件的代码。 我很可能会进一步修改这一点。

为了能够按 MQL5 信号的属性进行搜索和排序,定义所有可能的排序标准枚举

//+------------------------------------------------------------------+
//| Possible sorting criteria of MQL5 signals                        |
//+------------------------------------------------------------------+
#define FIRST_SIGNAL_MQL5_DBL_PROP  (SIGNAL_MQL5_PROP_INTEGER_TOTAL-SIGNAL_MQL5_PROP_INTEGER_SKIP)
#define FIRST_SIGNAL_MQL5_STR_PROP  (SIGNAL_MQL5_PROP_INTEGER_TOTAL-SIGNAL_MQL5_PROP_INTEGER_SKIP+SIGNAL_MQL5_PROP_DOUBLE_TOTAL-SIGNAL_MQL5_PROP_DOUBLE_SKIP)
enum ENUM_SORT_SIGNAL_MQL5_MODE
  {
//--- Sort by integer properties
   SORT_BY_SIGNAL_MQL5_TRADE_MODE = 0,                // Sort by signal type
   SORT_BY_SIGNAL_MQL5_DATE_PUBLISHED,                // Sort by signal publication date 
   SORT_BY_SIGNAL_MQL5_DATE_STARTED,                  // Sort by signal monitoring start date
   SORT_BY_SIGNAL_MQL5_DATE_UPDATED,                  // Sort by date of the latest update of the signal trading statistics
   SORT_BY_SIGNAL_MQL5_ID,                            // Sort by signal ID
   SORT_BY_SIGNAL_MQL5_LEVERAGE,                      // Sort by trading account leverage
   SORT_BY_SIGNAL_MQL5_PIPS,                          // Sort by trading result in pips
   SORT_BY_SIGNAL_MQL5_RATING,                        // Sort by a position in the signal rating
   SORT_BY_SIGNAL_MQL5_SUBSCRIBERS,                   // Sort by the number of subscribers
   SORT_BY_SIGNAL_MQL5_TRADES,                        // Sort by the number of trades
   SORT_BY_SIGNAL_MQL5_SUBSCRIPTION_STATUS,           // Sort by the status of account subscription to a signal
//--- Sort by real properties
   SORT_BY_SIGNAL_MQL5_BALANCE = FIRST_SIGNAL_MQL5_DBL_PROP, // Sort by account balance
   SORT_BY_SIGNAL_MQL5_EQUITY,                        // Sort by account equity
   SORT_BY_SIGNAL_MQL5_GAIN,                          // Sort by account growth in %
   SORT_BY_SIGNAL_MQL5_MAX_DRAWDOWN,                  // Sort by maximum drawdown
   SORT_BY_SIGNAL_MQL5_PRICE,                         // Sort by signal subscription price
   SORT_BY_SIGNAL_MQL5_ROI,                           // Sort by ROI
//--- Sort by string properties
   SORT_BY_SIGNAL_MQL5_AUTHOR_LOGIN = FIRST_SIGNAL_MQL5_STR_PROP, // Sort by signal author login
   SORT_BY_SIGNAL_MQL5_BROKER,                        // Sort by Broker (company) name
   SORT_BY_SIGNAL_MQL5_BROKER_SERVER,                 // Sort by broker server
   SORT_BY_SIGNAL_MQL5_NAME,                          // Sort by signal name
   SORT_BY_SIGNAL_MQL5_CURRENCY,                      // Sort by signal account currency
  };
//+------------------------------------------------------------------+

这是为新函数库对象创建新类的一套必要参数。

在 \MQL5\Include\DoEasy\Objects\ 里,创建一个新的文件夹 MQLSignalBase\,并新增一个含有 CMQLSignal 类的文件 MQLSignal.mqh

所有 CBaseObj 库对象的基准对象类都应作为基类:

//+------------------------------------------------------------------+
//|                                                    MQLSignal.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 "..\..\Objects\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Abstract MQL5 signal class                                       |
//+------------------------------------------------------------------+
class CMQLSignal : public CBaseObj
  {
  }

我们来研究一下类的组成,及其方法的实现:

//+------------------------------------------------------------------+
//|                                                    MQLSignal.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 "..\..\Objects\BaseObj.mqh"
//+------------------------------------------------------------------+
//| Abstract MQL5 signal class                                       |
//+------------------------------------------------------------------+
class CMQLSignal : public CBaseObj
  {
private:
   long              m_long_prop[SIGNAL_MQL5_PROP_INTEGER_TOTAL];       // Integer properties
   double            m_double_prop[SIGNAL_MQL5_PROP_DOUBLE_TOTAL];      // Real properties
   string            m_string_prop[SIGNAL_MQL5_PROP_STRING_TOTAL];      // String properties

//--- Return the index of the array the (1) double and (2) string properties are actually located at
   int               IndexProp(ENUM_SIGNAL_MQL5_PROP_DOUBLE property)   const { return(int)property-SIGNAL_MQL5_PROP_INTEGER_TOTAL;                               }
   int               IndexProp(ENUM_SIGNAL_MQL5_PROP_STRING property)   const { return(int)property-SIGNAL_MQL5_PROP_INTEGER_TOTAL-SIGNAL_MQL5_PROP_DOUBLE_TOTAL; }

public:
//--- Set object's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_SIGNAL_MQL5_PROP_INTEGER property,long value)    { this.m_long_prop[property]=value;                      }
   void              SetProperty(ENUM_SIGNAL_MQL5_PROP_DOUBLE property,double value)   { this.m_double_prop[this.IndexProp(property)]=value;    }
   void              SetProperty(ENUM_SIGNAL_MQL5_PROP_STRING property,string value)   { this.m_string_prop[this.IndexProp(property)]=value;    }
//--- Return object’s (1) integer, (2) real and (3) string property from the properties array
   long              GetProperty(ENUM_SIGNAL_MQL5_PROP_INTEGER property)         const { return this.m_long_prop[property];                     }
   double            GetProperty(ENUM_SIGNAL_MQL5_PROP_DOUBLE property)          const { return this.m_double_prop[this.IndexProp(property)];   }
   string            GetProperty(ENUM_SIGNAL_MQL5_PROP_STRING property)          const { return this.m_string_prop[this.IndexProp(property)];   }
//--- Return itself
   CMQLSignal       *GetObject(void)                                                   { return &this;}

//--- Return the flag of the object supporting this property
   virtual bool      SupportProperty(ENUM_SIGNAL_MQL5_PROP_INTEGER property)           { return true; }
   virtual bool      SupportProperty(ENUM_SIGNAL_MQL5_PROP_DOUBLE property)            { return true; }
   virtual bool      SupportProperty(ENUM_SIGNAL_MQL5_PROP_STRING property)            { return true; }

//--- Get description of (1) integer, (2) real and (3) string properties
   string            GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_STRING property);

//--- Display the description of object properties in the journal (full_prop=true - all properties, false - supported ones only)
   void              Print(const bool full_prop=false);
//--- Display a short description of the object in the journal
   virtual void      PrintShort(void);
//--- Return the object short name
   virtual string    Header(const bool shrt=false);
   
//--- Compare CMQLSignal objects by a specified property (to sort the list by an MQL5 signal object)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CMQLSignal objects by all properties (to search for equal MQL5 signal objects)
   bool              IsEqual(CMQLSignal* compared_obj) const;
   
//--- Constructors
                     CMQLSignal(){;}
                     CMQLSignal(const long signal_id);
                     
public:
//+------------------------------------------------------------------+ 
//| Methods of simplified access to MQL5 signal object               |
//+------------------------------------------------------------------+
//--- Returns the dates of (1) publication, (2) monitoring start, (3) trading statistics last update,
//--- (4) ID, (5) trading account leverage, (6) trading result in pips, (7) position in the signal rating,
//--- (8) number of subscribers, (9) number of trades, (10) account type, (11) flag of the current account subscription to a signal
   datetime          DatePublished(void)     const { return (datetime)this.GetProperty(SIGNAL_MQL5_PROP_DATE_PUBLISHED);         }
   datetime          DateStarted(void)       const { return (datetime)this.GetProperty(SIGNAL_MQL5_PROP_DATE_STARTED);           }
   datetime          DateUpdated(void)       const { return (datetime)this.GetProperty(SIGNAL_MQL5_PROP_DATE_UPDATED);           }
   long              ID(void)                const { return this.GetProperty(SIGNAL_MQL5_PROP_ID);                               }
   long              Leverage(void)          const { return this.GetProperty(SIGNAL_MQL5_PROP_LEVERAGE);                         }
   long              Pips(void)              const { return this.GetProperty(SIGNAL_MQL5_PROP_PIPS);                             }
   long              Rating(void)            const { return this.GetProperty(SIGNAL_MQL5_PROP_RATING);                           }
   long              Subscribers(void)       const { return this.GetProperty(SIGNAL_MQL5_PROP_SUBSCRIBERS);                      }
   long              Trades(void)            const { return this.GetProperty(SIGNAL_MQL5_PROP_TRADES);                           }
   long              TradeMode(void)         const { return (long)this.GetProperty(SIGNAL_MQL5_PROP_TRADE_MODE);                 }
   bool              SubscriptionStatus(void)const { return (bool)this.GetProperty(SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS);        }
//--- Return (1) the account balance, (2) account funds, (3) account growth in %,
//--- (4) maximum drawdown, (5) subscription price and (6) signal ROI value (Return on Investment) in %
   double            Balance(void)           const { return this.GetProperty(SIGNAL_MQL5_PROP_BALANCE);                          }
   double            Equity(void)            const { return this.GetProperty(SIGNAL_MQL5_PROP_EQUITY);                           }
   double            Gain(void)              const { return this.GetProperty(SIGNAL_MQL5_PROP_GAIN);                             }
   double            MaxDrawdown(void)       const { return this.GetProperty(SIGNAL_MQL5_PROP_MAX_DRAWDOWN);                     }
   double            Price(void)             const { return this.GetProperty(SIGNAL_MQL5_PROP_PRICE);                            }
   double            ROI(void)               const { return this.GetProperty(SIGNAL_MQL5_PROP_ROI);                              }
//--- Return (1) signal author's login, (2) broker (company) name,
//--- (3) broker server, (4) signal name and (5) signal account currency
   string            AuthorLogin(void)       const { return this.GetProperty(SIGNAL_MQL5_PROP_AUTHOR_LOGIN);                     }
   string            Broker(void)            const { return this.GetProperty(SIGNAL_MQL5_PROP_BROKER);                           }
   string            BrokerServer(void)      const { return this.GetProperty(SIGNAL_MQL5_PROP_BROKER_SERVER);                    }
   string            Name(void)              const { return this.GetProperty(SIGNAL_MQL5_PROP_NAME);                             }
   string            Currency(void)          const { return this.GetProperty(SIGNAL_MQL5_PROP_CURRENCY);                         }

//--- Set the dates of (1) publication, (2) monitoring start, (3) trading statistics last update,
//--- (4) ID, (5) trading account leverage, (6) trading result in pips, (7) position in the signal rating,
//--- (8) number of subscribers, (9) number of trades, (10) account type, (11) flag of the current account subscription to a signal
   void              SetDatePublished(const datetime date)  { this.SetProperty(SIGNAL_MQL5_PROP_DATE_PUBLISHED,date);            }
   void              SetDateStarted(const datetime date)    { this.SetProperty(SIGNAL_MQL5_PROP_DATE_STARTED,date);              }
   void              SetDateUpdated(const datetime date)    { this.SetProperty(SIGNAL_MQL5_PROP_DATE_UPDATED,date);              }
   void              SetID(const long id)                   { this.SetProperty(SIGNAL_MQL5_PROP_ID,id);                          }
   void              SetLeverage(const long value)          { this.SetProperty(SIGNAL_MQL5_PROP_LEVERAGE,value);                 }
   void              SetPips(const long value)              { this.SetProperty(SIGNAL_MQL5_PROP_PIPS,value);                     }
   void              SetRating(const long value)            { this.SetProperty(SIGNAL_MQL5_PROP_RATING,value);                   }
   void              SetSubscribers(const long value)       { this.SetProperty(SIGNAL_MQL5_PROP_SUBSCRIBERS,value);              }
   void              SetTrades(const long value)            { this.SetProperty(SIGNAL_MQL5_PROP_TRADES,value);                   }
   void              SetTradeMode(const long mode)          { this.SetProperty(SIGNAL_MQL5_PROP_TRADE_MODE,mode);                }
   void              SetSubscriptionStatus(const bool flag) { this.SetProperty(SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS,flag);       }
//--- Set (1) the account balance, (2) account funds, (3) account growth in %,
//--- (4) maximum drawdown, (5) subscription price and (6) signal ROI value (Return on Investment) in %
   void              SetBalance(const double value)         { this.SetProperty(SIGNAL_MQL5_PROP_BALANCE,value);                  }
   void              SetEquity(const double value)          { this.SetProperty(SIGNAL_MQL5_PROP_EQUITY,value);                   }
   void              SetGain(const double value)            { this.SetProperty(SIGNAL_MQL5_PROP_GAIN,value);                     }
   void              SetMaxDrawdown(const double value)     { this.SetProperty(SIGNAL_MQL5_PROP_MAX_DRAWDOWN,value);             }
   void              SetPrice(const double value)           { this.SetProperty(SIGNAL_MQL5_PROP_PRICE,value);                    }
   void              SetROI(const double value)             { this.SetProperty(SIGNAL_MQL5_PROP_ROI,value);                      }
//--- Set (1) signal author's login, (2) broker (company) name,
//--- (3) broker server, (4) signal name and (5) signal account currency
   void              SetAuthorLogin(const string value)     { this.SetProperty(SIGNAL_MQL5_PROP_AUTHOR_LOGIN,value);             }
   void              SetBroker(const string value)          { this.SetProperty(SIGNAL_MQL5_PROP_BROKER,value);                   }
   void              SetBrokerServer(const string value)    { this.SetProperty(SIGNAL_MQL5_PROP_BROKER_SERVER,value);            }
   void              SetName(const string value)            { this.SetProperty(SIGNAL_MQL5_PROP_NAME,value);                     }
   void              SetCurrency(const string value)        { this.SetProperty(SIGNAL_MQL5_PROP_CURRENCY,value);                 }

//--- Return the account type name
   string            TradeModeDescription(void);
   
  };
//+------------------------------------------------------------------+

在私密部分中声明存储整数型、实数型和字符串型对象属性的数组,以及返回对象的实数型和字符串型属性索引的方法。

在类的公开部分,我们可以看到设置和接收对象属性、搜索和排序、显示对象描述和类构造函数的标准方法。

公开部分里还含有简化访问对象属性的方法 — 这些方法具有不言自明的名称,如此函数库用户即可访问任何属性而无需记住所有对象枚举的名称。

The composition of the object classes was considered in details in the first part of the library description. 我们来看一下类方法的实现。

参数类构造函数接收信号 ID。 然后,所有对象属性都用从相应函数获得的值(考虑到该信号已被选择)来填充:

//+------------------------------------------------------------------+
//| Parametric constructor                                           |
//+------------------------------------------------------------------+
CMQLSignal::CMQLSignal(const long signal_id)
  {
   this.m_long_prop[SIGNAL_MQL5_PROP_ID]                             = signal_id;
   this.m_long_prop[SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS]            = false;
   this.m_long_prop[SIGNAL_MQL5_PROP_TRADE_MODE]                     = ::SignalBaseGetInteger(SIGNAL_BASE_TRADE_MODE);
   this.m_long_prop[SIGNAL_MQL5_PROP_DATE_PUBLISHED]                 = ::SignalBaseGetInteger(SIGNAL_BASE_DATE_PUBLISHED);
   this.m_long_prop[SIGNAL_MQL5_PROP_DATE_STARTED]                   = ::SignalBaseGetInteger(SIGNAL_BASE_DATE_STARTED);
   this.m_long_prop[SIGNAL_MQL5_PROP_DATE_UPDATED]                   = ::SignalBaseGetInteger(SIGNAL_BASE_DATE_UPDATED);
   this.m_long_prop[SIGNAL_MQL5_PROP_LEVERAGE]                       = ::SignalBaseGetInteger(SIGNAL_BASE_LEVERAGE);
   this.m_long_prop[SIGNAL_MQL5_PROP_PIPS]                           = ::SignalBaseGetInteger(SIGNAL_BASE_PIPS);
   this.m_long_prop[SIGNAL_MQL5_PROP_RATING]                         = ::SignalBaseGetInteger(SIGNAL_BASE_RATING);
   this.m_long_prop[SIGNAL_MQL5_PROP_SUBSCRIBERS]                    = ::SignalBaseGetInteger(SIGNAL_BASE_SUBSCRIBERS);
   this.m_long_prop[SIGNAL_MQL5_PROP_TRADES]                         = ::SignalBaseGetInteger(SIGNAL_BASE_TRADES);
   
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_BALANCE)]      = ::SignalBaseGetDouble(SIGNAL_BASE_BALANCE);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_EQUITY)]       = ::SignalBaseGetDouble(SIGNAL_BASE_EQUITY);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_GAIN)]         = ::SignalBaseGetDouble(SIGNAL_BASE_GAIN);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_MAX_DRAWDOWN)] = ::SignalBaseGetDouble(SIGNAL_BASE_MAX_DRAWDOWN);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_PRICE)]        = ::SignalBaseGetDouble(SIGNAL_BASE_PRICE);
   this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_ROI)]          = ::SignalBaseGetDouble(SIGNAL_BASE_ROI);
   
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_AUTHOR_LOGIN)] = ::SignalBaseGetString(SIGNAL_BASE_AUTHOR_LOGIN);
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_BROKER)]       = ::SignalBaseGetString(SIGNAL_BASE_BROKER);
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_BROKER_SERVER)]= ::SignalBaseGetString(SIGNAL_BASE_BROKER_SERVER);
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_NAME)]         = ::SignalBaseGetString(SIGNAL_BASE_NAME);
   this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_CURRENCY)]     = ::SignalBaseGetString(SIGNAL_BASE_CURRENCY);
  }
//+------------------------------------------------------------------+

信号订阅标志设置为 false — 所选信号的订阅是从另一个类执行的。

按照指定属性比较 MQL5 信号对象的方法:

//+----------------------------------------------------------------------+
//| Compare CMQLSignal objects with each other by the specified property |
//+----------------------------------------------------------------------+
int CMQLSignal::Compare(const CObject *node,const int mode=0) const
  {
   const CMQLSignal *obj_compared=node;
//--- compare integer properties of two objects
   if(mode<SIGNAL_MQL5_PROP_INTEGER_TOTAL)
     {
      long value_compared=obj_compared.GetProperty((ENUM_SIGNAL_MQL5_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_SIGNAL_MQL5_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare real properties of two objects
   else if(mode<SIGNAL_MQL5_PROP_DOUBLE_TOTAL+SIGNAL_MQL5_PROP_INTEGER_TOTAL)
     {
      double value_compared=obj_compared.GetProperty((ENUM_SIGNAL_MQL5_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_SIGNAL_MQL5_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- compare string properties of two objects
   else if(mode<SIGNAL_MQL5_PROP_DOUBLE_TOTAL+SIGNAL_MQL5_PROP_INTEGER_TOTAL+SIGNAL_MQL5_PROP_STRING_TOTAL)
     {
      string value_compared=obj_compared.GetProperty((ENUM_SIGNAL_MQL5_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_SIGNAL_MQL5_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+

简而言之,该方法接收需比较的对象,以及两个对象需比较的属性。 根据所传递的属性,比较两个对象的整数型、实数型或字符串型属性。 返回的比较结果为 -1、1 或 0(小于、大于、等于)。

比较 MQL5 信号对象所有属性的方法:

//+------------------------------------------------------------------+
//| Compare CMQLSignal objects by all properties                     |
//+------------------------------------------------------------------+
bool CMQLSignal::IsEqual(CMQLSignal *compared_obj) const
  {
   int beg=0, end=SIGNAL_MQL5_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_INTEGER prop=(ENUM_SIGNAL_MQL5_PROP_INTEGER)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=SIGNAL_MQL5_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_DOUBLE prop=(ENUM_SIGNAL_MQL5_PROP_DOUBLE)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   beg=end; end+=SIGNAL_MQL5_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_STRING prop=(ENUM_SIGNAL_MQL5_PROP_STRING)i;
      if(this.GetProperty(prop)!=compared_obj.GetProperty(prop)) return false; 
     }
   return true;
  }
//+------------------------------------------------------------------+

依据三个对象属性的三重循环中,比较两个对象的每个后续属性,如果两个对象的属性不相等,则返回 false。 两个对象在三个数组中的所有属性经过比较后,如果未发现不相等的属性,则返回 true

返回指定的整数型实数型字符串型对象属性描述的方法:

//+------------------------------------------------------------------+
//| Return description of object's integer property                  |
//+------------------------------------------------------------------+
string CMQLSignal::GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_INTEGER property)
  {
   return
     (
      property==SIGNAL_MQL5_PROP_TRADE_MODE     ?  CMessage::Text(MSG_SIGNAL_MQL5_TRADE_MODE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.TradeModeDescription()
         )  :
      property==SIGNAL_MQL5_PROP_DATE_PUBLISHED ?  CMessage::Text(MSG_SIGNAL_MQL5_DATE_PUBLISHED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.DatePublished())
         )  :
      property==SIGNAL_MQL5_PROP_DATE_STARTED   ?  CMessage::Text(MSG_SIGNAL_MQL5_DATE_STARTED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.DateStarted())
         )  :
      property==SIGNAL_MQL5_PROP_DATE_UPDATED   ?  CMessage::Text(MSG_SIGNAL_MQL5_DATE_UPDATED)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::TimeToString(this.DateUpdated())
         )  :
      property==SIGNAL_MQL5_PROP_ID             ?  CMessage::Text(MSG_SIGNAL_MQL5_ID)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_LEVERAGE       ?  CMessage::Text(MSG_SIGNAL_MQL5_LEVERAGE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_PIPS           ?  CMessage::Text(MSG_SIGNAL_MQL5_PIPS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_RATING         ?  CMessage::Text(MSG_SIGNAL_MQL5_RATING)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_SUBSCRIBERS    ?  CMessage::Text(MSG_SIGNAL_MQL5_SUBSCRIBERS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_TRADES        ?  CMessage::Text(MSG_SIGNAL_MQL5_TRADES)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS  ?  CMessage::Text(MSG_SIGNAL_MQL5_SUBSCRIPTION_STATUS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO))
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of object's real property                     |
//+------------------------------------------------------------------+
string CMQLSignal::GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_DOUBLE property)
  {
   return
     (
      property==SIGNAL_MQL5_PROP_BALANCE         ?  CMessage::Text(MSG_ACC_PROP_BALANCE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==SIGNAL_MQL5_PROP_EQUITY   ?  CMessage::Text(MSG_SIGNAL_MQL5_EQUITY)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
         
      property==SIGNAL_MQL5_PROP_GAIN   ?  CMessage::Text(MSG_SIGNAL_MQL5_GAIN)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==SIGNAL_MQL5_PROP_MAX_DRAWDOWN   ?  CMessage::Text(MSG_SIGNAL_MQL5_MAX_DRAWDOWN)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==SIGNAL_MQL5_PROP_PRICE   ?  CMessage::Text(MSG_SIGNAL_MQL5_PRICE)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      property==SIGNAL_MQL5_PROP_ROI   ?  CMessage::Text(MSG_SIGNAL_MQL5_ROI)+
         (!this.SupportProperty(property)    ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+::DoubleToString(this.GetProperty(property),2)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Return description of object's string property                   |
//+------------------------------------------------------------------+
string CMQLSignal::GetPropertyDescription(ENUM_SIGNAL_MQL5_PROP_STRING property)
  {
   return
     (
      property==SIGNAL_MQL5_PROP_AUTHOR_LOGIN   ?  CMessage::Text(MSG_SIGNAL_MQL5_AUTHOR_LOGIN)+": \""+this.GetProperty(property)+"\""    :
      property==SIGNAL_MQL5_PROP_BROKER         ?  CMessage::Text(MSG_SIGNAL_MQL5_BROKER)+": \""+this.GetProperty(property)+"\""          :
      property==SIGNAL_MQL5_PROP_BROKER_SERVER  ?  CMessage::Text(MSG_SIGNAL_MQL5_BROKER_SERVER)+": \""+this.GetProperty(property)+"\""   :
      property==SIGNAL_MQL5_PROP_NAME           ?  CMessage::Text(MSG_SIGNAL_MQL5_NAME)+": \""+this.GetProperty(property)+"\""            :
      property==SIGNAL_MQL5_PROP_CURRENCY       ?  CMessage::Text(MSG_SIGNAL_MQL5_CURRENCY)+": \""+this.GetProperty(property)+"\""        :
      ""
     );
  }
//+------------------------------------------------------------------+

根据传递给该方法的属性,创建并返回带有其描述和值的字符串。

在日志中显示所有 MQL5 信号对象属性的方法:

//+------------------------------------------------------------------+
//| Display object properties in the journal                         |
//+------------------------------------------------------------------+
void CMQLSignal::Print(const bool full_prop=false)
  {
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") =============");
   int beg=0, end=SIGNAL_MQL5_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_INTEGER prop=(ENUM_SIGNAL_MQL5_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=SIGNAL_MQL5_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_DOUBLE prop=(ENUM_SIGNAL_MQL5_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=SIGNAL_MQL5_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SIGNAL_MQL5_PROP_STRING prop=(ENUM_SIGNAL_MQL5_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," (",this.Header(),") =============\n");
  }
//+------------------------------------------------------------------+

利用相应的 GetPropertyDescription() 方法,依据整数型、实数型和字符串型属性在三重循环里显示每个后续对象属性的描述。

该方法返回 MQL5 信号对象的简称:

//+------------------------------------------------------------------+
//| Return the object short name                                     |
//+------------------------------------------------------------------+
string CMQLSignal::Header(const bool shrt=false)
  {
   return(shrt ? CMessage::Text(MSG_SIGNAL_MQL5_TEXT_SIGNAL) : CMessage::Text(MSG_SIGNAL_MQL5_TEXT_SIGNAL_MQL5));
  }
//+------------------------------------------------------------------+

该方法接收标志,指定简短长篇说明。 默认情况下显示长篇说明:

MQL5.com 信号服务的信号

如果标志是 true,则显示简短说明:

Signal

该方法在日志中显示对象简述:

//+------------------------------------------------------------------+
//| Display a short description of the object in the journal         |
//+------------------------------------------------------------------+
void CMQLSignal::PrintShort(void)
  {
   ::Print
     (
      this.Header(true),
      " \"",this.Name(),"\". ",
      CMessage::Text(MSG_SIGNAL_MQL5_AUTHOR_LOGIN),": ",this.AuthorLogin(),
      ", ID ",this.ID(),
      ", ",CMessage::Text(MSG_SIGNAL_MQL5_TEXT_GAIN),": ",::DoubleToString(this.Gain(),2),
      ", ",CMessage::Text(MSG_SIGNAL_MQL5_TEXT_DRAWDOWN),": ",::DoubleToString(this.MaxDrawdown(),2),
      ", ",CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE),": ",::DoubleToString(this.Price(),2)
     );
  }
//+------------------------------------------------------------------+

首先创建简短的信号标题。 终端日志中显示的某些参数已添加到其中。
例如,它也许看起来像这样:

Signal "DemoForArticle". Author login: login, ID XXXXXX, Growth: XX.XX, Drawdown: XX.XX, Price: XX.XX

该方法返回帐户类型名称:

//+------------------------------------------------------------------+
//| Return the account type name                                     |
//+------------------------------------------------------------------+
string CMQLSignal::TradeModeDescription(void)
  {
   return
     (
      this.TradeMode()==0 ? CMessage::Text(MSG_ACC_TRADE_MODE_REAL)     :
      this.TradeMode()==1 ? CMessage::Text(MSG_ACC_TRADE_MODE_DEMO)     :
      this.TradeMode()==2 ? CMessage::Text(MSG_ACC_TRADE_MODE_CONTEST)  :
      CMessage::Text(MSG_ACC_TRADE_MODE_UNKNOWN)
     );
  }
//+------------------------------------------------------------------+

根据信号源帐户,返回含有帐户类型(实盘、模拟,或竞赛)的字符串。

MQL5 信号对象的创建至此完毕。


测试

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

现在,DOM 快照序列集合类可供所有主库对象使用,而 MQL5 信号对象尚未连接到 CEngine。 因此,我们来替换 DOM 快照序列对象类的包含代码。

#include <DoEasy\Objects\Book\MBookSeries.mqh>

替换为包含 MQL5 信号对象:

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart65.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\MQLSignalBase\MQLSignal.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;
//+------------------------------------------------------------------+

MQL5 帮助的一个示例:获取免费、盈利、且订户数量不为零的信号列表:

void OnStart()
  {
//--- request the total number of signals in the signal database
   int total=SignalBaseTotal();
//--- loop through all signals
   for(int i=0;i<total;i++)
     {
      //--- select a signal for further operation
      if(SignalBaseSelect(i))
        {
         //--- receive signal properties
         long   id    =SignalBaseGetInteger(SIGNAL_BASE_ID);          // signal ID
         long   pips  =SignalBaseGetInteger(SIGNAL_BASE_PIPS);        // trading result in pips
         long   subscr=SignalBaseGetInteger(SIGNAL_BASE_SUBSCRIBERS); // number of subscribers
         string name  =SignalBaseGetString(SIGNAL_BASE_NAME);         // signal name
         double price =SignalBaseGetDouble(SIGNAL_BASE_PRICE);        // signal subscription price
         string curr  =SignalBaseGetString(SIGNAL_BASE_CURRENCY);     // signal currency
         //--- display all profitable free signals with a non-zero number of subscribers
         if(price==0.0 && pips>0 && subscr>0)
            PrintFormat("id=%d, name=\"%s\", currency=%s, pips=%d, subscribers=%d",id,name,curr,pips,subscr);
        }
      else PrintFormat("Signal selection error. Error code=%d",GetLastError());
     }
  }

我们在新的 MQL5 信号对象帮助下进行相同的操作。 在 EA 的 OnInit() 处理程序中编写以下代码模块

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Calling the function displays the list of enumeration constants in the journal 
//--- (the list is set in the strings 22 and 25 of the DELib.mqh file) for checking the constants validity
   //EnumNumbersTest();

//--- Set EA global variables
   prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_";
   testing=engine.IsTester();
   for(int i=0;i<TOTAL_BUTT;i++)
     {
      butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i);
      butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i);
     }
   lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0));
   magic_number=InpMagic;
   stoploss=InpStopLoss;
   takeprofit=InpTakeProfit;
   distance_pending=InpDistance;
   distance_stoplimit=InpDistanceSL;
   slippage=InpSlippage;
   trailing_stop=InpTrailingStop*Point();
   trailing_step=InpTrailingStep*Point();
   trailing_start=InpTrailingStart;
   stoploss_to_modify=InpStopLossModify;
   takeprofit_to_modify=InpTakeProfitModify;
   distance_pending_request=(InpDistancePReq<5 ? 5 : InpDistancePReq);
   bars_delay_pending_request=(InpBarsDelayPReq<1 ? 1 : InpBarsDelayPReq);
   g_point=SymbolInfoDouble(NULL,SYMBOL_POINT);
   g_digits=(int)SymbolInfoInteger(NULL,SYMBOL_DIGITS);
//--- Initialize random group numbers
   group1=0;
   group2=0;
   srand(GetTickCount());
   
//--- Initialize DoEasy library
   OnInitDoEasy();
   
//--- Check and remove remaining EA graphical objects
   if(IsPresentObectByPrefix(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Create the button panel
   if(!CreateButtons(InpButtShiftX,InpButtShiftY))
      return INIT_FAILED;
//--- Set trailing activation button status
   ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on);
//--- Reset states of the buttons for working using pending requests
   for(int i=0;i<14;i++)
     {
      ButtonState(butt_data[i].name+"_PRICE",false);
      ButtonState(butt_data[i].name+"_TIME",false);
     }

//--- Check playing a standard sound by macro substitution and a custom sound by description
   engine.PlaySoundByDescription(SND_OK);
//--- Wait for 600 milliseconds
   engine.Pause(600);
   engine.PlaySoundByDescription(TextByLanguage("Звук упавшей монетки 2","Falling coin 2"));

   CArrayObj *list=new CArrayObj();
   if(list!=NULL)
     {
      //--- request the total number of signals in the signal database 
      int total=SignalBaseTotal(); 
      //--- loop through all signals 
      for(int i=0;i<total;i++) 
        { 
         //--- select a signal for further operation 
         if(!SignalBaseSelect(i))
            continue;
         long id=SignalBaseGetInteger(SIGNAL_BASE_ID);
         CMQLSignal *signal=new CMQLSignal(id);
         if(signal==NULL)
            continue;
         if(!list.Add(signal))
           {
            delete signal;
            continue;
           }
        } 
      //--- display all profitable free signals with a non-zero number of subscribers
      Print("");
      static bool done=false;
      for(int i=0;i<list.Total();i++)
        {
         CMQLSignal *signal=list.At(i);
         if(signal==NULL)
            continue;
         if(signal.Price()>0 || signal.Subscribers()==0)
            continue;
         //--- The very first suitable signal is fully displayed in the journal
         if(!done)
           {
            signal.Print();
            done=true;
           }
         //--- Short descriptions are displayed for the rest
         else
            signal.PrintShort();
        }
      delete list;
     }
     
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

乍一看,所得到的代码量大于帮助中的代码量。 但这是暂时表象... 一旦信号集合类准备就绪,它将更加简洁。 同时,我将使用代码检查 MQL5 信号对象是否正常工作。

由于我们现在可从主库对象访问 DOM 快照序列集合类,因此 OnBookEvent() 处理程序进行了一些修改。 现在看起来如下:

//+------------------------------------------------------------------+
//| OnBookEvent function                                             |
//+------------------------------------------------------------------+
void OnBookEvent(const string& symbol)
  {
   static bool first=true;
   //--- Leave if failed to update the symbol snapshot series
   if(!engine.OnBookEvent(symbol))
      return;
   //--- Work by the current symbol
   if(symbol==Symbol())
     {
      //--- Get the DOM snapshot series of the current symbol
      CMBookSeries *book_series=engine.GetMBookSeries(symbol);
      if(book_series==NULL)
         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,book.Symbol(),": ",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;
        }
     }
  }
//+------------------------------------------------------------------+

我们也在 OnInitDoEasy() 函数中进行一些修改。 现在,所有用到品种的即时报价序列创建已实现,可直接访问函数库主对象的相应方法。 此外,我还加入了针对所创建 DOM 序列的检查

//--- Check created timeseries - display descriptions of all created timeseries in the journal
//--- (true - only created ones, false - created and declared ones)
   engine.GetTimeSeriesCollection().PrintShort(false); // Short descriptions

//--- Create tick series of all used symbols
   engine.TickSeriesCreateAll();

//--- Check created tick series - display descriptions of all created tick series in the journal
   engine.GetTickSeriesCollection().Print();

//--- Check created DOM series - display descriptions of all created DOM series in the journal
   engine.GetMBookSeriesCollection().Print();


编译 EA 并启动它,在设置中预先设置两个所用品种,和当前图表周期:


位于所创建 DOM 快照集合上的数据第一个适配信号的完整数据,以及关于所有盈利的免费信号的简要数据均会被显示到日志里。 清单的末尾含有快照序列中的数据,和当前图表的第一个获得的 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: 5385
EURUSD symbol timeseries: 
- Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 6310
Tick series "AUDUSD": Requested number of days: 1, Historical data created: 294221
Tick series "EURUSD": Requested number of days: 1, Historical data created: 216048
DOM snapshot series collection:
- "AUDUSD" DOM snapshot series: Requested number of days: 1, Actual history depth: 0
"EURUSD" DOM snapshot series: Requested number of days: 1, Actual history depth: 0
Subscribed to Depth of Market  AUDUSD
Subscribed to Depth of Market  EURUSD
Library initialization time: 00:00:25.015
 
============= Beginning of parameter list (Signal from the MQL5.com Signal service) =============
Account type: Demo
Publication date: 2018.06.04 16:45
Monitoring start date: 2018.06.04 16:45
Date of the latest update of the trading statistics: 2021.02.20 02:01
ID: 435626
Trading account leverage: 200
Trading result in pips: -72124
Position in the Rating of Signals: 12
Number of subscribers: 132
Number of trades: 7866
Status of account subscription to a signal: No
------
Account balance: 43144.27
Account equity: 43150.55
Account growth in %: 331.44
Maximum drawdown: 43.93
Signal subscription price: 0.00
Signal ROI (Return on Investment) in %: 331.51
------
Author login: "robots4forex"
Broker (company) name: "MetaQuotes Software Corp."
Broker server: "MetaQuotes-Demo"
Name: "Prospector Scalper EA"
Account currency: "GBP"
============= End of parameter list (Signal from the MQL5.com Signal service) =============
 
Signal "ADS MT5". Author login: vluxus, ID 478235, Growth: 251.84, Drawdown: 40.26, Price: 0.00
Signal "Sparrow USD ForexClub c 01012019". Author login: Tradotrade, ID 519975, Growth: 12.45, Drawdown: 14.98, Price: 0.00
Signal "RAZRED v03". Author login: joaoluiz_sa, ID 545382, Growth: 96.17, Drawdown: 28.18, Price: 0.00
Signal "NRDemo". Author login: v3sare, ID 655353, Growth: 2.94, Drawdown: 25.37, Price: 0.00
Signal "Amega 1000085182". Author login: AmegaTrust, ID 722001, Growth: 1.92, Drawdown: 5.13, Price: 0.00
Signal "Wns My strategy". Author login: WaldeliN, ID 727851, Growth: 103.69, Drawdown: 47.01, Price: 0.00
Signal "Bk EA". Author login: worknet, ID 749557, Growth: 506.88, Drawdown: 59.78, Price: 0.00
Signal "ROBIN 24". Author login: juanca034, ID 752873, Growth: 926.29, Drawdown: 30.25, Price: 0.00
Signal "Deny Forex". Author login: deny.mendonca, ID 759729, Growth: 149.06, Drawdown: 39.24, Price: 0.00
Signal "T Strategy". Author login: tonarino210, ID 760343, Growth: 28.87, Drawdown: 20.37, Price: 0.00
Signal "IC MT5 Demo". Author login: InvestForce, ID 760539, Growth: 67.01, Drawdown: 35.99, Price: 0.00
Signal "Gridingale". Author login: Myxx, ID 766073, Growth: 21.10, Drawdown: 15.55, Price: 0.00
Signal "Marcos Monteiro". Author login: slovenwill, ID 783988, Growth: 85.08, Drawdown: 17.59, Price: 0.00
Signal "Multi currency trend". Author login: mj2019, ID 785447, Growth: 54.42, Drawdown: 18.52, Price: 0.00
Signal "W7 901074879 Campeonato MT5". Author login: dramos236, ID 787269, Growth: 91.99, Drawdown: 21.20, Price: 0.00
Signal "Ramon Fx". Author login: viniciusramon18, ID 788732, Growth: 54.31, Drawdown: 9.46, Price: 0.00
Signal "Douglas demo w7". Author login: douglas.o.carne, ID 792392, Growth: 219.94, Drawdown: 43.61, Price: 0.00
"Suelen" signal. Author login: suelenacca, ID 794655, Growth: 67.40, Drawdown: 20.97, Price: 0.00
Signal "Conquers". Author login: borgesti, ID 795133, Growth: 37.23, Drawdown: 11.09, Price: 0.00
Signal "Conta demo torneio". Author login: Tiagoximenes, ID 798798, Growth: 42.36, Drawdown: 17.94, Price: 0.00
Signal "Conta demo de mil". Author login: Tiagoximenes, ID 798802, Growth: 132.02, Drawdown: 27.87, Price: 0.00
Signal "The art of Forex". Author login: Myxx, ID 801685, Growth: 170.29, Drawdown: 40.95, Price: 0.00
Signal "BB29 ICM". Author login: desmondpylow, ID 806971, Growth: 2.28, Drawdown: 41.60, Price: 0.00
Signal "Prometheus". Author login: g0079, ID 808538, Growth: 91.44, Drawdown: 22.98, Price: 0.00
Signal "Prueba robot 2 0 automatico". Author login: richwolfcompany, ID 809986, Growth: 76.76, Drawdown: 44.45, Price: 0.00
Signal "Deep Takeover Hedge StressTest 5M Candle". Author login: johnnypasado, ID 811819, Growth: 10.08, Drawdown: 13.58, Price: 0.00
Signal "Campeonato". Author login: AndreAutotecnic, ID 812233, Growth: 87.47, Drawdown: 13.79, Price: 0.00
Signal "OPM PRO". Author login: herinata, ID 812856, Growth: 38.55, Drawdown: 32.35, Price: 0.00
Signal "Slowly but surely 2". Author login: gyurmanz, ID 815467, Growth: 53.73, Drawdown: 13.08, Price: 0.00
Signal "Beef Waves". Author login: vladimir0005, ID 819055, Growth: 50.46, Drawdown: 32.69, Price: 0.00
Signal "Adriano Garcia". Author login: agarcia_ag, ID 823082, Growth: 111.62, Drawdown: 36.00, Price: 0.00
Signal "Max ScalperSpeed MT5". Author login: paran1615, ID 824333, Growth: 74.51, Drawdown: 40.62, Price: 0.00
Signal "SyH". Author login: gtrader2017, ID 826520, Growth: 42.78, Drawdown: 36.81, Price: 0.00
Signal "ECmp5s free". Author login: VallaLorenzo, ID 830456, Growth: 146.90, Drawdown: 27.64, Price: 0.00
Signal "MaxScalperSpeed MT5". Author login: paran1615, ID 835890, Growth: 64.33, Drawdown: 35.14, Price: 0.00
Signal "YEARNSIGNALS". Author login: yearnsignal2k19, ID 837512, Growth: 11.10, Drawdown: 2.54, Price: 0.00
Signal "AGS test 2". Author login: alireza.akbari, ID 838427, Growth: 7.93, Drawdown: 10.89, Price: 0.00
Signal "Waldeli003". Author login: WaldeliN, ID 838605, Growth: 32.98, Drawdown: 5.54, Price: 0.00
Signal "Michele". Author login: michele-m-r, ID 843351, Growth: 49.27, Drawdown: 13.90, Price: 0.00
Signal "SNAILER". Author login: 8F117EE2, ID 843458, Growth: 83.65, Drawdown: 11.86, Price: 0.00
Signal "Juniornicks". Author login: juniornicks, ID 845611, Growth: 100.25, Drawdown: 43.93, Price: 0.00
Signal "Black Hunter". Author login: christianlara, ID 845761, Growth: 51.94, Drawdown: 24.44, Price: 0.00
Signal "Master dizicheh1". Author login: awdtghuoilp, ID 857594, Growth: 5.04, Drawdown: 37.93, Price: 0.00
Signal "EUROS". Author login: Marketsystem, ID 858449, Growth: 5.31, Drawdown: 2.94, Price: 0.00
Signal "Scalpers risk10 pairs7 leverage100". Author login: leron34, ID 861750, Growth: 27.98, Drawdown: 20.53, Price: 0.00
Signal "EUREKA". Author login: Edmed933, ID 861927, Growth: 59.89, Drawdown: 7.32, Price: 0.00
Signal "Nadando Com Tubaroes". Author login: jun152, ID 862191, Growth: 21.18, Drawdown: 5.45, Price: 0.00
Signal "Demo using a grid system". Author login: RyanAfriansyah, ID 865900, Growth: 20.56, Drawdown: 8.38, Price: 0.00
Signal "Pilares". Author login: ValterCezar, ID 866672, Growth: 29.87, Drawdown: 18.96, Price: 0.00
Signal "EUROUSD". Author login: fxtrader036, ID 866719, Growth: 303.28, Drawdown: 40.70, Price: 0.00
Signal "LanzPower 25 S". Author login: sirlanz, ID 868027, Growth: 36.64, Drawdown: 45.53, Price: 0.00
Signal "Amadeu Volpato Desafio Internacional". Author login: Amadeu1971, ID 868928, Growth: 19.79, Drawdown: 12.57, Price: 0.00
Signal "Fernando correia W7". Author login: nandooo_123-hotmail, ID 870169, Growth: 41.70, Drawdown: 25.16, Price: 0.00
Signal "MAK GO". Author login: 9489631, ID 870413, Growth: 469.22, Drawdown: 36.31, Price: 0.00
Signal "Adriano Garcia W7bt 4 Pilares". Author login: agarcia_ag, ID 871868, Growth: 42.84, Drawdown: 13.19, Price: 0.00
Signal "Albertofxsemstop". Author login: albertosuga, ID 871969, Growth: 27.84, Drawdown: 19.36, Price: 0.00
Signal "BetoSTCDemo". Author login: betoabcsp, ID 872141, Growth: 29.03, Drawdown: 18.07, Price: 0.00
Signal "DESAFIOSEMSTOPLOSSCDS". Author login: cdsantos42, ID 873575, Growth: 19.47, Drawdown: 13.24, Price: 0.00
Signal "MrGeek7421". Author login: KamranAhmadi, ID 873583, Growth: 86.74, Drawdown: 16.33, Price: 0.00
Signal "Douglastorneio2w7". Author login: douglas.o.carne, ID 876302, Growth: 18.13, Drawdown: 15.34, Price: 0.00
Signal "Douglasw7demo1". Author login: douglas.o.carne, ID 876303, Growth: 148.80, Drawdown: 26.47, Price: 0.00
Signal "Douglastorneio1w7". Author login: douglas.o.carne, ID 876932, Growth: 136.86, Drawdown: 41.86, Price: 0.00
Signal "Campeonato mundial sem stop". Author login: Lpontes835, ID 878082, Growth: 23.52, Drawdown: 14.93, Price: 0.00
Signal "ALPHA IA v3". Author login: avaalpha, ID 878517, Growth: 2.77, Drawdown: 0.77, Price: 0.00
Signal "Gold x10". Author login: DynamixFX, ID 878540, Growth: 6.47, Drawdown: 8.87, Price: 0.00
Signal "MultiBolbandsRealM5". Author login: 11BREATH11, ID 879072, Growth: 83.18, Drawdown: 20.09, Price: 0.00
Signal "Ticols Stable profit". Author login: ticols, ID 879609, Growth: -56.37, Drawdown: 68.68, Price: 0.00
Signal "EA SkyBot MultiPares CENT". Author login: 4PerformanceFx, ID 882222, Growth: 248.38, Drawdown: 41.29, Price: 0.00
Signal "Trader Unity M15 100 rec". Author login: crifalo, ID 882268, Growth: 24.36, Drawdown: 26.11, Price: 0.00
Signal "Mad Piper Bill Millin". Author login: DiXOVERS, ID 882495, Growth: 251.06, Drawdown: 38.78, Price: 0.00
Signal "ProfitGuy STAR M Demo". Author login: justbond, ID 882847, Growth: 27.45, Drawdown: 24.89, Price: 0.00
Signal "EA GrayRock". Author login: serggray, ID 883235, Growth: 49.42, Drawdown: 28.68, Price: 0.00
Signal "FX FLASH". Author login: tradedeal, ID 883322, Growth: 9.17, Drawdown: 2.88, Price: 0.00
Signal "Optimizer". Author login: alama1, ID 884765, Growth: 73.53, Drawdown: 28.58, Price: 0.00
Signal "NnaFX Demo 02". Author login: 12259468, ID 886070, Growth: 136.64, Drawdown: 30.54, Pric: 0.00
Signal "Phantom5000 DEMO". Author login: JosephSmith, ID 887046, Growth: 43.41, Drawdown: 17.73, Price: 0.00
Signal "Art of Forex MadCat The G". Author login: The_G, ID 888018, Growth: 215.67, Drawdown: 40.86, Price: 0.00
Signal "ICMarkets MT5 AK 05". Author login: A.Klimkovsky, ID 889370, Growth: 13.03, Drawdown: 8.55, Price: 0.00
Signal "ProfitGuy STAR G Demo". Author login: justbond, ID 890551, Growth: 58.84, Drawdown: 58.80, Price: 0.00
Signal "BetoSemStopDM". Author login: betoabcsp, ID 892251, Growth: 94.96, Drawdown: 6.30, Price: 0.00
Signal "Smart Grid 26980 Demo". Author login: tm3912, ID 892313, Growth: 86.30, Drawdown: 37.19, Price: 0.00
Signal "Rel Vigor PSar n Red Dragon n mad max". Author login: DynamixFX, ID 892523, Growth: 73.74, Drawdown: 38.55, Price: 0.00
Signal "SolangeL". Author login: Mulherdeletras1, ID 894019, Growth: 108.40, Drawdown: 20.84, Price: 0.00
Signal "Paulotbone 1". Author login: paulotbone, ID 894062, Growth: 35.14, Drawdown: 23.93, Price: 0.00
Signal "GOLD MASTER". Author login: THEICD, ID 894983, Growth: 218.90, Drawdown: 22.80, Price: 0.00
Signal "Fxfrance". Author login: fxfrance, ID 895838, Growth: 369.48, Drawdown: 41.48, Price: 0.00
Signal "Marcos Paulo Serigatti". Author login: mpm4rcos, ID 895960, Growth: 45.62, Drawdown: 18.21, Price: 0.00
Signal "Roma Forex Desafio 4 Pilares". Author login: Jhonesroma, ID 896016, Growth: 29.60, Drawdown: 43.45, Price: 0.00
Signal "BOSBM OTC Test 5W". Author login: houli, ID 896563, Growth: 144.65, Drawdown: 22.94, Price: 0.00
Signal "FSTickTrade". Author login: onlyforsignup, ID 897751, Growth: 24.68, Drawdown: 16.20, Price: 0.00
Signal "Sun AI". Author login: Myxx, ID 899179, Growth: 16.82, Drawdown: 21.07, Price: 0.00
Signal "Equinox Demo". Author login: Kratoner, ID 905773, Growth: 44.46, Drawdown: 20.55, Price: 0.00
Signal "STRAGA Tornado VM1". Author login: stragapede, ID 906398, Growth: 36.70, Drawdown: 26.00, Price: 0.00
Signal "DiegoT". Author login: DiegoTT, ID 910230, Growth: 28.20, Drawdown: 11.49, Price: 0.00
Signal "Breaking Bad". Author login: Myxx, ID 911569, Growth: 7.63, Drawdown: 8.42, Price: 0.00
Signal "TradesaovivoBr". Author login: dhyegorodrigo1988, ID 913924, Growth: 16.77, Drawdown: 5.60, Price: 0.00
Signal "VantageFX Sunphone Dragon". Author login: sunphone, ID 916421, Growth: 345.56, Drawdown: 36.04, Price: 0.00
Signal "BYQS121". Author login: kadirryildiz, ID 916600, Growth: 32.85, Drawdown: 4.18, Price: 0.00
Signal "FBSLevelUP". Author login: manoj, ID 919106, Growth: 15.29, Drawdown: 10.49, Price: 0.00
Signal "Omega". Author login: zyntherius74, ID 922043, Growth: 70.18, Drawdown: 25.42, Price: 0.00
Signal "Best Bingo". Author login: kalnov-an, ID 926010, Growth: 59.90, Drawdown: 20.63, Price: 0.00
Signal "LCF 1". Author login: yosuf, ID 931735, Growth: 22.42, Drawdown: 36.26, Price: 0.00
Signal "Bao365". Author login: bao365, ID 933208, Growth: 28.41, Drawdown: 11.49, Price: 0.00
The "EURUSD" DOM snapshot series: Requested number of days: 1, Actual history depth: 1
"EURUSD" DOM snapshot (2021.02.24 22:22:54.654):
 - Sell order: 1.21576 [250.00]
 - Sell order: 1.21567 [100.00]
 - Sell order: 1.21566 [50.00]
 - Sell order: 1.21565 [36.00]
 - Buy order: 1.21563 [36.00]
 - Buy order: 1.21561 [50.00]
 - Buy order: 1.21559 [100.00]
 - Buy order: 1.21555 [250.00]


下一步是什么?

在下一篇文章中,我将创建 MQL5 信号集合。

以下是该函数库当前版本的所有文件,以及 MQL5 的测试 EA 文件,供您测试和下载。
请您在评论中留下问题和建议。

返回内容目录

*该系列的前几篇文章:

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

全部回复

0/140

量化课程

    移动端课程