【tradingview量化编程语言pinescript之变量声明】

变量声明

  • 介绍
    • na初始化
    • 元组声明
  • 变量重新分配
  • 声明方式
    • 在每个柱
    • var
    • varip

简介

变量是保存值的标识符。在您使用它们之前,必须在您的代码中*声明它们。*变量声明的语法是:

[<declaration_mode>] [<type>] <identifier> = <expression> | <structure>

要么

<tuple_declaration> = <function_call> | <structure>

注:

  • |表示“或”,方括号 ( []) 中的部分可以出现零次或一次。
  • <declaration_mode> 是变量的声明模式。它可以是var或 varip,也可以什么都不是,什么都没有。
  • 是可选的,就像在几乎所有 Pine Script™ 变量声明中一样。
  • 是变量的名称。
  • 可以是文字、变量、表达式或函数调用。
  • 可以是if、 for、 while或 switch结构
  • <tuple_declaration> 是用逗号分隔的变量名列表,用方括号 ( []) 括起来,例如 .[ma, upperBand, lowerBand]

这些都是有效的变量声明。最后一个变量plotColor需要四行:

BULL_COLOR = color.lime
i = 1
len = input(20, "Length")
float f = 10.5
closeRoundedToTick = math.round_to_mintick(close)
st = ta.supertrend(4, 14)
var barRange = float(na)
var firstBarOpen = open
varip float lastClose = na
[macdLine, signalLine, histLine] = ta.macd(close, 12, 26, 9)

plotColor = if close > open
    color.green
else
    color.red

笔记

上述语句都包含=赋值运算符,因为它们是变量声明。当您看到使用:=重新分配运算符的值时,代码正在将值重新分配给已经声明的变量。这是变量重新分配。确保您了解其中的区别,因为这是 Pine 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 初始化

在大多数情况下,显式类型声明是多余的,因为类型是在编译时从右边的值自动推断出来的=,所以使用它们的决定通常是一个偏好问题。例如:

baseLine0 = na          // compile time error!
float baseLine1 = na    // OK
baseLine2 = float(na)   // OK

在示例的第一行中,编译器无法确定baseLine0变量的类型,因为na是没有特定类型的泛型值。变量的声明baseLine1是正确的,因为它的 float类型是明确声明的。变量的声明baseLine2也是正确的,因为它的类型可以从 expression 派生float(na),它是na值到float类型的显式转换。baseLine1和的声明baseLine2是等价的。

元组声明

允许函数调用或结构返回多个值。当我们调用它们并希望存储它们返回的值时,必须使用*元组声明,它是用括号括起来的一个或多个值的逗号分隔集合。*这允许我们同时声明多个变量。例如,布林带的ta.bb()内置函数返回三个值:

[bbMiddle, bbUpper, bbLower] = ta.bb(close, 5, 4)

变量重新分配

使用:=重新分配运算符完成变量重新分配。它只能在首先声明变量并赋予初始值之后才能完成。在计算中经常需要为变量重新分配一个新值,并且当必须从结构的局部块中为全局范围的变量分配一个新值时,这总是必要的,例如:

//@version=5
indicator("", "", true)
sensitivityInput = input.int(2, "Sensitivity", minval = 1, tooltip = "Higher values make color changes less sensitive.")
ma = ta.sma(close, 20)
maUp = ta.rising(ma, sensitivityInput)
maDn = ta.falling(ma, sensitivityInput)

// On first bar only, initialize color to gray
var maColor = color.gray
if maUp
    // MA has risen for two bars in a row; make it lime.
    maColor := color.lime
else if maDn
    // MA has fallen for two bars in a row; make it fuchsia.
    maColor := color.fuchsia

plot(ma, "MA", maColor, 2)

注意:

  • 我们仅在第一根柱上进行初始化maColor,因此它会在所有柱上保留其值。
  • 在每个柱上,if语句检查 maUp或maOn用户指定的柱数(默认为 2)。当发生这种情况时,maColor必须从if局部块中为 的值重新分配一个新值。为此,我们使用:=重新赋值运算符。
  • 如果我们不使用:=重新赋值运算符,效果将是初始化一个新的maColor局部变量,该变量与全局范围的名称相同,但实际上是一个非常混乱的独立实体,只会持续存在的局部块里,然后消失得无影无踪。

Pine Script™ 中的所有用户定义变量都是可变的,这意味着它们的值可以使用:=重新分配运算符更改。为变量分配新值可能会改变其形式(有关更多信息,请参阅 Pine Script™类型系统页面)。在脚本在一个柱上执行期间,可以根据需要多次为变量分配新值,因此脚本可以包含一个变量的任意次数的重新分配。变量的声明模式决定了分配给变量的新值将如何保存。

声明模式

了解声明模式对变量行为的影响需要 Pine Script™执行模型的先验知识。

声明变量时,如果指定了声明方式,则必须先声明。可以使用三种模式:

  • “在每个柱上”,没有指定
  • var
  • varip

在每个柱上没有声明模式

当未指定显式声明模式时,即未使用var或 varip关键字时,将在每个柱上声明和初始化变量,例如,本页介绍中第一组示例中的以下声明:

BULL_COLOR = color.lime
i = 1
len = input(20, "Length")
float f = 10.5
closeRoundedToTick = math.round_to_mintick(close)
st = ta.supertrend(4, 14)
[macdLine, signalLine, histLine] = ta.macd(close, 12, 26, 9)
plotColor = if close > open
    color.green
else
    color.red

var

当使用var关键字时,变量仅初始化一次,如果声明在全局范围内,则在第一个柱上,或者如果声明在局部块内,则在第一次执行局部块时。之后,它将保留其在连续柱上的最后一个值,直到我们为它重新分配一个新值。在许多情况下,此行为非常有用,在这些情况下,变量的值必须在连续柱上的脚本迭代中保持不变。例如,假设我们想计算图表上绿色条的数量:

//@version=5
indicator("Green Bars Count")
var count = 0
isGreen = close >= open
if isGreen
    count := count + 1
plot(count)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H1PPWToT-1671845307319)(null)]

如果没有var修饰符,count每次新柱更新触发脚本重新计算时,变量都会重置为零(从而丢失其值)。

仅在第一根柱上声明变量通常有助于更有效地管理绘图。假设我们想要将最后一根柱线的收盘线延伸到右侧图表的右侧。我们可以写:

//@version=5
indicator("Inefficient version", "", true)
closeLine = line.new(bar_index - 1, close, bar_index, close, extend = extend.right, width = 3)
line.delete(closeLine[1])

但这是低效的,因为我们在每个历史柱和实时柱的每个更新上创建和删除线。使用它更有效:

//@version=5
indicator("Efficient version", "", true)
var closeLine = line.new(bar_index - 1, close, bar_index, close, extend = extend.right, width = 3)
if barstate.islast
    line.set_xy1(closeLine, bar_index - 1, close)
    line.set_xy2(closeLine, bar_index, close)

注意:

  • 我们仅在第一个柱上初始化closeLine,使用var声明模式
  • 我们通过将更新行的代码包含在if barstate.islast结构中,将其余代码的执行限制在图表的最后一个柱。

使用var声明模式对性能有非常轻微的惩罚。出于这个原因,在声明常量时,如果性能是一个问题,最好不要使用var,除非初始化涉及的计算比维护惩罚花费的时间更长,例如,具有复杂代码或字符串操作的函数。

varip

使用varip声明模式了解变量的行为 需要事先了解 Pine Script™ 的执行模型和栏状态。

varip 关键字可用于声明逃避回滚过程的变量,这在 Pine Script™ 的执行模型页面中有解释。

脚本仅在历史柱线收盘时执行一次,而当脚本实时运行时,它会在每次图表的提要检测到价格或交易量更新时执行。在每次实时更新时,Pine Script™ 的运行时通常会将脚本变量的值重置为它们最后提交的值,即它们在前一个柱关闭时所持有的值。这通常很方便,因为每个实时脚本执行都从已知状态开始,从而简化了脚本逻辑。

然而,有时,脚本逻辑要求代码能够在实时柱中的**不同执行之间保存变量值。**使用varip声明变量 使之成为可能。varip中的“ip”代表intrabar persist

让我们看看下面的代码,它没有使用varip:

//@version=5
indicator("")
int updateNo = na
if barstate.isnew
    updateNo := 1
else
    updateNo := updateNo + 1

plot(updateNo, style = plot.style_circles)

在历史柱上,barstate.isnew始终为真,因此绘图显示值“1”,因为if结构的else部分 从未执行过。在实时柱上,barstate.isnew 仅在脚本首次在柱的“开盘价”上执行时为真。然后该图将短暂显示“1”,直到发生后续执行。在实时柱的下一次执行中, if语句的第二个分支被执行,因为 barstate.isnew不再为真。由于在每次执行时都被初始化为na,表达式会产生na,因此在脚本的进一步实时执行中不会绘制任何内容。updateNo``updateNo + 1

如果我们现在使用varip来声明updateNo变量,则脚本的行为会大不相同:

//@version=5
indicator("")
varip int updateNo = na
if barstate.isnew
    updateNo := 1
else
    updateNo := updateNo + 1

plot(updateNo, style = plot.style_circles)

现在的区别在于updateNo跟踪每个实时柱上发生的实时更新的数量。发生这种情况是因为varip 声明允许updateNo在实时更新之间保留 的值;它不再在每次实时执行脚本时回滚。barstate.isnew上的测试 允许我们在新的实时柱出现时重置更新计数。

因为varip仅影响您的代码在实时柱中的行为,因此使用基于 varip变量的逻辑设计的策略的回测结果将无法在历史柱上重现该行为,这将使它们的测试结果无效。这也意味着历史柱上的绘图将无法实时重现脚本的行为。

猜你喜欢

转载自blog.csdn.net/weixin_40641289/article/details/128425993