数组中时间序列的索引方向
由于交易中存在的细节,MQL5 为处理数组引入了附加功能。其中一个功能是数组元素可包含对应于时间点的数据。例如,包括具有金融工具报价、价格最小变动单位以及技术指标读数的数组。数据的时间顺序意味着新元素会不断添加到数组末尾,其索引也随之递增。
然而,从交易角度而言,从现在到过去进行计数更为方便。这样一来,元素 0 始终包含最近、最新的值,元素 1 始终包含前一个值,以此类推。
MQL5 允许动态选择和切换数组索引方向。从现在到过去编号的数组称为时间序列。如果索引是从过去到现在递增,则属于常规数组。在时间序列中,时间随索引的增加而递减。在普通数组中,时间如现实生活中一样递增。
务必要注意,不要求数组必须包含时间相关值才能够切换寻址顺序。只不过该功能最常用于处理历史数据,事实上也正是为此类需求而设计。
此数组属性不影响数据在内存中的布局。只是编号顺序改变。特别是,我们可以在“从后向前”循环中遍历数组,从而能够在 MQL5 中实现其类似功能。但 MQL5 提供了现成函数,可以让应用程序编程人员无需关注所有这些例行工作。
时间序列可以是在 MQL 程序中描述的任何一维动态数组,以及从 MetaTrader 5 核心传递至 MQL 程序的外部数组,诸如实用函数的参数。例如,一种特殊类型的 MQL 程序“ 指标 ”在 OnCalculate 事件处理程序中接收具有当前图表价格数据的数组。我们将在后面本书第五章了解时间序列的所有实际应用特性。
在 MQL 程序中定义的数组默认不是时间序列。
我们来研究一组函数,用于确定和更改数组的“系列”属性,以及确定数组是否“归属于”终端。包括示例在内的常规 ArrayAsSeries.mq5 脚本将在说明后提供。
bool ArrayIsSeries(const void &array[])
该函数返回一个符号,表明指定数组是否是“真实”时间序列,即它是由终端本身控制和提供的。数组的这一特性无法更改。MQL 程序能够以“只读”模式使用这种数组。
在 MQL5 文档中,术语“时间序列”和“系列”用于描述数组的逆索引以及该数组可能“属于”终端这一事实(终端为其分配内存和填充数据)。在本书中,我们将尝试消除这种歧义,将具有逆索引的数组称为“时间序列”。而终端数组就是指终端的 own 数组。
你可以通过在时间序列模式与标准模式之间来回切换,可酌情更改终端的任何自定义数组的索引方向。可使用 ArraySetAsSeries 函数来进行切换,该函数不仅适用于自己的数组,而且也适用于自定义动态数组(参见下文)。
bool ArrayGetAsSeries(const void &array[])
该函数返回一个符号,指示是否为指定数组启用了时间序列索引模式(即索引在从现在到过去的方向上增加)。可以使用 ArraySetAsSeries 函数更改索引方向。
索引方向会影响 ArrayBsearch、ArrayMaximum 和 ArrayMinimum 函数返回的值(参见章节 数组的比较、排序和搜索)。
bool ArraySetAsSeries(const void &array[], bool as_series)
该函数根据 as_series 参数设置数组的索引方向:true 值表示逆序索引,而 false 值表示正常元素顺序。
如果属性设置成功,该函数返回 true,如果出错,则返回 false。
支持任何类型的数组,但对于多维数组和固定大小数组,禁止更改索引方向。
ArrayAsSeries.mq5 脚本描述了若干小型数组,用于进行涉及上述函数的试验。
#define LIMIT 10
|
我们有二维数组 array2D、固定和动态数组(类型均为 double)以及结构体数组和类对象数组。出于演示目的,fixed 和 dynamic 数组以连续整数填充(使用辅助函数 indexArray)。对于其它类型的数组,我们将只检查“系列”模式的适用性,因为逆索引效应的概念已经通过填充数组示例解释清楚。
首先,确保没有数组是终端自身的数组:
PRTS(ArrayIsSeries(array2D)); // false
|
所有 ArrayIsSeries 调用均返回 false,因为我们在 MQL 程序中定义了所有数组。我们会看到指标中 OnCalculate 函数的参数数组的值为 true(在第五章)。
接下来,我们检查数组索引的初始方向:
PRTS(ArrayGetAsSeries(array2D)); // false, cannot be true
|
我们会再次全部得到 false。
我们将 fixed 和 dynamic 数组输出到日志,以查看元素的原始顺序。
ArrayPrint(fixed, 1);
|
现在我们尝试更改索引顺序:
// error: parameter conversion not allowed
|
array2D 数组的一个语句导致编译错误,因此被注释掉。
fixed 数组的一个语句发出编译器警告,提示其不能被应用到恒定大小的数组。在运行时,所有 3 个最后语句均返回成功 (true)。我们看看数组的属性如何改变:
// attribute checks:
|
如预期的那样,数组没有转变为终端自身的数组。然而,四个数组中有三个将它们的索引方式更改为时间序列模式,包括一个结构体数组和对象数组。为演示结果,fixed 和 dynamic 数组再次显示在日志中。
ArrayPrint(fixed, 1); // without changes
|
由于该模式不适用于恒定大小的数组,因此其保持不变。dynamic 数组现在以逆序显示。
如果你将数组置于逆索引模式,调整其大小,然后恢复为之前的索引方式,则添加的元素将插入在数组的开头。