外观
变量声明
约 2996 字大约 10 分钟
简介
变量是保存值的标识符。使用变量之前,必须在代码中声明。变量声明的语法如下:
[<declaration_mode>] [<type>] <identifier> = <expression> | <structure>或者
<tuple_declaration> = <function_call> | <structure>其中:
|表示“或”,方括号([])内的部分可以出现零次或一次。<declaration_mode>是变量的 声明模式。它可以是 var 或 varip,或者什么都不指定。<type>是可选的,就像几乎所有 Mine Script® 变量声明一样(请参阅类型)。<identifier>是变量的 名称。<expression>可以是文字、变量、表达式或函数调用。<structure>可以是 if、 for、 while 或 switch 结构。<tuple_declaration>是用方括号 ([]) 括起来的变量名的逗号分隔列表,例如[ma, upperBand, lowerBand]。
这些都是有效的变量声明。最后一个需要四行:
Mine Script®
已复制
注意
以上语句均包含=赋值运算符,因为它们是变量声明。当您看到使用 := 重新赋值运算符的类似代码行时,表示代码正在将值重新赋给已声明的变量。这些是变量重新赋值。请务必理解其中的区别,因为这是 Mine Script 新手常见的绊脚石。有关详细信息,请参阅下一节变量重新赋值。
变量声明的正式语法是:
<variable_declaration>
[<declaration_mode>] [<type>] <identifier> = <expression> | <structure>
|
<tuple_declaration> = <function_call> | <structure>
<declaration_mode>
var | varip
<type>
int | float | bool | color | string | line | linefill | label | box | table | array<type> | matrix<type> | UDF初始化na
在大多数情况下,显式类型声明是多余的,因为类型会在编译时根据 右侧的值自动推断出来=,所以是否使用它们通常取决于个人喜好。例如:
Mine Script®
已复制
在示例的第一行中,编译器无法确定baseLine0变量的类型,因为na是一个不包含任何特定类型的泛型值。变量的声明baseLine1 是正确的,因为其 float 类型已显式声明。变量的声明baseLine2也是正确的,因为它的类型可以从表达式float(na)导出 ,该表达式是将na值显式转换为float类型的表达式。baseLine1和baseLine2的声明是等效的。
元组声明
函数调用或结构体可以返回多个值。当我们调用它们并想要存储它们的返回值时,必须使用元组声明,元组是由逗号分隔的一个或多个值组成的集合,并用括号括起来。这允许我们同时声明多个变量。例如,布林带的内置函数ta.bb()返回三个值:
Mine Script®
已复制
使用下划线 (_) 作为标识符
声明变量时,可以使用单个下划线 (_) 作为其标识符。赋给此类变量的值无法访问。您可以在脚本中的任何位置为标识符_赋任意数量的值,即使当前作用域中已有此类赋值。
当元组返回不需要的值时,这尤其有用。让我们编写另一个布林带脚本。在这里,我们只需要布林带本身,不需要中心线:
Mine Script®
已复制
变量重新赋值
变量重新赋值使用 := 赋值运算符完成。该操作只能在变量首次声明并赋值后进行。在计算中,为变量重新赋值通常很有必要,并且在全局作用域中的变量必须在结构体的局部块中赋值时,也总是需要重新赋值,例如:
Mine Script®
已复制
注意:
- 我们
maColor仅在第一个k线上进行初始化,因此它会在各个k线上保留其值。 - 在每个k线上,if语句都会检查 MA 是否在用户指定的k线数量(默认值为 2)内上涨或下跌。如果出现这种情况,则必须在if局部代码块中为
maColor的值重新赋值 。为此,我们使用:=重新赋值运算符。 - 如果我们不使用
:=重新赋值运算符,其效果将是初始化一个maColor与全局范围同名的新局部变量,但实际上是一个非常令人困惑的独立实体,它只会在本地块的长度内持续存在,然后消失得无影无踪。
Mine Script 中所有用户定义的变量都是可变的,这意味着可以使用 := 重新赋值运算符更改它们的值。为变量赋新值可能会更改其类型限定符(有关更多信息,请参阅 Mine Script 的类型系统页面 )。在脚本执行期间,可以根据需要多次为变量赋新值,因此一个脚本可以包含任意数量的变量重新赋值。变量的 声明模式决定了赋给变量的新值的保存方式。
声明模式
要了解声明模式对变量行为的影响,需要事先了解 Mine Script 的 执行模型。
声明变量时,如果指定了声明模式,则必须首先指定该模式。可以使用三种模式:
在每根K线上
当没有指定明确的声明模式时,即没有使用var或 varip 关键字,则在每根K线上声明和初始化变量,例如,本页介绍中第一组示例中的以下声明:
Mine Script®
已复制
var
使用var关键字时 ,变量仅初始化一次:如果声明在全局范围内,则在第一个k线上初始化;如果声明在局部块内,则在第一次执行局部块时初始化。之后,它将在后续k线上保留其最后一个值,直到我们为其重新赋值。这种行为在变量值必须在脚本跨连续k线迭代过程中保持不变的很多情况下非常有用。例如,假设我们想计算图表上绿色k线的数量:
Mine Script®
已复制

如果没有var修饰符,count每次新的k线更新触发脚本重新计算时,变量都会被重置为零(从而失去其值)。
仅在第一根k线上声明变量通常有助于更有效地管理绘图。假设我们想将最后一根k线的 close 线延伸至右侧图表的右侧。我们可以这样写:
Mine Script®
已复制
但这种做法效率低下,因为我们要在每个历史k线和实时k线的每次更新时创建和删除这条线。更高效的方法是:
Mine Script®
已复制
注意:
- 我们
closeLine仅在第一根k线上进行初始化,使用 var 声明模式 - 我们将更新线条的代码封装在if barstate.islast结构中,从而将其余代码的执行限制在图表的最后一条k线上 。
使用var声明模式会略微降低性能。因此,在声明常量时,如果性能是主要考量因素,最好不要使用 var,除非初始化操作所需的计算时间比维护性能损失更长,例如包含复杂代码或字符串操作的函数。
varip
要理解使用varip声明模式的变量行为,需要事先了解 Mine Script 的 执行模型 和 k线状态。
varip关键字 可用于声明逃避回滚过程的变量,这在 Mine Script 的执行模型页面中有解释 。
脚本仅在历史K线收盘时执行一次,而实时运行时,每当图表数据流检测到价格或成交量更新时,脚本都会执行。每次实时更新时,Mine Script 的运行时通常会将脚本变量的值重置为其上次提交的值,即上一个K线收盘时的值。这通常很方便,因为每次实时脚本执行都从已知状态开始,从而简化了脚本逻辑。
然而,有时脚本逻辑需要代码能够在实时k线图中的不同执行之间保存变量值。使用varip声明变量可以实现这一点。varip 中的“ip” 代表“intrabar persist”(k线图内持久化)。
让我们看看下面的代码,它没有使用 varip:
Mine Script®
已复制
在历史k线上,barstate.isnew 始终为真,因此绘图显示值“1”,因为if结构的else部分从未执行过。在实时k线上,barstate.isnew仅在脚本首次在k线“开盘”处执行时才为真。之后,绘图将短暂显示“1”,直到后续执行发生。在实时k线期间的后续执行中,由于barstate.isnew不再为真, 因此将执行if语句的第二个分支。由于updateNo每次执行时都初始化为na,updateNo + 1表达式结果为na,因此在脚本的后续实时执行中不会绘制任何内容。
如果我们现在使用 varip 来声明updateNo变量,脚本的行为会非常不同:
Mine Script®
已复制
现在的区别在于,updateNo跟踪每个实时k线上发生的实时更新次数。这是因为 varip 声明允许在实时更新之间保留updateNo的值;它不再在每次脚本实时执行时回滚。测试上的barstate.isnew允许我们在新的实时k线出现时重置更新计数。
由于 varip 仅影响实时k线上代码的行为,因此,使用基于 varip 变量逻辑设计的策略的回测结果将无法在历史k线上重现该行为,这将导致测试结果无效。这也意味着基于历史k线绘制的图表将无法实时重现脚本的行为。