English Русский Español Deutsch 日本語 Português
preview
MQL5 酷宝书 – 财经日历

MQL5 酷宝书 – 财经日历

MetaTrader 5示例 | 20 一月 2022, 12:55
1 903 3
Denis Kirichenko
Denis Kirichenko

概述

MetaTrader 5 终端和 MQL5 编程语言正在不断发展,它们的市场分析功能、开发更复杂交易机器人工具的能力,等等,也在不断扩展。 新的终端工具之一是财经日历,它既可以手动操作,也可以在机器人的辅助下操作。

内置的日历足够灵活。 您可以在终端的日历选项卡上进行配置,嵌入您的网页上,或下载移动版本。 作为一名算法交易者,我最感兴趣的是该工具的编程特性。

这篇文章中,我将尝试把它们发扬光大。


1. 财经日历 — 文档中有什么内容

首先,我们来快速查看文档特征。 通常来说,这十分简单。 与 MQL5 资源的常见情况一样,信息以一致的方式呈现,并用小示例加以说明。


1.1 财经日历函数

该文档介绍了 10 个日历函数

  1. CalendarCountryById();
  2. CalendarEventById();
  3. CalendarValueById();
  4. CalendarCountries();
  5. CalendarEventByCountry();
  6. CalendarEventByCurrency();
  7. CalendarValueHistoryByEvent();
  8. CalendarValueHistory();
  9. CalendarValueLastByEvent();
  10. CalendarValueLast().

这些函数通常返回日历属性(国家、事件、值),或历史事件值。


1.2 财经日历结构

开发人员建议使用三种结构:MqlCalendarCountry、MqlCalendarEvent 和 MqlCalendarValue。


1.2.1  MqlCalendarCountry

该结构提供了有关我们感兴趣的国家和事件的详细信息。

目前,我已经认证了若干经纪商的网站日历有 21 个国家、欧盟和全世界(全球事件)的数据。

[id]           [name] [code] [currency] [currency_symbol]       [url_name] [reserved]
[ 0]  999 "European Union" "EU"   "EUR"      "€"               "european-union"        ...
[ 1]  124 "Canada"         "CA"   "CAD"      "$"               "canada"                ...
[ 2]   36 "Australia"      "AU"   "AUD"      "$"               "australia"             ...
[ 3]  554 "New Zealand"    "NZ"   "NZD"      "$"               "new-zealand"           ...
[ 4]  392 "Japan"          "JP"   "JPY"      "¥"               "japan"                 ...
[ 5]  156 "China"          "CN"   "CNY"      "¥"               "china"                 ...
[ 6]  276 "Germany"        "DE"   "EUR"      "€"               "germany"               ...
[ 7]  250 "France"         "FR"   "EUR"      "€"               "france"                ...
[ 8]  380 "Italy"          "IT"   "EUR"      "€"               "italy"                 ...
[ 9]   76 "Brazil"         "BR"   "BRL"      "R$"              "brazil"                ...
[10]  344 "Hong Kong"      "HK"   "HKD"      "HK$"             "hong-kong"             ...
[11]  702 "Singapore"      "SG"   "SGD"      "R$"              "singapore"             ...
[12]  484 "Mexico"         "MX"   "MXN"      "Mex$"            "mexico"                ...
[13]  710 "South Africa"   "ZA"   "ZAR"      "R"               "south-africa"          ...
[14]  356 "India"          "IN"   "INR"      "₹"               "india"                 ...
[15]  578 "Norway"         "NO"   "NOK"      "Kr"              "norway"                ...
[16]    0 "Worldwide"      "WW"   "ALL"      ""                "worldwide"             ...
[17]  840 "United States"  "US"   "USD"      "$"               "united-states"         ...
[18]  826 "United Kingdom" "GB"   "GBP"      "£"               "united-kingdom"        ...
[19]  756 "Switzerland"    "CH"   "CHF"      "₣"               "switzerland"           ...
[20]  410 "South Korea"    "KR"   "KRW"      "₩"               "south-korea"           ...
[21]  724 "Spain"          "ES"   "EUR"      "€"               "spain"                 ...
[22]  752 "Sweden"         "SE"   "SEK"      "Kr"              "sweden"                ...

俄罗斯并不在此清单内,这有点奇怪。 希望它很快就能出现。


1.2.2  MqlCalendarEvent

该结构提供了有关事件的详细信息。 该结构拥有相当多的属性。 这有潜力成为一款综合基本面分析的良好工具。 稍后,我将研究如何根据某个标准来排序事件。


1.2.3  MqlCalendarValue

该结构提供了有关事件值的详细信息。 其中有前值、实际值和预测值。

在使用该结构时,请记住以下几个微妙的方面。

actual_value, forecast_value, prev_value  revised_prev_value 存储的字段值放大了一百万倍。如果未设置字段值,则该字段存储值为  LONG_MIN (-9223372036854775808)。 不过,如果该字段设置了数值,则应将其除以1000000(一百万)。

MqlCalendarValue 结构有自己的方法,可用指定字段的值简化操作

这些方法可分为两组。

第一组检查给定值是否已被指定:

HasActualValue(void) — 返回 true,如果设置了实际值;否则返回 false
HasForecastValue(void) — 返回 true,如果设置了预测值;否则返回 false
HasPreviousValue(void) — 返回 true,如果设置了前值;否则返回 false
HasRevisedValue(void) — 返回 true,如果设置了修正值;否则返回 false

第二组则直接接收某个值:

GetActualValue(void) — 返回事件的实际值(double),如果未设置相关值,则返回 nan
GetForecastValue(void) — 返回事件的预测值(double),如果未设置相关值,则返回 nan
GetPreviousValue(void) — 返回事件的前值(double),如果未设置相关值,则返回 nan
GetRevisedValue(void) — 返回事件的修正值(double),如果未设置相关值,则返回 nan

我们来看看 MqlCalendarValue 结构如何接收,并检查字段值。 我们将重点关注上一次日本银行(BoJ)的利率决策。 利用 Test_empty_value.mq5 在日志中显示必要的数据,脚本提供了三个获取数值的方式。 

//+------------------------------------------------------------------+
//| LongDouble                                                       |
//+------------------------------------------------------------------+
union LongDouble
  {
   long   long_value;
   double double_value;
  };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Bank of Japan (BoJ) Interest Rate Decision on 22 Sep 2021 02:47 GMT
   ulong event_id = 392060022; // "boj-interest-rate-decision"
   MqlCalendarValue values[];
   datetime date_from, date_to;
   date_from = D'22.09.2021';
   date_to = date_from + PeriodSeconds(PERIOD_D1);
   if(::CalendarValueHistoryByEvent(event_id, values, date_from, date_to))
     {
      LongDouble forecast_val;
      //--- 1) "forecast_value" field
      forecast_val.long_value = values[0].forecast_value;
      ::PrintFormat("\"forecast_value\" field: %I64d", forecast_val.long_value);
      //--- 2) MqlCalendarValue::GetForecastValue()
      forecast_val.double_value = values[0].GetForecastValue();
      ::PrintFormat("MqlCalendarValue::GetForecastValue(): %g", forecast_val.double_value);
      //--- 3) MqlCalendarValue::HasForecastValue()
      if(!values[0].HasForecastValue())
         ::PrintFormat("MqlCalendarValue::HasForecastValue(): %s", (string)false);
     }
  }
//+------------------------------------------------------------------+

第一种方式简单地获取预测值。 若是没有预测值,我们就会得到 LONG_MIN(-9223372036854775808)。 第二种方式已应用在 MqlCalendarValue::GetForecastValue() 结构方法当中。 它返回 'nan'。 第三种方式是最谨慎的,因为它要检查预测值是否存在。 

启动脚本后,日志中将显示以下记录:

GR      0       21:23:36.076    Test_empty_value (USDCAD,H1)    "forecast_value" field: -9223372036854775808
LH      0       21:23:36.080    Test_empty_value (USDCAD,H1)    MqlCalendarValue::GetForecastValue(): nan
HM      0       21:23:36.080    Test_empty_value (USDCAD,H1)    MqlCalendarValue::HasForecastValue(): false


1.2.4 结构关系

这些结构依据以下关系互连(图例 1)。

日历枚举关系

图例 1. 日历结构关系


MqlCalendarCountry 结构通过国家识别码与 MqlCalendarEvent 链接。 "一对多" 关系形式 (1..*)。

MqlCalendarEvent 结构依据事件识别码与 MqlCalendarValue 链接。 "一对多" 关系形式 (1..*)。


1.3 出错

开发人员分配操控财经日历的运行时错误组。 它们是如下请求:

财经日历


ERR_CALENDAR_MORE_DATA
5400 数组大小不足以接收所有值的定义
ERR_CALENDAR_TIMEOUT
5401 请求时间超限
ERR_CALENDAR_NO_DATA
5402 国家未找到



2. 辅助结构和 CiCalendarInfo 类

我更钟情于面向对象一端。 因此,我将给出一个类的示例,该类能提供对日历属性的访问。

请记住,日历 这是一件相当兼收并蓄的事物。 我并非数据库专家,但据我所知,日历通常是一个包含多个数据表的关系数据库。

除了获取属性之外,CiCalendarInfo 类还提供了旨在创建选定事件时间序列的实现。

我们先来看看辅助结构。


2.1 时间序列结构

因为我们要检索 TS(时间序列)的数据,所以我们应该创建其编程根基。 SiTimeSeries 结构负责这一点。.

//+------------------------------------------------------------------+
//| Time series structure                                            |
//+------------------------------------------------------------------+
struct SiTimeSeries
  {
   private:
      bool              init;        // is initialized?
      uint              size;
      datetime          timevals[];  // time values
      double            datavals[];  // data values
      string            name;        // ts name
   public:
      //--- constructor
      void              SiTimeSeries(void);
      //--- destructor
      void             ~SiTimeSeries(void);
      //--- copy consructor
      void              SiTimeSeries(const SiTimeSeries &src_ts);
      //--- assignment operator
      void              operator=(const SiTimeSeries &src_ts);
      //--- equality operator
      bool              operator==(const SiTimeSeries &src_ts);
      //--- indexing operator
      SiTsObservation   operator[](const uint idx) const;
      //--- initialization
      bool              Init(datetime &ts_times[], const double &ts_values[],
                             const string ts_name);
      //--- get series properties
      bool              GetSeries(datetime &dst_times[], double &dst_values[], string &dst_name);
      bool              GetSeries(SiTsObservation &dst_observations[], string &dst_name);
      //--- service
      bool              IsInit(void) const
        {
         return init;
        };
      uint              Size(void) const
        {
         return size;
        };
      void              Print(const int digs = 2, const uint step = 0);
  };
//+------------------------------------------------------------------+

结构的主要元素是 timevals[] 和 datavals[] 数组。 第一个包含时间序列,而第二个包含数值序列

该结构在实现时把其元素均置于私密部分当中。 这意味着时间序列在创建后无法修改。

我们会在下面的示例中处理时间序列结构。 Test_TS.mq5 脚本接收自 2016 年 1 月 1 日到 2021 年 11 月 1 日之间的美国非农就业数据,并将其显示在特殊的图表上。 所以可令图表产生两条曲线 - 实际值和预测值。 我们将采用事件报告区间作为时间线。

脚本启动后,我们首先在日志里显示时间序列数值,然后在图表上绘制图表(图例 2)。


非农数据 (2016-2021)

图例 2. 美国非农就业 (2016-2021)

 

该脚本由以下时间序列值填充:

//--- prepare time and data values for the timeseries
for(int v_idx = 0; v_idx < nfp_values_size; v_idx++)
   {
    MqlCalendarValue curr_nfp_val = nfp_values[v_idx];
    datetime curr_nfp_time = curr_nfp_val.period;
    timevals[v_idx] = curr_nfp_time;
    double curr_nfp_dataval = curr_nfp_val.GetActualValue();
    datavals1[v_idx] = curr_nfp_dataval;
    curr_nfp_dataval = curr_nfp_val.GetForecastValue();
    datavals2[v_idx] = curr_nfp_dataval;
   }

利用 MqlCalendarValue::GetActualValue() 和 MqlCalendarValue::GetForecastValue() 函数立即接收所需的数值。


2.2 时间序列观测结构

任何时间序列都由观测值组成。 创建以下的 SiTsObservation 简单结构用于观测。

//+------------------------------------------------------------------+
//| Time series observation structure                                |
//+------------------------------------------------------------------+
struct SiTsObservation
  {
   datetime          time; // timestamp
   double            val;  // value
   //--- constructor
   void              SiTsObservation(void): time(0), val(EMPTY_VALUE) {}
  };
//+------------------------------------------------------------------+

索引运算符已在 SiTimeSeries 时间序列结构中声明。 它返回所需的序列观测值。 在上述示例中(非农数据上所绘数值),该序列由 70 个值组成。 在此情况下,可以通过以下方式获得第一次最后一次的观测值:

SiTsObservation first_observation, last_observation;
first_observation = nfp_ts1[0];
last_observation = nfp_ts1[nfp_values_size - 1];
string time_str = ::TimeToString(first_observation.time, TIME_DATE);
string data_str = ::DoubleToString(first_observation.val, 0);
::PrintFormat("\nFirst observation: %s, %s", time_str, data_str);
time_str = ::TimeToString(last_observation.time, TIME_DATE);
data_str = ::DoubleToString(last_observation.val, 0);
::PrintFormat("Last observation: %s, %s", time_str, data_str);

在日志中执行指定的代码后,我们得到以下记录:

KJ      0       21:27:16.386    Test_ts (USDCAD,H1)     First observation: 2015.12.01, 292
HO      0       21:27:17.225    Test_ts (USDCAD,H1)     Last observation: 2021.09.01, 194


2.3 CiCalendarInfo 类

我假设创建该类是为了简化对日历属性的访问,并获取事件值(类似于 CAccountInfoCSymbolInfo 和其它交易类),由此应保持其连贯性。

下面是类声明。

//+------------------------------------------------------------------+
//| Class CiCalendarInfo.                                            |
//| Appointment: Class for access to calendar info.                  |
//|              Derives from class CObject.                         |
//+------------------------------------------------------------------+
class CiCalendarInfo : public CObject
  {
      //--- === Data members === ---
   protected:
      string            m_currency;
      ulong             m_country_id;
      MqlCalendarCountry m_country_description;
      ulong             m_event_id;
      MqlCalendarEvent  m_event_description;
      static MqlCalendarCountry m_countries[];
      bool              m_is_init;
      //--- === Methods === ---
   public:
      //--- constructor/destructor
      void           CiCalendarInfo(void);
      void          ~CiCalendarInfo(void) {};
      //--- initialization
      bool           Init
      (
         const string currency = NULL,         // country currency code name
         const ulong country_id = WRONG_VALUE, // country ID
         const ulong event_id = WRONG_VALUE,   // event ID
         const bool to_log = true              // to log?
      );
      void           Deinit(void);
      //--- Сalendar structures descriptions
      bool           CountryDescription(MqlCalendarCountry &country, const bool to_log = false);
      bool           EventDescription(MqlCalendarEvent &event, const bool to_log = false);
      bool           ValueDescription(ulong value_id, MqlCalendarValue &value,
                                      const bool to_log = false);
      bool           EventsByCountryDescription(MqlCalendarEvent &events[], const bool to_log = false);
      bool           EventsByCurrencyDescription(MqlCalendarEvent &events[], const bool to_log = false);
      bool           EventsBySector(const ENUM_CALENDAR_EVENT_SECTOR event_sector,
                                    MqlCalendarEvent &events[], const bool to_log = false);
      //--- Сalendar enum descriptions
      string         EventTypeDescription(const ENUM_CALENDAR_EVENT_TYPE event_type);
      string         EventSectorDescription(const ENUM_CALENDAR_EVENT_SECTOR event_sector);
      string         EventFrequencyDescription(const ENUM_CALENDAR_EVENT_FREQUENCY event_frequency);
      string         EventTimeModeDescription(const ENUM_CALENDAR_EVENT_TIMEMODE event_time_mode);
      string         EventUnitDescription(const ENUM_CALENDAR_EVENT_UNIT event_unit);
      string         EventImportanceDescription(const ENUM_CALENDAR_EVENT_IMPORTANCE event_importance);
      string         EventMultiplierDescription(const ENUM_CALENDAR_EVENT_MULTIPLIER event_multiplier);
      string         ValueImpactDescription(const ENUM_CALENDAR_EVENT_IMPACT event_impact);
      //--- history
      bool           ValueHistorySelectByEvent
      (
         MqlCalendarValue &values[], // array for value descriptions
         datetime datetime_from,     // left border of a time range
         datetime datetime_to = 0    // right border of a time range
      )                 const;
      bool           ValueHistorySelectByEvent
      (
         SiTimeSeries &dst_ts,       // timeseries for value descriptions
         datetime datetime_from,     // left border of a time range
         datetime datetime_to = 0    // right border of a time range
      )                 const;
      bool           ValueHistorySelect
      (
         MqlCalendarValue &values[], // array for value descriptions
         datetime datetime_from,     // left border of a time range
         datetime datetime_to = 0    // right border of a time range
      )                 const;
      bool           ValueHistorySelect
      (
         SiTimeSeries &dst_ts[],     // array of timeseries for value descriptions
         datetime datetime_from,     // left border of a time range
         datetime datetime_to = 0    // right border of a time range
      );
      //--- the calendar database status
      int            ValueLastSelectByEvent
      (
         ulong&               change_id,     // Calendar change ID
         MqlCalendarValue&    values[]       // array for value descriptions
      )                 const;
      int            ValueLastSelect
      (
         ulong&               change_id,     // Calendar change ID
         MqlCalendarValue&    values[]       // array for value descriptions
      )                 const;
      //--- countries and continents
      bool           GetCountries(CArrayString &countries_arr);
      bool           GetCountries(MqlCalendarCountry &countries[]);
      bool           GetUniqueContinents(string &continents[]);
      bool           GetCountriesByContinent(const ENUM_CONTINENT src_continent,
                                             CArrayString &countries_arr);
      string         GetCountryNameById(const ulong country_id);
      //--- events
      bool           GetEventsByName(CArrayString &events_arr, const string name = NULL);
      bool           GetEventsByName(MqlCalendarEvent &events[], const string name = NULL);
      bool           FilterEvents(MqlCalendarEvent &filtered_events[],
                                  MqlCalendarEvent &src_events[], const ulong filter);
      //--- print
      void           PrintCountryDescription(const MqlCalendarCountry &country);
      void           PrintEventDescription(const MqlCalendarEvent &event);
      void           PrintValueDescription(const MqlCalendarValue &value);
      //---
   private:
      bool           ValidateProperties(void);
      bool           CountryById(const ulong country_id);
      bool           EventId(void);
  };
MqlCalendarCountry CiCalendarInfo::m_countries[];

该类由以下成员数据组成:

  1. m_currency 国家 货币 代码;
  2. m_country_id ISO 3166-1 定义的国家识别码;
  3. m_country_description 国家 说明;
  4. m_event_id 事件识别码;
  5. m_event_description 事件说明;
  6. m_countries 日历中提供的国家/地区说明数组;
  7. m_is_init 初始化标志。

m_currency, m_country_id 和 m_event_id 成员数据是来自日历数据库的用于创建数据请求的一组标准。

m_country_description m_event_description 成员数据则在已知国家/地区和事件时,可快速访问说明。

m_countries 成员数据均是静态的。 国家/地区数据是常量,因此无需每次初始化新的 CiCalendarInfo 对象即可请求该数据。

现在我针对一些方法加以说明。


2.3.1 初始化方法

该方法允许我们开始处理类对象。 该方法对于接收日历数据至关重要。 该方法采用一组标准作为参数(货币代码、国家识别码、事件识别码),并依据一个参数启用在日志中显示初始化数据。这些标准可令访问日历更加具体。

//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
bool CiCalendarInfo::Init(const string currency = NULL,         // country currency code name
                          const ulong country_id = WRONG_VALUE, // country ID
                          const ulong event_id = WRONG_VALUE,   // event ID
                          const bool to_log = true              // to log?
                         )
  {
//--- check reinitialization
   if(m_is_init)
     {
      ::PrintFormat(__FUNCTION__ + ": CiCalendarInfo object already initialized!");
      return false;
     }
//--- check countries
   int countries_cnt = ::ArraySize(m_countries);
   if(countries_cnt < 1)
     {
      ::ResetLastError();
      countries_cnt = ::CalendarCountries(m_countries);
      if(countries_cnt < 1)
        {
         ::PrintFormat(__FUNCTION__ + ": CalendarCountries() returned 0! Error %d",
                       ::GetLastError());
         return false;
        }
     }
   for(int c_idx = 0; c_idx < countries_cnt; c_idx++)
     {
      MqlCalendarCountry curr_country = m_countries[c_idx];
      //--- check currency
      if(!::StringCompare(curr_country.currency, currency))
        {
         m_currency = currency;
        }
      //--- check country
      if(country_id != WRONG_VALUE)
         if(curr_country.id == country_id)
           {
            m_country_id = country_id;
           }
     }
//--- check event
   if(event_id != WRONG_VALUE)
     {
      m_event_id = event_id;
     }
//--- validate properties
   if(!this.ValidateProperties())
      return false;
//---
   if(to_log)
     {
      ::Print("\n---== New Calendar Info object ==---");
      if(m_currency != NULL)
         ::PrintFormat("   Currency: %s", m_currency);
      if(m_country_id != WRONG_VALUE)
         ::PrintFormat("   Country id: %I64u", m_country_id);
      if(m_event_id != WRONG_VALUE)
         ::PrintFormat("   Event id: %I64u", m_event_id);
     }
   m_is_init = true;
   return true;
  }
//+------------------------------------------------------------------+

我们用一个简单的脚本 Test_initialization.mq5 来描绘方法的操作。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- TRUE
//--- 1) all currencies, all countries, all events
   CiCalendarInfo calendar_info1;
   bool is_init = calendar_info1.Init();
//--- 2) EUR, all countries, all events
   CiCalendarInfo calendar_info2;
   is_init = calendar_info2.Init("EUR");
//--- 3) EUR, Germany, all events
   CiCalendarInfo calendar_info3;
   is_init = calendar_info3.Init("EUR", 276);
//--- 4) EUR, Germany, HICP m/m
   CiCalendarInfo calendar_info4;
   is_init = calendar_info4.Init("EUR", 276, 276010022);
//--- FALSE
//--- 5) EUR, Germany, nonfarm-payrolls
   CiCalendarInfo calendar_info5;
   is_init = calendar_info5.Init("EUR", 276, 840030016);
//--- 6) EUR, US, nonfarm-payrolls
   CiCalendarInfo calendar_info6;
   is_init = calendar_info6.Init("EUR", 840, 840030016);
//--- 7) EUR, all countries, nonfarm-payrolls
   CiCalendarInfo calendar_info7;
   is_init = calendar_info7.Init("EUR", WRONG_VALUE, 840030016);
  }
//+------------------------------------------------------------------+

脚本启动后,我们会在日志中看到以下记录:

DO      0       21:30:19.703    Test_initialization (USDCAD,H1) ---== New Calendar Info object ==---
GE      0       21:30:19.703    Test_initialization (USDCAD,H1) 
LL      0       21:30:19.703    Test_initialization (USDCAD,H1) ---== New Calendar Info object ==---
FI      0       21:30:19.703    Test_initialization (USDCAD,H1)    Currency: EUR
GO      0       21:30:19.703    Test_initialization (USDCAD,H1) 
LJ      0       21:30:19.703    Test_initialization (USDCAD,H1) ---== New Calendar Info object ==---
FS      0       21:30:19.703    Test_initialization (USDCAD,H1)    Currency: EUR
KO      0       21:30:19.703    Test_initialization (USDCAD,H1)    Country id: 276
CH      0       21:30:19.703    Test_initialization (USDCAD,H1) 
PI      0       21:30:19.703    Test_initialization (USDCAD,H1) ---== New Calendar Info object ==---
JF      0       21:30:19.703    Test_initialization (USDCAD,H1)    Currency: EUR
OL      0       21:30:19.703    Test_initialization (USDCAD,H1)    Country id: 276
HD      0       21:30:19.703    Test_initialization (USDCAD,H1)    Event id: 276010022
HR      0       21:30:19.703    Test_initialization (USDCAD,H1) CiCalendarInfo::ValidateProperties: failed! Country ids must be the same!
OP      0       21:30:19.703    Test_initialization (USDCAD,H1) CiCalendarInfo::ValidateProperties: failed! Currencies must be the same!
GP      0       21:30:19.703    Test_initialization (USDCAD,H1) CiCalendarInfo::ValidateProperties: failed! Currencies must be the same!

初始化方法检查指定的参数,即它的参数项里属于单一国家货币的那一个。 因此,返回以下组合"false": EUR – Germany - nonfarm-payrolls, EUR – US - nonfarm-payrolls and EUR – all countries - nonfarm-payrolls.

在初始化方法伊始,有一层防止重新初始化的保护。 日历对象仍然可以重新初始化,但首先我们应该调用逆初始化方法。 例如,我们首先定义日历对象来收集 EUR 事件的数据。 然后,应该将对象重新定向到 USD。 Test_reinitialization.mq5 脚本描绘了此任务的不正确的正确的解决方案。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
   {
//--- ERROR
   CiCalendarInfo calendar_info1;
   bool is_init = calendar_info1.Init("EUR");
   is_init = calendar_info1.Init("USD");
//--- OK
   CiCalendarInfo calendar_info2;
   is_init = calendar_info2.Init("EUR");
   calendar_info2.Deinit();
   is_init = calendar_info2.Init("USD");
   }
//+------------------------------------------------------------------+

在不正确的情况下,我们将看到如下记录:

MP      0       21:34:19.397    Test_reinitialization (USDCAD,H1)       
FQ      0       21:34:19.397    Test_reinitialization (USDCAD,H1)       ---== New Calendar Info object ==---
HO      0       21:34:19.397    Test_reinitialization (USDCAD,H1)          Currency: EUR
KI      0       21:34:19.397    Test_reinitialization (USDCAD,H1)       CiCalendarInfo::Init: CiCalendarInfo object already initialized!
EI      0       21:34:19.397    Test_reinitialization (USDCAD,H1)       
NO      0       21:34:19.397    Test_reinitialization (USDCAD,H1)       ---== New Calendar Info object ==---
PF      0       21:34:19.397    Test_reinitialization (USDCAD,H1)          Currency: EUR
QL      0       21:34:19.397    Test_reinitialization (USDCAD,H1)       
RD      0       21:34:19.397    Test_reinitialization (USDCAD,H1)       ---== New Calendar Info object ==---
DS      0       21:34:19.397    Test_reinitialization (USDCAD,H1)          Currency: USD


2.3.2 接收日历结构说明的方法

在某种程度上,这些方法是允许调用标准日历函数的包装器。 CiCalendarInfo::CountryDescription() and CiCalendarInfo::EventDescription() 方法返回在日历对象初始化期间确认的国家和事件说明。 

此外,这些方法能够在日志中显示所请求属性的说明。

我们用一个简单的脚本 Test_structures_descriptions.mq5 来描绘接收说明方法的操作。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- 1) events by country
   CiCalendarInfo calendar_info;
   ulong country_id = 276; // Germany
   if(calendar_info.Init(NULL, country_id))
     {
      MqlCalendarEvent events[];
      if(calendar_info.EventsByCountryDescription(events))
        {
         Print("\n---== Events selected by country ==---");
         PrintFormat("   Country id: %I64u", country_id);
         PrintFormat("   Events number: %d", ::ArraySize(events));
        }
     }
   calendar_info.Deinit();
//--- 2) events by currency
   string country_currency = "EUR";
   if(calendar_info.Init(country_currency))
     {
      MqlCalendarEvent events[];
      if(calendar_info.EventsByCurrencyDescription(events))
        {
         Print("\n---== Events selected by currency ==---");
         PrintFormat("   Currency: %s", country_currency);
         PrintFormat("   Events number: %d", ::ArraySize(events));
        }
     }
  }
//+------------------------------------------------------------------+

在日志中,我们可以发现以下字符串:

MK      0       21:36:35.659    Test_structures_descriptions (USDCAD,H1)        
DM      0       21:36:35.659    Test_structures_descriptions (USDCAD,H1)        ---== New Calendar Info object ==---
MP      0       21:36:35.659    Test_structures_descriptions (USDCAD,H1)           Country id: 276
FH      0       21:36:35.793    Test_structures_descriptions (USDCAD,H1)        
ON      0       21:36:35.793    Test_structures_descriptions (USDCAD,H1)        ---== Events selected by country ==---
RR      0       21:36:35.793    Test_structures_descriptions (USDCAD,H1)           Country id: 276
GD      0       21:36:35.793    Test_structures_descriptions (USDCAD,H1)           Events number: 61
FP      0       21:36:35.793    Test_structures_descriptions (USDCAD,H1)        
OG      0       21:36:35.793    Test_structures_descriptions (USDCAD,H1)        ---== New Calendar Info object ==---
KI      0       21:36:35.793    Test_structures_descriptions (USDCAD,H1)           Currency: EUR
MN      0       21:36:35.794    Test_structures_descriptions (USDCAD,H1)        
QE      0       21:36:35.794    Test_structures_descriptions (USDCAD,H1)        ---== Events selected by currency ==---
FO      0       21:36:35.794    Test_structures_descriptions (USDCAD,H1)           Currency: EUR
FJ      0       21:36:35.794    Test_structures_descriptions (USDCAD,H1)           Events number: 276

这意味着德国有 61 条事件,欧洲全部国家有 276 条事件。


2.3.3 该方法接收日历枚举说明

日历结构包含八个枚举:

  1. ENUM_CALENDAR_EVENT_TYPE;
  2. ENUM_CALENDAR_EVENT_SECTOR;
  3. ENUM_CALENDAR_EVENT_FREQUENCY;
  4. ENUM_CALENDAR_EVENT_TIMEMODE;
  5. ENUM_CALENDAR_EVENT_UNIT;
  6. ENUM_CALENDAR_EVENT_IMPORTANCE;
  7. ENUM_CALENDAR_EVENT_MULTIPLIER;
  8. ENUM_CALENDAR_EVENT_IMPACT.

前七个枚举引用 MqlCalendarEvent 结构,而最后一个枚举引用 MqlCalendarValue 结构。

CiCalendarInfo 类定义了八个方法,可用于说明从建议列表中选定的枚举值。 我们利用 Test_enums_descriptions.mq5 脚本进行方法测试。 脚本随机选择10 条英国事件,并在日志中显示每条的数据。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
   {
   CiCalendarInfo calendar_info;
   ulong country_id = 826; // UK
   if(calendar_info.Init(NULL, country_id))
      {
      MqlCalendarEvent events[];
      if(calendar_info.EventsByCountryDescription(events))
         {
         ::MathSrand(77);
         int events_num =::ArraySize(events);
         int n = 10;
         MqlCalendarEvent events_selected[];
         ::ArrayResize(events_selected, n);
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            int rand_val =::MathRand();
            int rand_idx = rand_val % events_num;
            events_selected[ev_idx] = events[rand_idx];
            }
         //--- 0) name
         ::Print("\n---== Name ==---");
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            MqlCalendarEvent curr_event = events_selected[ev_idx];
            ::PrintFormat("   [%d] - %s", ev_idx + 1, curr_event.name);
            }
         //--- 1) type
         ::Print("\n---== Type ==---");
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            MqlCalendarEvent curr_event = events_selected[ev_idx];
            ::PrintFormat("   [%d] - %s", ev_idx + 1,
                          calendar_info.EventTypeDescription(curr_event.type));
            }
         //--- 2) sector
         ::Print("\n---== Sector ==---");
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            MqlCalendarEvent curr_event = events_selected[ev_idx];
            ::PrintFormat("   [%d] - %s", ev_idx + 1,
                          calendar_info.EventSectorDescription(curr_event.sector));
            }
         //--- 3) frequency
         ::Print("\n---== Frequency ==---");
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            MqlCalendarEvent curr_event = events_selected[ev_idx];
            ::PrintFormat("   [%d] - %s", ev_idx + 1,
                          calendar_info.EventFrequencyDescription(curr_event.frequency));
            }
         //--- 3) time mode
         ::Print("\n---== Time mode ==---");
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            MqlCalendarEvent curr_event = events_selected[ev_idx];
            ::PrintFormat("   [%d] - %s", ev_idx + 1,
                          calendar_info.EventTimeModeDescription(curr_event.time_mode));
            }
         //--- 4) unit
         ::Print("\n---== Unit ==---");
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            MqlCalendarEvent curr_event = events_selected[ev_idx];
            ::PrintFormat("   [%d] - %s", ev_idx + 1,
                          calendar_info.EventUnitDescription(curr_event.unit));
            }
         //--- 5) importance
         ::Print("\n---== Importance ==---");
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            MqlCalendarEvent curr_event = events_selected[ev_idx];
            ::PrintFormat("   [%d] - %s", ev_idx + 1,
                          calendar_info.EventImportanceDescription(curr_event.importance));
            }
         //--- 6) multiplier
         ::Print("\n---== Multiplier ==---");
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            MqlCalendarEvent curr_event = events_selected[ev_idx];
            ::PrintFormat("   [%d] - %s", ev_idx + 1,
                          calendar_info.EventMultiplierDescription(curr_event.multiplier));
            }
         //--- 7) impact
         MqlCalendarValue values_by_event[];
         datetime start_dt, stop_dt;
         start_dt = D'01.01.2021';
         stop_dt = D'01.11.2021';
         ::Print("\n---== Impact ==---");
         for(int ev_idx = 0; ev_idx < n; ev_idx++)
            {
            MqlCalendarEvent curr_event = events_selected[ev_idx];
            CiCalendarInfo event_info;
            MqlCalendarValue ev_values[];
            if(event_info.Init(NULL, WRONG_VALUE, curr_event.id))
               if(event_info.ValueHistorySelectByEvent(ev_values, start_dt, stop_dt))
                  {
                  int ev_values_size =::ArraySize(ev_values);
                  ::PrintFormat("   [%d] - %s", ev_idx + 1,
                                calendar_info.ValueImpactDescription(ev_values[--ev_values_size].impact_type));
                  }
            }
         }
      }
   }
//+------------------------------------------------------------------+

若要再现获得的结果,需将伪随机整数值生成器的初始状态设置为某个数字(::MathSrand(77))。 脚本已选择了以下事件:

  1. BoE Housing Equity Withdrawal q/q;
  2. BoE Deputy Governor Markets and Banking Ramsden Speech;
  3. Claimant Count Change;
  4. Core CPI y/y;
  5. Average Weekly Earnings, Total Pay y/y;
  6. Easter Monday;
  7. BoE Mortgage Lending m/m;
  8. BoE MPC Member Vlieghe Speech;
  9. Core RPI y/y;
  10. Claimant Count Change.

日志中会出现以下说明:

FP      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     ---== Type ==---
CG      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [1] - Indicator
EN      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [2] - Event
EI      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [3] - Indicator
LP      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [4] - Indicator
OK      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [5] - Indicator
OD      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [6] - Holiday
EL      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [7] - Indicator
GG      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [8] - Event
ON      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [9] - Indicator
CJ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [10] - Indicator
DO      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     
PE      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     ---== Sector ==---
JR      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [1] - Money
KJ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [2] - Money
NQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [3] - Labor market
QS      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [4] - Prices
HD      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [5] - Labor market
JP      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [6] - Holidays
OI      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [7] - Housing
EQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [8] - Money
LD      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [9] - Prices
JR      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [10] - Labor market
RS      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     
NF      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     ---== Frequency ==---
ML      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [1] - Quarterly
QH      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [2] - None
MN      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [3] - Monthly
PI      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [4] - Monthly
OP      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [5] - Monthly
CE      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [6] - None
CR      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [7] - Monthly
CS      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [8] - None
GE      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [9] - Monthly
OO      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [10] - Monthly
PI      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     
NQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     ---== Time mode ==---
FE      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [1] - Exact time
MS      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [2] - Exact time
PH      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [3] - Exact time
CQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [4] - Exact time
RO      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [5] - Exact time
PF      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [6] - Takes all day
NR      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [7] - Exact time
MK      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [8] - Exact time
DQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [9] - Exact time
RM      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [10] - Exact time
FK      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     
HP      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     ---== Unit ==---
CI      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [1] - National currency
OO      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [2] - None
MG      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [3] - People
CO      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [4] - Percentage
NE      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [5] - Percentage
OK      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [6] - None
KQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [7] - National currency
CH      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [8] - None
LQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [9] - Percentage
CE      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [10] - People
LL      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     
PD      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     ---== Importance ==---
FS      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [1] - Low
PD      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [2] - Moderate
DK      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [3] - High
EM      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [4] - Low
QJ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [5] - Moderate
GQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [6] - None
PG      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [7] - Low
RO      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [8] - Moderate
LI      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [9] - Low
FM      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [10] - High
ND      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     
CM      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     ---== Multiplier ==---
HE      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [1] - Billions
MK      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [2] - None
IM      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [3] - Thousands
MI      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [4] - None
HQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [5] - None
OH      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [6] - None
DN      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [7] - Billions
IF      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [8] - None
LN      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [9] - None
OH      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [10] - Thousands
DM      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     
FF      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)     ---== Impact ==---
OK      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [1] - Positive
OR      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [2] - None
EJ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [3] - Positive
RQ      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [4] - Negative
CG      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [5] - Negative
KN      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [6] - None
JF      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [7] - None
EM      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [8] - None
GD      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [9] - Positive
QH      0       21:14:19.340    Test_enums_descriptions (USDCAD,H1)        [10] - Positive

例如,第一条事件 “BoE Housing Equity Withdrawal q/q” 说明如下:

  1. "Type" - 指标;
  2. "Sector" - 资金;
  3. "Frequency" - 季度;
  4. "Time mode" - 确切时间;
  5. "Unit" - 国家法定货币;
  6. "Importance" - 低;
  7. "Multiplier" - 十亿;
  8. "Impact" - 正面。

最后一条事件 "Claimant Count Change" 则如下说明:

  1. "Type" - 指标;
  2. "Sector" - 劳工;
  3. "Frequency" - 季度;
  4. "Time mode" - 确切时间;
  5. "Unit" - 国家法定货币;
  6. "Importance" - 低;
  7. "Multiplier" - 十亿;
  8. "Impact" - 正面。


2.3.4 访问历史记录的方法

这些方法还用到内置的日历函数,随同获取事件值的数据。 例如,::CalendarValueHistoryByEvent() 函数经由两个重载方法 CiCalendarInfo::ValueHistorySelectByEvent() 来访问。 第一个函数依据 MqlCalendarValue 结构形式的事件标识符返回指定时间范围内所有事件数值的数组 ,而第二个函数则把数值数组已转换为时间序列。

我们已看到过在 Test_value_history_by_event.mq5 脚本里 CiCalendarInfo::ValueHistorySelectByEvent() 方法是如何操作的。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- NFP
   CiCalendarInfo nfp_info;
   ulong nfp_id = 840030016;
   if(nfp_info.Init(NULL, WRONG_VALUE, nfp_id))
     {
      SiTimeSeries nfp_ts;
      if(nfp_info.ValueHistorySelectByEvent(nfp_ts, 0, ::TimeTradeServer()))
         nfp_ts.Print(0);
     }
  }
//+------------------------------------------------------------------+

美国非农就业选择整个历史记录。

日志中出现以下记录:

PL      0       21:45:03.581    Test_value_history_by_event (USDCAD,H1) ---== New Calendar Info object ==---
NI      0       21:45:03.581    Test_value_history_by_event (USDCAD,H1)    Event id: 840030016
OM      0       21:45:03.581    Test_value_history_by_event (USDCAD,H1) 
HG      0       21:45:03.581    Test_value_history_by_event (USDCAD,H1) ---== Times series - Nonfarm Payrolls==---
CJ      0       21:45:03.581    Test_value_history_by_event (USDCAD,H1) [1]: time - 2007.03.09 16:30, value - 97
RE      0       21:45:03.581    Test_value_history_by_event (USDCAD,H1) [2]: time - 2007.04.06 15:30, value - 177
MS      0       21:45:03.581    Test_value_history_by_event (USDCAD,H1) [3]: time - 2007.05.04 15:30, value - 80
FL      0       21:45:03.581    Test_value_history_by_event (USDCAD,H1) [4]: time - 2007.06.01 15:30, value - 190
LH      0       21:45:03.581    Test_value_history_by_event (USDCAD,H1) [5]: time - 2007.07.06 15:30, value - 69
...
JE      0       21:45:03.583    Test_value_history_by_event (USDCAD,H1) [172]: time - 2021.06.04 15:30, value - 559
JP      0       21:45:03.583    Test_value_history_by_event (USDCAD,H1) [173]: time - 2021.07.02 15:30, value - 850
IO      0       21:45:03.583    Test_value_history_by_event (USDCAD,H1) [174]: time - 2021.08.06 15:30, value - 943
NJ      0       21:45:03.583    Test_value_history_by_event (USDCAD,H1) [175]: time - 2021.09.03 15:30, value - 235
HI      0       21:45:03.583    Test_value_history_by_event (USDCAD,H1) [176]: time - 2021.10.08 15:30, value - 194

*在此,我指定了第一个和最后五条事件数值,从而避免令文章变得混乱。


2.3.5 检查日历数据库状态的方法

这些方法还利用相应的内置日历函数。 仅当得到的事件值数量等于零,而自身错误超过零时,才会报告错误。 

在第三部分“非商用净持仓指标”中研究了 CiCalendarInfo::ValueLastSelectByEvent() 方法的示例,在其中我们需要检测新值的外观。


2.3.6 获取国家和大陆数据的方法

这些方法返回特定的国家数据。 我将简要介绍其中的每一项。

CiCalendarInfo::GetCountries(CArrayString &countries_arr) 方法返回初始化期间得到的国家列表构成的字符串类型变量动态数组。

CiCalendarInfo::GetCountries(MqlCalendarCountry &countries[]) 方法返回初始化期间得到的国家列表构成的 MqlCalendarCountry 类型变量动态数组。

CiCalendarInfo::GetUniqueContinents(string & continents[]) 方法返回这些国家所在的大陆列表。 后者也是在初始化过程中获得的

CiCalendarInfo:: GetCountriesByContinent(const ENUM_CONTINENT src_continent, CArrayString &countries_arr) 方法返回依据指定大陆得到的国家列表

CiCalendarInfo::GetCountryNameById(const ulong country_id) 方法返回依据其识别码得到的国家名称。

ENUM_CONTINENT 枚举能够操控大陆。 它描述了以下大陆:

  1. World(全世界);
  2. Asia(亚洲);
  3. Africa(非洲);
  4. Europe(欧洲);
  5. North America(北美洲);
  6. South America(南美洲);
  7. Australia/Oceania(澳洲/大洋洲);
  8. Antarctica(南极洲).

我把南极洲也包括在枚举之中,这看起来很有趣。 但我想有一份详尽的大陆名单,所以就让它留在那里吧。 “World(全世界) ”常数被安排为一个单独的大陆。

此外,我还创建了 ScontryContinente 结构来处理大陆。 初始化方法提供的常量数组内含国家代码、名称和对应大陆。 当前版本包括了欧盟和全世界在内的 197 个国家。

我们创建 Test_get_countries.mq5 脚本来检验获取国家和大陆数据的方法操作。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   CiCalendarInfo country_calendar_info;
   if(country_calendar_info.Init())
     {
      //--- 1) get countries (CArrayString)
      CArrayString countries_arr;
      if(country_calendar_info.GetCountries(countries_arr))
        {
         int countries_num = countries_arr.Total();
         if(countries_num > 0)
           {
            ::Print("\n---== CArrayString list ==---");
            ::PrintFormat("   Countries list consists of %d countries.", countries_num);
            ::PrintFormat("   First country: %s", countries_arr.At(0));
            ::PrintFormat("   Last country: %s", countries_arr.At(countries_num - 1));
           }
        }
      //--- 2) get countries (MqlCalendarCountry)
      MqlCalendarCountry countries[];
      if(country_calendar_info.GetCountries(countries))
        {
         int countries_num = ::ArraySize(countries);
         if(countries_num > 0)
           {
            ::Print("\n---== MqlCalendarCountry array ==---");
            ::PrintFormat("   Countries array consists of %d countries.", countries_num);
            ::PrintFormat("   First country: %s", countries[0].name);
            ::PrintFormat("   Last country: %s", countries[countries_num - 1].name);
           }
        }
      //--- 3) get unique continents
      string continent_names[];
      int continents_num = 0;
      if(country_calendar_info.GetUniqueContinents(continent_names))
        {
         continents_num = ::ArraySize(continent_names);
         if(continents_num > 0)
           {
            ::Print("\n---== Unique continent names ==---");
            for(int c_idx = 0; c_idx < continents_num; c_idx++)
              {
               string curr_continent_name = continent_names[c_idx];
               ::PrintFormat("   [%d] - %s", c_idx + 1, curr_continent_name);
              }
           }
        }
      //--- 4) get countries by continent
      if(continents_num)
        {
         ENUM_CONTINENT continents[];
         ::ArrayResize(continents, continents_num);
         ::Print("\n---== Countries by continent ==---");
         for(int c_idx = 0; c_idx < continents_num; c_idx++)
           {
            ENUM_CONTINENT curr_continent =
               SCountryByContinent::ContinentByDescription(continent_names[c_idx]);
            if(countries_arr.Shutdown())
               if(country_calendar_info.GetCountriesByContinent(curr_continent, countries_arr))
                 {
                  int countries_by_continent = countries_arr.Total();
                  ::PrintFormat("   Continent \"%s\" includes %d country(-ies):",
                                continent_names[c_idx], countries_by_continent);
                  for(int c_jdx = 0; c_jdx < countries_by_continent; c_jdx++)
                    {
                     ::PrintFormat("   [%d] - %s", c_jdx + 1,
                                   countries_arr.At(c_jdx));
                    }
                 }
           }
        }
      //--- 5) get country description
      string country_code = "RU";
      SCountryByContinent country_continent_data;
      if(country_continent_data.Init(country_code))
        {
         ::Print("\n---== Country ==---");
         ::PrintFormat("   Name: %s", country_continent_data.Country());
         ::PrintFormat("   Code: %s", country_continent_data.Code());
         ENUM_CONTINENT curr_continent = country_continent_data.Continent();
         ::PrintFormat("   Continent enum: %s", ::EnumToString(curr_continent));
         ::PrintFormat("   Continent description: %s",
                       country_continent_data.ContinentDescription());
        }
     }
  }
//+------------------------------------------------------------------+

在脚本工作时,日志中将出现以下信息:

EH      0       23:05:16.492    Test_get_countries (USDCAD,H1)  ---== New Calendar Info object ==---
HR      0       23:05:16.492    Test_get_countries (USDCAD,H1)  
QH      0       23:05:16.492    Test_get_countries (USDCAD,H1)  ---== CArrayString list ==---
NR      0       23:05:16.492    Test_get_countries (USDCAD,H1)     Countries list consists of 23 countries.
NP      0       23:05:16.492    Test_get_countries (USDCAD,H1)     First country: European Union
LF      0       23:05:16.492    Test_get_countries (USDCAD,H1)     Last country: Norway
LQ      0       23:05:16.492    Test_get_countries (USDCAD,H1)  
GG      0       23:05:16.492    Test_get_countries (USDCAD,H1)  ---== MqlCalendarCountry array ==---
IL      0       23:05:16.492    Test_get_countries (USDCAD,H1)     Countries array consists of 23 countries.
JP      0       23:05:16.492    Test_get_countries (USDCAD,H1)     First country: European Union
HG      0       23:05:16.492    Test_get_countries (USDCAD,H1)     Last country: Norway
OR      0       23:05:16.493    Test_get_countries (USDCAD,H1)  
FJ      0       23:05:16.493    Test_get_countries (USDCAD,H1)  ---== Unique continent names ==---
KS      0       23:05:16.493    Test_get_countries (USDCAD,H1)     [1] - Africa
NK      0       23:05:16.493    Test_get_countries (USDCAD,H1)     [2] - Asia
HR      0       23:05:16.493    Test_get_countries (USDCAD,H1)     [3] - Australia/Oceania
HM      0       23:05:16.493    Test_get_countries (USDCAD,H1)     [4] - Europe
RE      0       23:05:16.493    Test_get_countries (USDCAD,H1)     [5] - North America
CO      0       23:05:16.493    Test_get_countries (USDCAD,H1)     [6] - South America
GH      0       23:05:16.493    Test_get_countries (USDCAD,H1)     [7] - World
GP      0       23:05:18.606    Test_get_countries (USDCAD,H1)  
LE      0       23:05:18.606    Test_get_countries (USDCAD,H1)  ---== Countries by continent ==---
HO      0       23:05:18.608    Test_get_countries (USDCAD,H1)     Continent "Africa" includes 1 country(-ies):
RR      0       23:05:18.608    Test_get_countries (USDCAD,H1)     [1] - South Africa
NH      0       23:05:18.610    Test_get_countries (USDCAD,H1)     Continent "Asia" includes 6 country(-ies):
CM      0       23:05:18.610    Test_get_countries (USDCAD,H1)     [1] - China
RK      0       23:05:18.610    Test_get_countries (USDCAD,H1)     [2] - Hong Kong
CL      0       23:05:18.610    Test_get_countries (USDCAD,H1)     [3] - India
LJ      0       23:05:18.610    Test_get_countries (USDCAD,H1)     [4] - South Korea
LJ      0       23:05:18.610    Test_get_countries (USDCAD,H1)     [5] - Japan
IR      0       23:05:18.610    Test_get_countries (USDCAD,H1)     [6] - Singapore
OK      0       23:05:18.614    Test_get_countries (USDCAD,H1)     Continent "Australia/Oceania" includes 2 country(-ies):
RM      0       23:05:18.614    Test_get_countries (USDCAD,H1)     [1] - Australia
NJ      0       23:05:18.614    Test_get_countries (USDCAD,H1)     [2] - New Zealand
MM      0       23:05:18.616    Test_get_countries (USDCAD,H1)     Continent "Europe" includes 9 country(-ies):
LO      0       23:05:18.616    Test_get_countries (USDCAD,H1)     [1] - European Union
DF      0       23:05:18.616    Test_get_countries (USDCAD,H1)     [2] - Germany
OQ      0       23:05:18.616    Test_get_countries (USDCAD,H1)     [3] - France
CE      0       23:05:18.616    Test_get_countries (USDCAD,H1)     [4] - United Kingdom
OM      0       23:05:18.616    Test_get_countries (USDCAD,H1)     [5] - Switzerland
RS      0       23:05:18.616    Test_get_countries (USDCAD,H1)     [6] - Spain
FE      0       23:05:18.616    Test_get_countries (USDCAD,H1)     [7] - Sweden
JS      0       23:05:18.616    Test_get_countries (USDCAD,H1)     [8] - Italy
DD      0       23:05:18.616    Test_get_countries (USDCAD,H1)     [9] - Norway
LR      0       23:05:18.618    Test_get_countries (USDCAD,H1)     Continent "North America" includes 3 country(-ies):
LK      0       23:05:18.618    Test_get_countries (USDCAD,H1)     [1] - Canada
HS      0       23:05:18.618    Test_get_countries (USDCAD,H1)     [2] - United States
CK      0       23:05:18.618    Test_get_countries (USDCAD,H1)     [3] - Mexico
GL      0       23:05:18.619    Test_get_countries (USDCAD,H1)     Continent "South America" includes 1 country(-ies):
EQ      0       23:05:18.619    Test_get_countries (USDCAD,H1)     [1] - Brazil
DH      0       23:05:18.622    Test_get_countries (USDCAD,H1)     Continent "World" includes 1 country(-ies):
JK      0       23:05:18.622    Test_get_countries (USDCAD,H1)     [1] - Worldwide
QM      0       23:05:18.622    Test_get_countries (USDCAD,H1)  
KH      0       23:05:18.622    Test_get_countries (USDCAD,H1)  ---== Country ==---
PQ      0       23:05:18.622    Test_get_countries (USDCAD,H1)     Name: Russian Federation
KG      0       23:05:18.622    Test_get_countries (USDCAD,H1)     Code: RU
MR      0       23:05:18.622    Test_get_countries (USDCAD,H1)     Continent enum: CONTINENT_EUROPE
MI      0       23:05:18.622    Test_get_countries (USDCAD,H1)     Continent description: Europe

故此,当前日历的版本所描述的事件,均与位于七大洲的 23 个国家经济相关(前提是参考“World(世界)”常数)。 


2.3.7  获取事件数据的方法

这些方法允许根据特定标准选择事件。 

The CiCalendarInfo::GetEventsByName(CArrayString &events_arr, const string name = NULL) 方法会执行一次选择,选出结果作为字符串类型变量的动态数组。 选择标准是事件名称。

CiCalendarInfo::GetEventsByName(MqlCalendarEvent & events[], const string name = NULL) 方法与之前的方法类似。 唯一的区别是,它在执行选择的时候是以 MqlCalendarCountry 类型变量数组的形式。 

CiCalendarInfo::FilterEvents(MqlCalendarEvent &filtered_events[], MqlCalendarEvent &src_events[], const ulong filter) method also 执行选择,结果作为  MqlCalendarCountry 类型变量的数组。 此处已在一组标志中实现了多个标准。 总共有 49 个这样的标准。 它们涵盖所有枚举值: ENUM_CALENDAR_EVENT_TYPE, ENUM_CALENDAR_EVENT_SECTOR, ENUM_CALENDAR_EVENT_FREQUENCY, ENUM_CALENDAR_EVENT_TIMEMODE, ENUM_CALENDAR_EVENT_UNIT, ENUM_CALENDAR_EVENT_IMPORTANCE, ENUM_CALENDAR_EVENT_MULTIPLI。

由于 “enum” 类型是4 字节的数据类型(32 位),故这种情况需要 49 位,因此创建一个新的包罗万象的元枚举似乎是不可能的。 另一方面,“long” 类型提供 64 位。

以下代码用于解决此问题:

//--- defines for events filtering
//--- 1) type (3)
#define FILTER_BY_TYPE_EVENT           0x1              // 1 by type "event"
#define FILTER_BY_TYPE_INDICATOR       0x2              // 2 by type "indicator"
#define FILTER_BY_TYPE_HOLIDAY         0x4              // 3 by type "holiday"
//--- 2) sector (13)
#define FILTER_BY_SECTOR_NONE          0x8              // 4 by sector "none"
#define FILTER_BY_SECTOR_MARKET        0x10             // 5 by sector "market"
#define FILTER_BY_SECTOR_GDP           0x20             // 6 by sector "GDP"
#define FILTER_BY_SECTOR_JOBS          0x40             // 7 by sector "jobs"
#define FILTER_BY_SECTOR_PRICES        0x80             // 8 by sector "prices"
#define FILTER_BY_SECTOR_MONEY         0x100            // 9 by sector "money"
#define FILTER_BY_SECTOR_TRADE         0x200            // 10 by sector "trade"
#define FILTER_BY_SECTOR_GOVERNMENT    0x400            // 11 by sector "government"
#define FILTER_BY_SECTOR_BUSINESS      0x800            // 12 by sector "business"
#define FILTER_BY_SECTOR_CONSUMER      0x1000           // 13 by sector "consumer"
#define FILTER_BY_SECTOR_HOUSING       0x2000           // 14 by sector "housing"
#define FILTER_BY_SECTOR_TAXES         0x4000           // 15 by sector "taxes"
#define FILTER_BY_SECTOR_HOLIDAYS      0x8000           // 16 by sector "holidays"
//--- 3) frequency (6)
#define FILTER_BY_FREQUENCY_NONE       0x10000          // 17 by frequency "none"
#define FILTER_BY_FREQUENCY_WEEK       0x20000          // 18 by frequency "week"
#define FILTER_BY_FREQUENCY_MONTH      0x40000          // 19 by frequency "month"
#define FILTER_BY_FREQUENCY_QUARTER    0x80000          // 20 by frequency "quarter"
#define FILTER_BY_FREQUENCY_YEAR       0x100000         // 21 by frequency "year"
#define FILTER_BY_FREQUENCY_DAY        0x200000         // 22 by frequency "day"
//--- 4) importance (4)
#define FILTER_BY_IMPORTANCE_NONE      0x400000         // 23 by importance "none"
#define FILTER_BY_IMPORTANCE_LOW       0x800000         // 24 by importance "low"
#define FILTER_BY_IMPORTANCE_MODERATE  0x1000000        // 25 by importance "medium"
#define FILTER_BY_IMPORTANCE_HIGH      0x2000000        // 26 by importance "high"
//--- 5) unit (14)
#define FILTER_BY_UNIT_NONE            0x4000000        // 27 by unit "none"
#define FILTER_BY_UNIT_PERCENT         0x8000000        // 28 by unit "percentage"
#define FILTER_BY_UNIT_CURRENCY        0x10000000       // 29 by unit "currency"
#define FILTER_BY_UNIT_HOUR            0x20000000       // 30 by unit "hours"
#define FILTER_BY_UNIT_JOB             0x40000000       // 31 by unit "jobs"
#define FILTER_BY_UNIT_RIG             0x80000000       // 32 by unit "drilling rigs"
#define FILTER_BY_UNIT_USD             0x100000000      // 33 by unit "USD"
#define FILTER_BY_UNIT_PEOPLE          0x200000000      // 34 by unit "people"
#define FILTER_BY_UNIT_MORTGAGE        0x400000000      // 35 by unit "mortgage loans"
#define FILTER_BY_UNIT_VOTE            0x800000000      // 36 by unit "votes"
#define FILTER_BY_UNIT_BARREL          0x1000000000     // 37 by unit "barrels"
#define FILTER_BY_UNIT_CUBICFEET       0x2000000000     // 38 by unit "cubic feet"
#define FILTER_BY_UNIT_POSITION        0x4000000000     // 39 by unit "net positions"
#define FILTER_BY_UNIT_BUILDING        0x8000000000     // 40 by unit "buildings"
//--- 6) multiplier (5)
#define FILTER_BY_MULTIPLIER_NONE      0x10000000000    // 41 by multiplier "none"
#define FILTER_BY_MULTIPLIER_THOUSANDS 0x20000000000    // 42 by multiplier "thousands"
#define FILTER_BY_MULTIPLIER_MILLIONS  0x40000000000    // 43 by multiplier "millions"
#define FILTER_BY_MULTIPLIER_BILLIONS  0x80000000000    // 44 by multiplier "billions"
#define FILTER_BY_MULTIPLIER_TRILLIONS 0x100000000000   // 45 by multiplier "trillions"
//--- 7) time mode (4)
#define FILTER_BY_TIMEMODE_DATETIME    0x200000000000   // 46 by time mode "na"
#define FILTER_BY_TIMEMODE_DATE        0x400000000000   // 47 by time mode "positive"
#define FILTER_BY_TIMEMODE_NOTIME      0x800000000000   // 48 by time mode "negative"
#define FILTER_BY_TIMEMODE_TENTATIVE   0x1000000000000  // 49 by time mode "na"
//--- type
#define IS_TYPE_EVENT(filter) ((filter&FILTER_BY_TYPE_EVENT)!=0)
#define IS_TYPE_INDICATOR(filter) ((filter&FILTER_BY_TYPE_INDICATOR)!=0)
#define IS_TYPE_HOLIDAY(filter) ((filter&FILTER_BY_TYPE_HOLIDAY)!=0)
//--- sector
#define IS_SECTOR_NONE(filter) ((filter&FILTER_BY_SECTOR_NONE)!=0)
#define IS_SECTOR_MARKET(filter) ((filter&FILTER_BY_SECTOR_MARKET)!=0)
#define IS_SECTOR_GDP(filter) ((filter&FILTER_BY_SECTOR_GDP)!=0)
#define IS_SECTOR_JOBS(filter) ((filter&FILTER_BY_SECTOR_JOBS)!=0)
#define IS_SECTOR_PRICES(filter) ((filter&FILTER_BY_SECTOR_PRICES)!=0)
#define IS_SECTOR_MONEY(filter) ((filter&FILTER_BY_SECTOR_MONEY)!=0)
#define IS_SECTOR_TRADE(filter) ((filter&FILTER_BY_SECTOR_TRADE)!=0)
#define IS_SECTOR_CONSUMER(filter) ((filter&FILTER_BY_SECTOR_CONSUMER)!=0)
#define IS_SECTOR_HOUSING(filter) ((filter&FILTER_BY_SECTOR_HOUSING)!=0)
#define IS_SECTOR_TAXES(filter) ((filter&FILTER_BY_SECTOR_TAXES)!=0)
#define IS_SECTOR_HOLIDAYS(filter) ((filter&FILTER_BY_SECTOR_HOLIDAYS)!=0)
//--- frequency
#define IS_FREQUENCY_NONE(filter) ((filter&FILTER_BY_FREQUENCY_NONE)!=0)
#define IS_FREQUENCY_WEEK(filter) ((filter&FILTER_BY_FREQUENCY_WEEK)!=0)
#define IS_FREQUENCY_MONTH(filter) ((filter&FILTER_BY_FREQUENCY_MONTH)!=0)
#define IS_FREQUENCY_QUARTER(filter) ((filter&FILTER_BY_FREQUENCY_QUARTER)!=0)
#define IS_FREQUENCY_YEAR(filter) ((filter&FILTER_BY_FREQUENCY_YEAR)!=0)
#define IS_FREQUENCY_DAY(filter) ((filter&FILTER_BY_FREQUENCY_DAY)!=0)
//--- importance
#define IS_IMPORTANCE_NONE(filter) ((filter&FILTER_BY_IMPORTANCE_NONE)!=0)
#define IS_IMPORTANCE_LOW(filter) ((filter&FILTER_BY_IMPORTANCE_LOW)!=0)
#define IS_IMPORTANCE_MODERATE(filter) ((filter&FILTER_BY_IMPORTANCE_MODERATE)!=0)
#define IS_IMPORTANCE_HIGH(filter) ((filter&FILTER_BY_IMPORTANCE_HIGH)!=0)
//--- unit
#define IS_UNIT_NONE(filter) ((filter&FILTER_BY_UNIT_NONE)!=0)
#define IS_UNIT_PERCENT(filter) ((filter&FILTER_BY_UNIT_PERCENT)!=0)
#define IS_UNIT_CURRENCY(filter) ((filter&FILTER_BY_UNIT_CURRENCY)!=0)
#define IS_UNIT_HOUR(filter) ((filter&FILTER_BY_UNIT_HOUR)!=0)
#define IS_UNIT_JOB(filter) ((filter&FILTER_BY_UNIT_JOB)!=0)
#define IS_UNIT_RIG(filter) ((filter&FILTER_BY_UNIT_RIG)!=0)
#define IS_UNIT_USD(filter) ((filter&FILTER_BY_UNIT_USD)!=0)
#define IS_UNIT_PEOPLE(filter) ((filter&FILTER_BY_UNIT_PEOPLE)!=0)
#define IS_UNIT_MORTGAGE(filter) ((filter&FILTER_BY_UNIT_MORTGAGE)!=0)
#define IS_UNIT_VOTE(filter) ((filter&FILTER_BY_UNIT_VOTE)!=0)
#define IS_UNIT_BARREL(filter) ((filter&FILTER_BY_UNIT_BARREL)!=0)
#define IS_UNIT_CUBICFEET(filter) ((filter&FILTER_BY_UNIT_CUBICFEET)!=0)
#define IS_UNIT_POSITION(filter) ((filter&FILTER_BY_UNIT_POSITION)!=0)
#define IS_UNIT_BUILDING(filter) ((filter&FILTER_BY_UNIT_BUILDING)!=0)
//--- multiplier
#define IS_MULTIPLIER_NONE(filter) ((filter&FILTER_BY_MULTIPLIER_NONE)!=0)
#define IS_MULTIPLIER_THOUSANDS(filter) ((filter&FILTER_BY_MULTIPLIER_THOUSANDS)!=0)
#define IS_MULTIPLIER_MILLIONS(filter) ((filter&FILTER_BY_MULTIPLIER_MILLIONS)!=0)
#define IS_MULTIPLIER_BILLIONS(filter) ((filter&FILTER_BY_MULTIPLIER_BILLIONS)!=0)
#define IS_MULTIPLIER_TRILLIONS(filter) ((filter&FILTER_BY_MULTIPLIER_TRILLIONS)!=0)
//--- time mode
#define IS_TIMEMODE_DATETIME(filter) ((filter&FILTER_BY_TIMEMODE_DATETIME)!=0)
#define IS_TIMEMODE_DATE(filter) ((filter&FILTER_BY_TIMEMODE_DATE)!=0)
#define IS_TIMEMODE_NOTIME(filter) ((filter&FILTER_BY_TIMEMODE_NOTIME)!=0)
#define IS_TIMEMODE_TENTATIVE(filter) ((filter&FILTER_BY_TIMEMODE_TENTATIVE)!=0)

我们来看一看测试示例 - Test_filter_events.mq5 脚本。 首先,为指定的 EUR 创建日历对象。

接下来,在模块 1中,选择所有与 EUR 相关,且名称中有 “Unemployment(失业)”字样的事件。 这类事件共有 33 条。 事件名称被发送到字符串类型变量的动态数组。

模块 2 中,执行相同操作,填充 MqlCalendarEvent 类型数组。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   CiCalendarInfo event_calendar_info;
   if(event_calendar_info.Init("EUR"))
     {
      //--- 1) get events by name (CArrayString)
      CArrayString events_arr;
      string ev_name = "Unemployment";
      if(event_calendar_info.GetEventsByName(events_arr, ev_name))
        {
         int events_num = events_arr.Total();
         if(events_num > 0)
           {
            ::Print("\n---== CArrayString list ==---");
            ::PrintFormat("   Events list consists of %d events.", events_num);
            ::PrintFormat("   First event: %s", events_arr.At(0));
            ::PrintFormat("   Last event: %s", events_arr.At(events_num - 1));
           }
        }
      //--- 2) get events by name (MqlCalendarEvent)
      MqlCalendarEvent events[];
      if(event_calendar_info.GetEventsByName(events, ev_name))
        {
         int events_num = ::ArraySize(events);
         if(events_num > 0)
           {
            ::Print("\n---== MqlCalendarEvent array ==---");
            ::PrintFormat("   Events array consists of %d events.", events_num);
            ::PrintFormat("   First event: %s", events[0].name);
            ::PrintFormat("   Last event: %s", events[events_num - 1].name);
           }
        }
      //--- 3) filter events
      MqlCalendarEvent filtered_events[];
      int indices[2];
      indices[0] = 0;
      string events_str[2];
      events_str[0] = "First";
      events_str[1] = "Last";
      ulong filter = 0;
      filter |= FILTER_BY_IMPORTANCE_HIGH;
      if(event_calendar_info.FilterEvents(filtered_events, events, filter))
        {
         int f_events_num = ::ArraySize(filtered_events);
         ::Print("\n---== Filtered events array ==---");
         ::Print("   Filtered by: importance high");
         ::PrintFormat("   Events array consists of %d events.", ::ArraySize(filtered_events));
         if(f_events_num > 0)
           {
            indices[1] = f_events_num - 1;
            for(int ind = 0; ind <::ArraySize(indices); ind++)
              {
               MqlCalendarEvent curr_event = filtered_events[indices[ind]];
               ::PrintFormat("   \n%s event:", events_str[ind]);
               event_calendar_info.PrintEventDescription(curr_event);
              }
           }
         ::ArrayFree(filtered_events);
         filter ^= FILTER_BY_IMPORTANCE_HIGH;
        }
      filter |= FILTER_BY_IMPORTANCE_MODERATE;
      if(event_calendar_info.FilterEvents(filtered_events, events, filter))
        {
         int f_events_num = ::ArraySize(filtered_events);
         ::Print("\n---== Filtered events array ==---");
         ::Print("   Filtered by: importance medium");
         ::PrintFormat("   Events array consists of %d events.", ::ArraySize(filtered_events));
         if(f_events_num > 0)
           {
            indices[1] = f_events_num - 1;
            for(int ind = 0; ind <::ArraySize(indices); ind++)
              {
               MqlCalendarEvent curr_event = filtered_events[indices[ind]];
               ::PrintFormat("   \n%s event:", events_str[ind]);
               event_calendar_info.PrintEventDescription(curr_event);
              }
           }
         ::ArrayFree(filtered_events);
         filter ^= FILTER_BY_IMPORTANCE_MODERATE;
        }
      filter |= FILTER_BY_IMPORTANCE_LOW;
      if(event_calendar_info.FilterEvents(filtered_events, events, filter))
        {
         int f_events_num = ::ArraySize(filtered_events);
         ::Print("\n---== Filtered events array ==---");
         ::Print("   Filtered by: importance low");
         ::PrintFormat("   Events array consists of %d events.", ::ArraySize(filtered_events));
         if(f_events_num > 0)
           {
            indices[1] = f_events_num - 1;
            for(int ind = 0; ind <::ArraySize(indices); ind++)
              {
               MqlCalendarEvent curr_event = filtered_events[indices[ind]];
               ::PrintFormat("   \n%s event:", events_str[ind]);
               event_calendar_info.PrintEventDescription(curr_event);
              }
           }
         ::ArrayFree(filtered_events);
         filter ^= FILTER_BY_IMPORTANCE_LOW;
        }
      filter |= FILTER_BY_IMPORTANCE_NONE;
      if(event_calendar_info.FilterEvents(filtered_events, events, filter))
        {
         int f_events_num = ::ArraySize(filtered_events);
         ::Print("\n---== Filtered events array ==---");
         ::Print("   Filtered by: importance none");
         ::PrintFormat("   Events array consists of %d events.", ::ArraySize(filtered_events));
         if(f_events_num > 0)
           {
            indices[1] = f_events_num - 1;
            for(int ind = 0; ind <::ArraySize(indices); ind++)
              {
               MqlCalendarEvent curr_event = filtered_events[indices[ind]];
               ::PrintFormat("   \n%s event:", events_str[ind]);
               event_calendar_info.PrintEventDescription(curr_event);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+

模块 3 中,根据事件的重要性进行分类。 首先,我们看看前面按名称选择的 33 条事件中有多少是重要的。 事实证明,它们都不是。 27 条事件为中等重要,6 条事件为低等重要。 此外,还有 0 条未指定重要级别的事件。 

日志的内容如下:

JL      0       13:18:48.419    Test_filter_events (USDCAD,H1)  
FM      0       13:18:48.421    Test_filter_events (USDCAD,H1)  ---== New Calendar Info object ==---
JP      0       13:18:48.421    Test_filter_events (USDCAD,H1)     Currency: EUR
CE      0       13:18:48.630    Test_filter_events (USDCAD,H1)  
EL      0       13:18:48.631    Test_filter_events (USDCAD,H1)  ---== CArrayString list ==---
IF      0       13:18:48.631    Test_filter_events (USDCAD,H1)     Events list consists of 33 events.
MQ      0       13:18:48.631    Test_filter_events (USDCAD,H1)     First event: Unemployment Rate
RK      0       13:18:48.631    Test_filter_events (USDCAD,H1)     Last event: NAV Unemployment Change
HF      0       13:18:48.635    Test_filter_events (USDCAD,H1)  
OR      0       13:18:48.635    Test_filter_events (USDCAD,H1)  ---== MqlCalendarEvent array ==---
JH      0       13:18:48.635    Test_filter_events (USDCAD,H1)     Events array consists of 33 events.
ER      0       13:18:48.635    Test_filter_events (USDCAD,H1)     First event: Unemployment Rate
JM      0       13:18:48.635    Test_filter_events (USDCAD,H1)     Last event: NAV Unemployment Change
DH      0       13:18:48.635    Test_filter_events (USDCAD,H1)  
CR      0       13:18:48.635    Test_filter_events (USDCAD,H1)  ---== Filtered events array ==---
HH      0       13:18:48.635    Test_filter_events (USDCAD,H1)     Filtered by: importance high
DO      0       13:18:48.635    Test_filter_events (USDCAD,H1)     Events array consists of 0 events.
CN      0       13:18:48.636    Test_filter_events (USDCAD,H1)  
PI      0       13:18:48.636    Test_filter_events (USDCAD,H1)  ---== Filtered events array ==---
NO      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Filtered by: importance medium
PE      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Events array consists of 27 events.
KG      0       13:18:48.636    Test_filter_events (USDCAD,H1)     
KI      0       13:18:48.636    Test_filter_events (USDCAD,H1)  First event:
IS      0       13:18:48.636    Test_filter_events (USDCAD,H1)  
EJ      0       13:18:48.636    Test_filter_events (USDCAD,H1)  ---== Event description ==---
JF      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Id: 999030020
DP      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Type: Indicator
KJ      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Sector: Labor market
JM      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Frequency: Monthly
QJ      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Time mode: Exact time
CN      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Country id: 999
KK      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Unit: Percentage
JP      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Importance: Moderate
JH      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Multiplier: None
JF      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Digits: 1
PL      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Source URL: https://ec.europa.eu/eurostat
NH      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Event code: unemployment-rate
MQ      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Name: Unemployment Rate
GI      0       13:18:48.636    Test_filter_events (USDCAD,H1)     
OO      0       13:18:48.636    Test_filter_events (USDCAD,H1)  Last event:
OJ      0       13:18:48.636    Test_filter_events (USDCAD,H1)  
OP      0       13:18:48.636    Test_filter_events (USDCAD,H1)  ---== Event description ==---
QH      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Id: 578040001
NO      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Type: Indicator
ID      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Sector: Labor market
DF      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Frequency: Monthly
KS      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Time mode: Exact time
LI      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Country id: 578
QR      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Unit: Percentage
LJ      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Importance: Moderate
DQ      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Multiplier: None
LH      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Digits: 1
IS      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Source URL: https://www.nav.no/en/Home
EQ      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Event code: nav-unemployment-rate-nsa
PJ      0       13:18:48.636    Test_filter_events (USDCAD,H1)     Name: NAV Unemployment Rate n.s.a.
ED      0       13:18:48.636    Test_filter_events (USDCAD,H1)  
FF      0       13:18:48.636    Test_filter_events (USDCAD,H1)  ---== Filtered events array ==---
PK      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Filtered by: importance low
JS      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Events array consists of 6 events.
FH      0       13:18:48.637    Test_filter_events (USDCAD,H1)     
FS      0       13:18:48.637    Test_filter_events (USDCAD,H1)  First event:
LI      0       13:18:48.637    Test_filter_events (USDCAD,H1)  
LO      0       13:18:48.637    Test_filter_events (USDCAD,H1)  ---== Event description ==---
EK      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Id: 276060003
IM      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Type: Indicator
FE      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Sector: Labor market
OP      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Frequency: Monthly
HQ      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Time mode: Exact time
HH      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Country id: 276
KM      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Unit: People
DJ      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Importance: Low
RM      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Multiplier: Millions
KJ      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Digits: 3
LS      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Source URL: https://www.arbeitsagentur.de/en/welcome
MN      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Event code: unemployment-nsa
ND      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Name: Unemployment n.s.a.
LP      0       13:18:48.637    Test_filter_events (USDCAD,H1)     
LE      0       13:18:48.637    Test_filter_events (USDCAD,H1)  Last event:
DP      0       13:18:48.637    Test_filter_events (USDCAD,H1)  
DG      0       13:18:48.637    Test_filter_events (USDCAD,H1)  ---== Event description ==---
CS      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Id: 578040002
QE      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Type: Indicator
NM      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Sector: Labor market
GH      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Frequency: Monthly
PI      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Time mode: Exact time
GS      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Country id: 578
CE      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Unit: People
LS      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Importance: Low
HJ      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Multiplier: Thousands
QR      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Digits: 3
NI      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Source URL: https://www.nav.no/en/Home
MQ      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Event code: nav-unemployment-change
ES      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Name: NAV Unemployment Change
PI      0       13:18:48.637    Test_filter_events (USDCAD,H1)  
CS      0       13:18:48.637    Test_filter_events (USDCAD,H1)  ---== Filtered events array ==---
DK      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Filtered by: importance none
DH      0       13:18:48.637    Test_filter_events (USDCAD,H1)     Events array consists of 0 events.

正如我曾提及的,选择事件有 49 条标准。 它们即可组合使用,也可以单独使用。


3. 非商用净持仓指标

财经日历容纳了许多不同的事件。 我已选择了一个其中最引人注目的事件 — 商品期货交易委员会(CFTC)的每周报告,该报告展示了多头和空头持仓总量之间的差值。 

我们来创建一个指标,在图表的单独窗口中显示所选商品资产的数据。

共有 11 项此类资产。 创建以下枚举:

//+------------------------------------------------------------------+
//| CFTC Non-Commercial Net Positions                                |
//+------------------------------------------------------------------+
enum ENUM_NON_COM_NET_POSITIONS
  {
   NON_COM_NET_POSITIONS_COPPER = 0,      // Copper
   NON_COM_NET_POSITIONS_SILVER = 1,      // Silver
   NON_COM_NET_POSITIONS_GOLD = 2,        // Gold
   NON_COM_NET_POSITIONS_CRUDE_OIL = 3,   // Crude oil
   NON_COM_NET_POSITIONS_SP_500 = 4,      // S&P 500
   NON_COM_NET_POSITIONS_AlUMINIUM = 5,   // Aluminium
   NON_COM_NET_POSITIONS_CORN = 6,        // Corn
   NON_COM_NET_POSITIONS_NGAS = 7,        // Natural gas
   NON_COM_NET_POSITIONS_SOYBEANS = 8,    // Soybeans
   NON_COM_NET_POSITIONS_WHEAT = 9,       // Wheat
   NON_COM_NET_POSITIONS_NASDAQ_100 = 10, // Nasdaq 100
  };

该指标用于显示前值,并检测新值。 对于第一个任务,我决定在 OnCalculate() 响应程序中采用以下代码模块:

//--- first call
if(prev_calculated == 0)
  {
//--- initialize buffer
   ::ArrayInitialize(gBuffer, EMPTY_VALUE);
//--- 1) collect all events by country
   ulong country_id = 840; // US
   if(gPtrEventsInfo.Init(NULL, country_id))
     {
      MqlCalendarEvent events[];
      if(gPtrEventsInfo.EventsByCountryDescription(events, false))
        {
         string event_code_substr = GetEventCodeSubstring();
         if(event_code_substr != NULL)
            for(int ev_idx = 0; ev_idx <::ArraySize(events); ev_idx++)
              {
               MqlCalendarEvent curr_event = events[ev_idx];
               if(::StringFind(curr_event.event_code, event_code_substr) > -1)
                 {
                  //--- 2) collect all values by event id
                  if(gPtrValuesInfo.Init(NULL, WRONG_VALUE, curr_event.id))
                    {
                     SiTimeSeries net_positions_ts;
                     if(gPtrValuesInfo.ValueHistorySelectByEvent(net_positions_ts, 0))
                       {
                        string net_positions_name;
                        SiTsObservation ts_observations[];
                        if(net_positions_ts.GetSeries(ts_observations, net_positions_name))
                          {
                           //--- consider only past observations
                           int new_size = 0;
                           for(int obs_idx =::ArraySize(ts_observations) - 1; obs_idx >= 0; obs_idx--)
                             {
                              if(ts_observations[obs_idx].val != EMPTY_VALUE)
                                 break;
                              new_size = obs_idx;
                             }
                           if(new_size > 0)
                              ::ArrayResize(ts_observations, new_size);
                           //--- find the starting date
                           datetime start_dtime, ts_start_dtime;
                           start_dtime = time[0];
                           ts_start_dtime = ts_observations[0].time;
                           if(ts_start_dtime > start_dtime)
                              start_dtime = ts_start_dtime;
                           ::IndicatorSetString(INDICATOR_SHORTNAME, net_positions_name);
                           ::IndicatorSetInteger(INDICATOR_DIGITS, 1);
                           //---
                           int start_bar_idx =::iBarShift(_Symbol, _Period, ts_start_dtime);
                           if(start_bar_idx > -1)
                             {
                              start_bar_idx = rates_total - start_bar_idx;
                              uint observations_cnt = 0;
                              SiTsObservation curr_observation = ts_observations[observations_cnt];
                              uint ts_size = ::ArraySize(ts_observations);
                              for(int bar = start_bar_idx; bar < rates_total; bar++)
                                {
                                 if((observations_cnt + 1) < ts_size)
                                   {
                                    SiTsObservation next_observation =
                                       ts_observations[observations_cnt + 1];
                                    if(time[bar] >= next_observation.time)
                                      {
                                       curr_observation = next_observation;
                                       gLastValueDate = curr_observation.time;
                                       gLastValue = curr_observation.val;
                                       observations_cnt++;
                                      }
                                   }
                                 gBuffer[bar] = curr_observation.val;
                                }
                              //--- just to get a change id
                              MqlCalendarValue values[];
                              gPtrValuesInfo.ValueLastSelectByEvent(gChangeId, values);
                             }
                          }
                       }
                    }
                  break;
                 }
              }
        }
     }
  }

在该模块中初始化第一个日历对象。 我只指明一个国家识别码  USA。 接下来,选择所有国家/地区事件,并通过输入变量中设置的事件代码检测所需的资产。 然后,初始化第二个日历对象,并请求历史记录。 接下来,填充指标缓冲区。

第二个模块则在 OnCalculate() 响应程序中检测新值:

MqlCalendarValue values[];
if(gPtrValuesInfo.ValueLastSelectByEvent(gChangeId, values) > 0)
   if(values[0].time > gLastValueDate)
     {
      gLastValueDate = values[0].time;
      gLastValue = values[0].GetActualValue();
      //--- to log
      if(InpTpLog)
        {
         ::Print("\n---== New event value ==---");
         ::PrintFormat("   Time: %s", ::TimeToString(gLastValueDate));
         datetime server_time =::TimeTradeServer();
         ::PrintFormat("   Release time: %s", ::TimeToString(server_time));
         ::PrintFormat("   Actual value: %0.1f", gLastValue);
        }
     }
//--- if a new bar
if(rates_total > prev_calculated)
   for(int bar = prev_calculated; bar < rates_total; bar++)
      gBuffer[bar] = gLastValue;

结果应类似于下图(图例 3)。


CFTC S&P 500 非商用净持仓

图例 3. CFTC S&P 500 非商用净持仓

在指标代码中,我们可以看到,由于指标中全局变量被重新初始化,故日历对象是动态创建的。


结束语

在本文中,我创建了日历对象类 该类用于简化对日历属性和接收事件值的访问。 日历数据库非常广泛,可以分析重要的财经事件,而无需借助第三方资源。

存档文件包含本文中用到的源代码。 在我的电脑上,所有文件和文件夹都位于 %MQL5\Shared Projects\Testing\Calendar 之中。 如果您的源目录定位不同,请注意正确使用 #include 指令包含 CalendarInfo.mqh 头文件。

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

附加的文件 |
Code.zip (31.04 KB)
最近评论 | 前往讨论 (3)
熙雅 张
熙雅 张 | 28 1月 2022 在 18:56
MetaQuotes:

新文章 MQL5 酷宝书 – 财经日历已发布:

作者:Denis Kirichenko

熙雅 张
熙雅 张 | 28 1月 2022 在 18:56
MetaQuotes:

新文章 MQL5 酷宝书 – 财经日历已发布:

作者:Denis Kirichenko

受益匪淺
Tao Lu
Tao Lu | 1 2月 2022 在 13:50
Thank you.
手工制图表和交易工具箱(第三部分)。 优化和全新工具 手工制图表和交易工具箱(第三部分)。 优化和全新工具
在本文中,我们将深入开发利用键盘快捷键在图表上绘制图形对象的设想。 全新工具已被加到函数库当中了,包括一条贯穿任意顶点绘制的直线,以及一组能够评估逆转时间和价位的矩形。 此外,本文还展示了优化代码从而提高性能的可能性。 实现示例已经重写,能够使用其它交易程序的快捷方式。 所需的代码知识水平:略高于初学者。
开发 EA 构造函数的一次尝试 开发 EA 构造函数的一次尝试
在本文中,我把自己的一套交易函数以成品 EA 的形式提供给大家。 这种方法能够通过简单地添加指标和改变输入来获得多种交易策略。
处理时间(第二部分):函数 处理时间(第二部分):函数
自动判定经纪商时移和 GMT。 与其请求您的经纪商的支持,您可能会从他们那里得到一个不充分的答案(他们很愿意解释时间错位),我们只需自行查看在时间变化的几周内他们如何计算价格 — 但手工操作极其繁琐,我们让程序来做这件事 — 毕竟这就是为什么我们要有一台 PC。
处理时间(第一部分):基础 处理时间(第一部分):基础
能够简化和澄清时间、经纪商时移、以及夏季或冬季变更的时间处理函数和代码片段。 准确的时序也许是交易中的一个关键因素。 在当前钟点,伦敦或纽约的证券交易所是否已经或尚未开市,外汇交易的交易时间何时开始和结束? 对于一名实况手工交易者来说,这不算是个大问题。