外观
数组
约 7391 字大约 25 分钟
高级
注意
本页面包含高级内容。如果您是 Mine Script® 编程初学者,建议先熟悉其他更基础的 Mine Script 功能,再学习本部分内容。
简介
Mine Script数组是一种一维集合,可存储多个值引用。它们为处理需要显式声明一组相似变量(如price00、price01、price02等)的情况提供了更优方案。
数组中的所有元素必须属于相同类型,包括内置类型、用户自定义类型或枚举类型。
脚本通过数组ID引用数组,这与线条、标签等特殊类型的引用方式类似。Mine Script不使用索引运算符访问单个数组元素,而是通过array.get()和array.set()等函数读写元素值。
数组元素通过索引进行访问,索引从0开始,最大值为数组元素数量减一。Mine Script数组可动态调整大小,脚本每次迭代时都可改变元素数量。单个脚本可包含多个数组实例,数组大小上限为100,000个元素。
注意
我们将使用数组的*起始端(beginning)表示索引0的位置,数组的末端(end)*表示具有最大索引值的元素。为简洁起见,后文提及“数组”时,其含义也将包含数组ID(array IDs)的指代。
声明数组
Mine Script采用以下语法声明数组:
[var/varip ][array<type>/<type[]> ]<identifier> = <expression>其中,<type> 是用于声明数组值类型的类型模板,<expression> 返回指定类型的数组或 na。
声明数组变量时,可使用 array 关键字后接类型模板,也可使用类型名后跟 [] 修饰符(注意不要与用于历史引用的 [] 操作符混淆)。
由于 Mine 始终使用类型特定的函数来创建数组,声明中的 array<type>/type[] 部分实际上是冗余的(除非声明被赋值为 na 的数组变量)。即使非必需,显式声明数组类型有助于向代码阅读者明确意图。
以下代码行声明了一个指向 na 的数组变量 prices。此种情况下,必须指定类型以声明该变量可引用包含“float”值的数组:
Mine Script®
已复制
我们也可以用以下形式编写上述示例:
Mine Script®
已复制
声明数组且 <expression> 不为 na 时,需使用以下函数之一:array.new<type>(size, initial_value)、array.from() 或 array.copy()。对于 array.new<type>(size, initial_value) 函数,参数size和initial_value可设为“series”类型,以实现数组元素的动态大小调整和初始化。以下示例创建了一个包含零个“float”元素的数组,此处 array.new<float>() 函数调用返回的数组ID将被赋值给prices变量:
Mine Script®
已复制
注意
array.*命名空间包含类型特定的数组创建函数:array.new_int()、array.new_float()、array.new_bool()、array.new_color()、array.new_string()、array.new_line()、array.new_linefill()、array.new_label()、array.new_box()、array.new_table(),同时array.new<type>()函数可创建包含任何类型(含用户自定义类型)的数组。
array.new* 函数的 initial_value 参数允许用户将数组所有元素设为指定值。若未提供 initial_value 参数,则数组将填充为 na 值。
以下代码声明了一个名为 prices 的数组ID,指向包含两个元素的数组(每个元素被赋值为当前K线的收盘价):
Mine Script®
已复制
要创建数组并使用不同值初始化其元素,请使用 array.from()。该函数会根据调用时传入的参数推断数组的大小和元素类型。与 array.new* 函数一样,它接受“series”类型的参数。传入函数的所有值必须为相同类型。
例如,以下三行代码都会创建具有相同两个元素的“bool”类型数组:
Mine Script®
已复制
使用 var 和 varip 关键字
用户可通过 var 和 varip 关键字声明仅在图表首个K线首次迭代时初始化一次的数组变量。以此方式声明的数组变量将始终指向同一数组实例(除非显式重新赋值),使数组及其元素引用能在不同K线间持续保留。
当使用这些关键字声明数组变量,并在每个K线向数组末尾追加新值时,数组长度将逐K线递增。至脚本在最后一根K线执行时,数组大小将达到 bar_index + 1(因 bar_index 从零开始计数),如下列代码所示:
Mine Script®
已复制
若省略 var 关键字,代码将在每个K线重新声明数组。此时执行 array.push() 后,a.size() 将始终返回值1。
注意
使用 varip 声明的数组变量在历史数据上的行为与 var 相同,但在实时 K 线(即脚本最后一次编译后出现的 K 线)上,会在每次价格变动时更新其值。varip 变量所持有的数组只能包含 int、float、bool、color 或 string 类型,或者字段仅包含这些类型或其集合(数组、矩阵)的用户自定义类型。
数组元素的读写
脚本可通过 array.set(id, index, value) 写入数组元素值,通过 array.get(id, index) 读取元素值。使用时必须确保索引值小于等于数组大小(因数组索引从0开始)。获取数组大小需调用 array.size(id) 函数。
下例使用 set() 方法向 fillColors 数组填充不同透明度的基础颜色实例,再通过 array.get() 根据最近 lookbackInput 根K线内最高价所在位置,从数组中获取对应颜色:

Mine Script®
已复制
另一种初始化数组元素的方法是先创建空数组(不含任何元素),然后使用 array.push() 将新元素追加到数组末尾,每次调用都会使数组大小增加1。以下代码在功能上等同于前例脚本中的初始化部分:
Mine Script®
已复制
以下代码实现与前例相同的功能,但改用 array.unshift() 在 fillColors 数组头部插入新元素:
Mine Script®
已复制
我们同样可以通过 array.from() 函数一次性创建具有相同元素的 fillColors 数组:
Mine Script®
已复制
array.fill(id, value, index_from, index_to) 函数用于将数组的全部元素(或指定索引范围内的元素)设置为指定值。若省略最后两个可选参数,函数将填充整个数组。例如:
Mine Script®
已复制
和:
Mine Script®
已复制
是等效的,但是:
Mine Script®
已复制
仅会将数组中索引1和2的第二、第三个元素填充为close值。需特别注意:array.fill()的最后一个参数index_to必须比实际要填充的最后一个索引大1。其余元素将保持为na值,因为array.new()函数调用时未提供initial_value参数。
遍历数组元素
当需要遍历数组元素索引且数组大小未知时,可通过 array.size() 函数获取最大索引值。例如:
Mine Script®
已复制
需注意:
- 我们使用 request.security_lower_tf() 函数,该函数返回
1分钟时间框架下的收盘价数组。 - 若在小于
1分钟的时间框架图表上使用此代码示例,将会报错。 - 当
to表达式为na时,for循环不会执行。请注意to的值仅在循环入口处评估一次。
另一种遍历数组的方法是使用 for...in 循环。这是标准 for 循环的变体,可直接遍历数组中的值引用和索引。以下是使用 for...in 循环改写上述代码的示例:
Mine Script®
已复制
请注意:
- for...in 循环可以返回包含每个索引和对应元素的元组。例如,
for [i, price] in a会返回数组a中每个元素的索引i和值price。
while 循环语句同样适用:
Mine Script®
已复制
作用域
用户可在脚本的全局作用域中声明数组,也可在函数、方法及条件结构的局部作用域中声明。与其他内置类型(尤其是基础类型)不同,脚本可在局部作用域内修改全局分配的数组,从而实现全局变量的功能,允许脚本中的任何函数直接与之交互。以下示例利用此特性逐步计算更高或更低的价格水平:

Mine Script®
已复制
历史引用
Mine Script 的历史引用操作符 [] 可以访问数组变量的历史状态,允许脚本与之前分配给变量的历史数组实例进行交互。
举例说明,我们创建一个简单示例来展示两种等效方式获取前一根K线的收盘价。该脚本使用 [] 操作符获取前一根K线时分配给变量 a 的数组实例,然后使用 get() 方法获取第一个元素的值(previousClose1)。对于 previousClose2,我们直接在 close 变量上使用历史引用操作符来获取值。从图表可以看出,previousClose1 和 previousClose2 返回相同的值:

Mine Script®
已复制
数组元素插入与删除
插入
以下三个函数可用于向数组中插入新元素:
array.unshift() 在数组开头(索引0处)插入一个新元素,并将所有现有元素的索引值增加1。
array.insert() 在指定索引处插入一个新元素,并将该索引及之后的所有现有元素的索引增加1。

Mine Script®
已复制
array.push() 在数组末尾添加一个新元素。
移除元素
以下四个函数用于从数组中移除元素(前三个函数会返回被移除元素的值):
array.remove() 移除指定索引处的元素,并返回该元素的值。
array.shift() 移除数组的第一个元素,并返回其值。
array.pop() 移除数组的最后一个元素,并返回其值。
array.clear() 清空数组中的所有元素(注意:此操作不会删除数组元素引用的任何对象)。
Mine Script®
已复制
使用数组作为栈
栈是LIFO(后进先出)结构。其行为类似于垂直堆叠的书籍——每次只能从顶部添加或移除一本书。Mine Script数组可以用作栈,此时我们使用array.push()和array.pop()函数在数组末尾添加和移除元素。
array.push(prices, close)将在prices数组的末尾添加一个新元素,使数组的大小增加1。
array.pop(prices)将从prices数组移除末尾元素,返回其值并使数组的大小减少1。
以下示例展示如何使用这些函数跟踪上涨行情中的连续低点:

Mine Script®
已复制
使用数组作为队列
队列是FIFO(先进先出)结构。它们的行为类似于到达红灯处的车辆:新来的车辆排在队伍末尾,而最先离开的是最早到达红灯的车辆。
在下面的代码示例中,我们让用户通过脚本的输入参数决定要在图表上显示多少个标签。我们使用这个数量来确定标签数组的大小,并将数组元素初始化为na。
当检测到新的枢轴点时,我们为其创建一个标签,将标签ID保存在pLabel变量中,然后使用array.push()将这个新标签的ID添加到数组末尾,使数组大小比要在图表上保留的标签最大数量多1。
最后,我们通过使用array.shift()移除数组的第一个元素来使最旧的标签出列,并删除该数组元素值所引用的标签。这样操作后,数组将再次包含pivotCountInput个元素。请注意,在数据集的最初几个K线上,我们会在创建最大数量的标签之前删除na标签ID,但这不会导致运行时错误。以下是我们的代码:

Mine Script®
已复制
数组计算
虽然序列变量可视为随时间向后延伸的水平值集合,但Mine Script的一维数组可视作存在于每个K线上的垂直结构。由于数组的元素集合并非时间序列,Mine Script的常规数学函数不可直接作用于数组,必须使用专用函数操作数组的所有值。可用函数包括:array.abs()、array.avg()、array.covariance()、array.min()、array.max()、array.median()、array.mode()、array.percentile_linear_interpolation()、array.percentile_nearest_rank()、array.percentrank()、array.range()、array.standardize()、array.stdev()、array.sum()、array.variance()。
需注意:与Mine Script常规数学函数不同,这些数组函数在部分计算值为na时不会返回na,但存在以下例外:
当所有数组元素为na值或数组为空时返回na(但array.standardize()会返回空数组)。
array.mode()在找不到众数时将返回na。
数组操作
数组拼接
使用 array.concat() 函数可将两个数组合并(即拼接)。拼接时,第二个数组会被追加到第一个数组的末尾,因此第一个数组会被修改,而第二个数组保持不变。该函数返回第一个数组的ID:

Mine Script®
已复制
数组复制
您可以使用 array.copy() 函数复制数组。以下示例将数组 a 复制到名为 _b 的新数组中:

Mine Script®
已复制
请注意,在前面的示例中,如果简单地使用 _b = a 并不会复制数组,而只会复制其引用ID。此后,两个变量将指向同一个数组,因此使用其中任何一个变量都会影响同一个数组实例。
数组连接
使用 array.join() 方法可以将数组中的所有元素连接成一个字符串,并通过指定的分隔符进行分隔:
Mine Script®
已复制
数组排序
包含“int”或“float”元素的数组可以使用array.sort()进行升序或降序排序。order参数是可选的,默认为order.ascending。与所有array.*()函数参数一样,它被限定为“series”类型,因此可以在运行时动态决定,如下例所示。请注意,在示例中要排序的数组也是在运行时确定的:

Mine Script®
已复制
另一个实用的数组排序选项是使用 array.sort_indices() 函数。该函数接收原始数组的引用,并返回一个包含原始数组排序后索引的新数组(不修改原数组)。order 参数可选,默认值为 order.ascending(升序)。
数组反转
使用array.reverse()方法可以反转数组元素的顺序:
Mine Script®
已复制
数组切片
使用 array.slice() 切片数组会创建父数组子集的浅拷贝。通过 index_from 和 index_to 参数确定要切片的子集范围,其中 index_to 参数必须比切片结束索引大1。
在本例中,要切片数组 a 的索引0到2的子集,需使用 _sliceOfA = array.slice(a, 0, 3):

Mine Script®
已复制
数组搜索
我们可以使用 array.includes() 函数测试某个值是否为数组的一部分,如果找到该元素则返回 true。通过 array.indexof() 函数可以查找值在数组中的首次出现位置(首个出现的索引值最小)。此外,还可以使用 array.lastindexof() 查找值的最后一次出现位置:
Mine Script®
已复制
我们也可以对数组执行二分搜索,但需要注意:对数组执行二分搜索意味着数组必须先按升序排序。array.binary_search() 函数会在找到值时返回其索引,未找到时返回-1。如果我们希望即使未找到指定值也返回一个存在的索引,可以使用其他可用的二分搜索函数。array.binary_search_leftmost() 函数会在找到值时返回其索引,否则返回该值如果存在应该位于的最左侧索引。array.binary_search_rightmost() 函数几乎相同,会在找到值时返回其索引,否则返回该值如果存在应该位于的最右侧索引。
错误处理
在Mine脚本中,错误的array.*()调用语法会在保存脚本时触发常规编译器错误,并显示在Mine Editor窗口底部的控制台中。若对函数调用的确切语法存在疑问,请参阅《Mine Script v5参考手册》。
使用数组的脚本也可能引发运行时错误,这些错误会在图表上指标名称旁显示感叹号标识。我们将在本节讨论这些运行时错误。
索引xx越界。数组大小为yy
这很可能成为您遇到最频繁的错误。当引用不存在的数组索引时就会发生此错误。“xx”值代表您尝试使用的错误索引,“yy”则表示数组的大小。请记住数组索引从零开始(而非一),最大有效索引为数组大小减一。因此,大小为3的数组最后一个有效索引是2。
要避免此错误,必须在代码逻辑中采取措施防止使用超出数组索引边界的值。以下代码将触发错误,因为循环中使用的最后一个索引超出了数组的有效范围:
Mine Script®
已复制
正确的for循环语句应为:
Mine Script®
已复制
要遍历未知大小的数组中的所有元素,请使用:
Mine Script®
已复制
当您使用脚本设置/输入选项卡中的字段动态调整数组大小时,应通过 input.int() 的 minval 和 maxval 参数保护该值的边界范围:
Mine Script®
已复制
更多信息请参阅本页遍历数组元素章节。
当数组ID为na时无法调用数组方法
当数组ID初始化为na时,不允许对其调用数组方法,因为此时数组并不存在。此时存在的只是一个包含na值的数组变量,而非指向现有数组的有效数组ID。请注意,即使创建空数组(如使用a = array.new_int(0))也会获得有效ID。以下代码将抛出我们正在讨论的错误:
Mine Script®
已复制
为避免此错误,应使用以下方式创建大小为零的数组:
Mine Script®
已复制
或:
Mine Script®
已复制
数组过大。最大尺寸为100000
此错误会在代码尝试声明大小超过100,000的数组时出现。如果在动态向数组追加元素时,新元素会导致数组大小超过最大值,也会发生此错误。
无法创建负大小的数组
我们尚未发现负大小数组的任何用途,但如果您确实需要,我们可能会考虑支持。
无法对空数组使用shift()
当调用array.shift()移除空数组的第一个元素时会出现此错误。
无法对空数组使用pop()
当调用array.pop()移除空数组的最后一个元素时会出现此错误。
索引from必须小于索引to
在array.slice()等使用两个索引的函数中,第一个索引必须始终小于第二个索引。
切片超出父数组边界
当父数组的大小被修改,导致切片创建的浅拷贝指向父数组边界之外时,会出现此消息。以下代码将重现此错误:在创建索引3到4的切片(父数组5个元素中的最后两个元素)后,我们移除父数组的第一个元素,使其大小变为4且最后一个索引变为3。此时,仍指向父数组索引3到4"窗口"的浅拷贝已超出父数组边界:
Mine Script®
已复制