数组的日志记录

若要通知用户、进行调试以及诊断问题,最简单的方式就是将变量、数组和有关 MQL 程序状态的消息打印到日志。至于数组,我们可以使用 Print 函数实现逐元素打印,我们已从演示脚本了解了该函数。稍后我们将在关于 与用户交互的章节正式描述该函数。

然而,将与元素迭代及其准确格式设置相关的整个例行程序委托给 MQL5 环境会更加方便。为此,API 提供了特殊的 ArrayPrint 函数。

我们已在 使用数组 章节了解了该函数的使用示例。现在我们深入探讨其功能。

void ArrayPrint(const void &array[], uint digits = _Digits, const string separator = NULL,
ulong start = 0, ulong count = WHOLE_ARRAY,
ulong flags = ARRAYPRINT_HEADER | ARRAYPRINT_INDEX | ARRAYPRINT_LIMIT | ARRAYPRINT_DATE | ARRAYPRINT_SECONDS)

该函数使用指定设置将一个数组记录到日志。该数组必须是内置类型之一或者是简单结构体类型。简单结构体是具有内置类型字段的结构体,字符串和动态数组除外。如果结构体组成中存在类对象和指针,则不属于简单类别。

数组必须具有维度 1 或 2。格式设置自动调整为数组配置,如果可能,以可视化形式显示(见下文)。尽管 MQL5 支持具有最多 4 个维度的数组,但该函数不显示具有 3 个或以上维度的数组,因为很难以平面形态表示这种数组。这种行为在程序编译或执行阶段不会引发错误。

除了第一个参数外,其他参数都可以省略,并为它们定义了默认值。

digits 参数用于实数数组以及结构体的数字字段。该参数设置数字小数部分显示的字符数。默认值是 预定义图表变量之一,即 _Digits,这是当前图表的交易品种价格中的小数位数。

分隔字符 separator 用于指定在结构体数组中显示字段时的列。在默认值 (NULL) 情况下,该函数使用空格作为分隔符。

startcount 参数分别设置起始元素编号以及要打印的元素数量。默认情况下,该函数打印整个数组,但结果可能还会受到 ARRAYPRINT_LIMIT 标志的影响(见下文)。

flags 参数接受组合使用影响各种显示特性的标志。其中一些标志如下:

  • ARRAYPRINT_HEADER 在结构体数组之前输出头部(其中包含结构体字段名称);该标志不影响非结构体数组。
  • ARRAYPRINT_INDEX 按维度输出元素索引(对于一维数组,索引显示在左边,对于二维数组,索引显示在左边和上方)。
  • ARRAYPRINT_LIMIT 用于大数组,输出限于前一百条和后一百条记录(默认启用此限制)。
  • ARRAYPRINT_DATE 用于 datetime 类型的值以显示日期。
  • ARRAYPRINT_MINUTES 用于 datetime 类型的值以显示时间到最近分钟数。
  • ARRAYPRINT_SECONDS 用于 datetime 类型的值以显示时间到最近秒数。

默认情况下, datetime 类型的值以 ARRAYPRINT_DATE | ARRAYPRINT_SECONDS 格式输出。

color 类型的值以十六进制格式输出。

枚举值显示为整数。

该函数不输出嵌套数组、结构体和对象指针。而是显示三个点代替。

ArrayPrint.mq5 脚本演示了该函数的工作方式。

OnStart 函数提供了若干数组(一维、二维、三维)的定义,这些数组使用 ArrayPrint(采用默认设置)输出。

void OnStart()
{
   int array1D[] = {12345678910};
   double array2D[][5] = {{12345}, {678910}};
   double array3D[][3][5] =
   {
      {{ 1,  2,  3,  4,  5}, { 6,  7,  8,  910}, {1112131415}},
      {{1617181920}, {2122232425}, {2627282930}},
   };
   
   Print("array1D");
   ArrayPrint(array1D);
   Print("array2D");
   ArrayPrint(array2D);
   Print("array3D");
   ArrayPrint(array3D);
   ...
}

我们将在日志中获得以下行:

array1D
 1  2  3  4  5  6  7  8  9 10
array2D
         [,0]     [,1]     [,2]     [,3]     [,4]
[0,]  1.00000  2.00000  3.00000  4.00000  5.00000
[1,]  6.00000  7.00000  8.00000  9.00000 10.00000
array3D

array1D 数组不够大(可以放入一行中),因此未显示它的索引。

array2D 数组有多行(索引),因此显示它们的索引(默认启用 ARRAYPRINT_INDEX)。

请注意,由于是对包含五位数价格 _Digits=5 的 EURUSD 图表运行脚本,其影响 double 类型值的格式设置。

array3D 数组被忽略:不输出它的行。

此外,PairSimpleStruct 结构体在脚本中定义:

struct Pair
{
   int xy;
};
   
struct SimpleStruct
{
   double value;
   datetime time;
   int count;
   ENUM_APPLIED_PRICE price;
   color clr;
   string details;
   void *ptr;
   Pair pair;
};

SimpleStruct 包含内置类型字段、一个 void 指针,以及一个 Pair 类型的字段。

OnStart 函数中,使用 ArrayPrint 以两种模式创建并输出一个 SimpleStruct 类型的数组:以默认设置和自定义设置两种模式(“逗号”之后的数位数是 3,分隔符是 ";",datetime 的格式是“仅日期”)。

void OnStart()
{
   ...
   SimpleStruct simple[] =
   {
      { 12.57839D'2021.07.23 11:15', 22345PRICE_MEDIANclrBlue"text message"},
      {135.82949D'2021.06.20 23:45', 8569PRICE_TYPICALclrAzure},
      { 1087.576D'2021.05.15 10:01:30', -3298PRICE_WEIGHTEDclrYellow"note"},
   };
   Print("SimpleStruct (default)");
   ArrayPrint(simple);
   
   Print("SimpleStruct (custom)");
   ArrayPrint(simple3";"0WHOLE_ARRAYARRAYPRINT_DATE);
}

这将生成以下结果:

SimpleStruct (default)
       [value]              [time] [count] [type]    [clr]      [details] [ptr] [pair]
[0]   12.57839 2021.07.23 11:15:00   22345      5 00FF0000 "text message"   ...    ...
[1]  135.82949 2021.06.20 23:45:00    8569      6 00FFFFF0 null             ...    ...
[2] 1087.57600 2021.05.15 10:01:30   -3298      7 0000FFFF "note"           ...    ...
SimpleStruct (custom)
  12.578;2021.07.23;  22345;     5;00FF0000;"text message";  ...;   ...
 135.829;2021.06.20;   8569;     6;00FFFFF0;null          ;  ...;   ...
1087.576;2021.05.15;  -3298;     7;0000FFFF;"note"        ;  ...;   ...

请注意,我们在本例中以及在前面章节中使用的日志是在终端中生成,用户可在Toolbox 窗口的Experts选项卡中查看。但是稍后我们将熟悉测试程序,其象终端本身一样为某些类型的 MQL 程序(指标和 EA 交易)提供相同的执行环境。如果它们在测试程序中启动,则 ArrayPrint 函数及其它相关函数(在 用户交互章节中介绍)会将消息输出到 测试代理的日志中。
 
但截至目前,我们一直并且在一定时间内将继续仅使用脚本,并且这些脚本只能在终端内执行。