数组特点
在介绍 MQL5 中声明数组的语法细节以及它们的应用实践之前,让我们来了解构造数组的一些基本概念。
数组的核心特点是维数。在一维数组中,元素是逐个放置的,就像一排士兵,只需一个数字(索引)就能引用元素。在给定历史深度开立的金融工具的逐根柱线价格便可以保存在这样的数组中。
在二维数组中,元素在两个逻辑上垂直的方向上发散,形成一个正方形(或者一般情况下为矩形),每个元素需要两个索引,即每个维度一个。这样的数组可以用来存储每个历史柱线的价格四方形(开盘价、最高价、最低价和收盘价)。柱线编号使用第一维度计数,而第二维度用于从 0 到 3 的数字,分别表示一种价格类型。
三维数组相当于一个有三个轴的立方体(或者更严格地说,是一个直角平行六面体)。继续逐根柱线价格数组的例子,我们可以给它添加第三个维度,该维度负责迭代来自市场报价的金融工具。
对于每个维度,数组都有固定的长度(大小),用于设定索引范围。如果计划载入 1,000 根柱线和 10 个金融工具的历史,我们将在数组的第一个维度中得到 1,000 个元素,在第二个维度 (OHLC) 中得到 4 个元素,在第三个维度中得到 10 个元素。
所有维度中大小的乘积即为数组元素总数;在我们的例子中,总数是 40,000。在 MQL5 中,总数不能超过 2147483647(int 的最大值)。
因为我们生活在一个三维世界中,所以很难想象一个 4 维数组的立体形状。但是 MQL5 允许创建最多包含四个维度的数组。
请注意,始终可以使用一维数组来代替具有随机维数(包括 4 维以上)的多维数组。只需要将多个索引重新计算,获得一个连续索引。例如,如果一个二维数组有 10 列(维度 1,X 轴)和 5 行(维度 2,Y 轴),则可以被转换为具有相同元素数量(即 50 个元素)的一维数组。在这种情况下,元素索引通过以下公式获得:
index = Y * N + X |
此处,N 是第一个维度中元素的数量,在我们的例子中是 10;就是每行的大小;Y 是行号(0 到 4);X 是列号(0 到 9)。
跨维度大小是区分数组和变量的另一个特征。因此,必须在说明中以某种方式指定维度的数量和每个维度的大小,以及数组名称和数据类型(参见 下一节)。
请区分变量(数组元素)的大小(以字节为单位)和数组的大小(数组中元素的个数)。从理论上讲,就占用的内存而言,完整的数组大小必须是一个元素的大小(由数据类型决定)与元素个数的乘积。然而,这一公式在实践中不一定总是有效。特别是,由于字符串的长度各不相同,因此很难计算一个字符串数组占用的内存量。
根据内存分配方法,数组可以分为动态数组和定长数组。
代码中描述的定长数组在所有维度上都具有精确的大小。这些大小之后无法改变。然而,实际任务中经常会出现待处理的数据量不确定的情况,因此,需要在算法操作期间改变数组的大小。动态数组就是针对这个特定用途而出现的。接下来我们会看到,动态数组在声明时没有指定第一个维度的大小,然后使用特殊的 MQL5 API 函数进行“扩展”或“压缩”。
MQL5 文档中使用了一个有歧义的术语,将定长数组称为静态。这个概念也适用于 'static' 修饰符,该修饰符可应用于数组。这样的数组被声明为动态时,在内存分配方面不是静态的,而在 'static' 修饰符方面则是静态的。为了排除这种歧义,本书中的静态字符仅代表声明属性。
除了动态数组和定长数组,MQL5 中还有一些特殊数组,用于存储报价和技术指标缓冲区。这类数组称为时间序列数组,因为它们的索引与时间相对应。实际上,这些数组是动态的一维数组。然而,与其他动态数组不同,终端本身会为它们分配内存。我们将在涉及 时间序列 和 指标的相关章节中介绍。