循环

介绍

当不需要循环时

Pine Script™ 的运行时及其内置函数使循环在许多情况下变得不必要。尚不熟悉 Pine Script™ 运行时和内置函数的新手 Pine Script™ 程序员如果想要计算最近 10 个 收盘 价的平均值,通常会编写如下代码:

//@version=5
indicator("Inefficient MA", "", true)
MA_LENGTH = 10
sumOfCloses = 0.0
for offset = 0 to MA_LENGTH - 1
    sumOfCloses := sumOfCloses + close[offset]
inefficientMA = sumOfCloses / MA_LENGTH
plot(inefficientMA)

在 Pine 中,for循环 对于完成此类任务而言是不必要的,而且效率低下。应该这样做。此代码更短运行速度更快,因为它不使用循环,而是使用 ta.sma() 内置函数来完成任务:

//@version=5
indicator("Efficient MA", "", true)
thePineMA = ta.sma(close, 10)
plot(thePineMA)

计算最后几条柱状图中某个条件的发生次数也是 Pine Script™ 初级程序员经常认为必须用循环来完成的任务。要计算最后 10 条柱状图中上涨的柱状图数量,他们将使用:

//@version=5
indicator("Inefficient sum")
MA_LENGTH = 10
upBars = 0.0
for offset = 0 to MA_LENGTH - 1
    if close[offset] > open[offset]
        upBars := upBars + 1
plot(upBars)

在 Pine 中编写此代码的有效方法(对于程序员来说,因为它可以节省时间、实现最快的加载图表以及最公平地共享我们的公共资源)是使用 math.sum () 内置函数来完成任务:

//@version=5
indicator("Efficient sum")
upBars = math.sum(close > open ? 1 : 0, 10)     
plot(upBars)

那里发生的事情是:

  • 我们使用 ?: 三元运算符来构建一个表达式,使得上行条的结果为 1,其他条的结果为 0。
  • 我们使用 math.sum() 内置函数来对最后 10 个条形图的值进行运行总和。

何时需要循环

循环的存在是有充分理由的,因为即使在 Pine Script™ 中,在某些情况下它们也是必要的。这些情况通常包括:

  • 集合(数组矩阵映射)的操作
  • 回顾历史,使用只能在当前柱上知道的参考值来分析柱,例如,找出过去有多少高点高于 当前柱的 高点。由于当前柱的高点 仅在脚本正在运行的柱上才为人所知,因此需要循环来回溯并分析过去的柱。
  • 对过去的条形图执行无法使用内置函数完成的计算。

`为`

for结构 允许使用计数器重复执行语句。其语法为:

[[<declaration_mode>] [<type>] <identifier> = ]for <identifier> = <expression> to <expression>[ by <expression>]
<local_block_loop>

在哪里:

  • 方括号 ( []) 中的部分可以出现零次或一次,花括号 ( {}) 中的部分可以出现零次或多次。
  • <declaration_mode> 是变量的 声明模式
  • <type> 是可选的,就像几乎所有的 Pine Script™ 变量声明一样(参见类型
  • <identifier> 是变量的 名称
  • <expression> 可以是文字、变量、表达式或函数调用。
  • <local_block_loop> 由零个或多个语句组成,后跟一个返回值,返回值可以是一组值。它必须缩进四个空格或一个制表符。它可以包含break退出循环的语句,也可以continue包含退出当前迭代并继续下一个迭代的语句。
  • 分配给该变量的值是 <local_block_loop> 的返回值,即循环最后一次迭代计算出的最后一个值, 如果未执行循环,则为na 。
  • 中的标识符for <identifier>是循环的计数器初始值
  • 中的表达式= <expression>计数器的起始值。
  • 中的表达式to <expression>计数器的最终值。它仅在循环入口处进行评估
  • 中的表达式by <expression>是可选的。它是循环计数器在每次循环迭代中增加或减少的步长。当 时,它的默认值为 1。当 时,start value < end value它的默认值为 -1 start value > end value。用作默认值的步长(+1 或 -1)由起始值和结束值决定。

此示例使用 for 语句回顾用户定义的条形图数量,以确定有多少条形图的 最高 点高于或低于 图表上最后一条形图的 最高点。这里需要一个for循环,因为脚本只能访问图表最后一条形图上的参考值。Pine Script™ 的运行时在这里不能用于动态计算,因为脚本正在逐条执行:

//@version=5
indicator("`for` loop")
lookbackInput = input.int(50, "Lookback in bars", minval = 1, maxval = 4999)
higherBars = 0
lowerBars = 0
if barstate.islast
    var label lbl = label.new(na, na, "", style = label.style_label_left)
    for i = 1 to lookbackInput
        if high[i] > high
            higherBars += 1
        else if high[i] < high
            lowerBars += 1
    label.set_xy(lbl, bar_index, high)
    label.set_text(lbl, str.tostring(higherBars, "# higher bars\n") + str.tostring(lowerBars, "# lower bars"))

此示例在其函数中使用循环checkLinesForBreaches()来遍历枢轴线数组,并在价格与枢轴线交叉时删除它们。此处需要使用循环,因为必须在每个条形上检查每个 hiPivotLinesloPivotLines数组中的所有线条,并且没有内置函数可以为我们执行此操作:

//@version=5
MAX_LINES_COUNT = 100
indicator("Pivot line breaches", "", true, max_lines_count = MAX_LINES_COUNT)

color hiPivotColorInput  = input(color.new(color.lime, 0), "High pivots")
color loPivotColorInput  = input(color.new(color.fuchsia, 0), "Low pivots")
int   pivotLegsInput     = input.int(5, "Pivot legs")
int   qtyOfPivotsInput   = input.int(50, "Quantity of last pivots to remember", minval = 0, maxval = MAX_LINES_COUNT / 2)
int   maxLineLengthInput = input.int(400, "Maximum line length in bars", minval = 2)

// ————— Queues a new element in an array and de-queues its first element.
qDq(array, qtyOfElements, arrayElement) =>
    array.push(array, arrayElement)
    if array.size(array) > qtyOfElements
        // Only deqeue if array has reached capacity.
        array.shift(array)

// —————— Loop through an array of lines, extending those that price has not crossed and deleting those crossed.
checkLinesForBreaches(arrayOfLines) =>
    int qtyOfLines = array.size(arrayOfLines)
    // Don't loop in case there are no lines to check because "to" value will be `na` then`.
    for lineNo = 0 to (qtyOfLines > 0 ? qtyOfLines - 1 : na)
        // Need to check that array size still warrants a loop because we may have deleted array elements in the loop.
        if lineNo < array.size(arrayOfLines)
            line  currentLine    = array.get(arrayOfLines, lineNo)
            float lineLevel      = line.get_price(currentLine, bar_index)
            bool  lineWasCrossed = math.sign(close[1] - lineLevel) != math.sign(close - lineLevel)
            bool  lineIsTooLong  = bar_index - line.get_x1(currentLine) > maxLineLengthInput
            if lineWasCrossed or lineIsTooLong
                // Line stays on the chart but will no longer be extend on further bars.
                array.remove(arrayOfLines, lineNo)
                // Force type of both local blocks to same type.
                int(na)
            else
                line.set_x2(currentLine, bar_index)
                int(na)

// Arrays of lines containing non-crossed pivot lines.
var array<line> hiPivotLines = array.new_line(qtyOfPivotsInput)
var array<line> loPivotLines = array.new_line(qtyOfPivotsInput)

// Detect new pivots.
float hiPivot = ta.pivothigh(pivotLegsInput, pivotLegsInput)
float loPivot = ta.pivotlow(pivotLegsInput, pivotLegsInput)

// Create new lines on new pivots.
if not na(hiPivot)
    line newLine = line.new(bar_index[pivotLegsInput], hiPivot, bar_index, hiPivot, color = hiPivotColorInput)
    line.delete(qDq(hiPivotLines, qtyOfPivotsInput, newLine))
else if not na(loPivot)
    line newLine = line.new(bar_index[pivotLegsInput], loPivot, bar_index, loPivot, color = loPivotColorInput)
    line.delete(qDq(loPivotLines, qtyOfPivotsInput, newLine))

// Extend lines if they haven't been crossed by price.
checkLinesForBreaches(hiPivotLines)
checkLinesForBreaches(loPivotLines)

`同时`

while 结构允许重复执行语句 直到条件为假。其语法为:

[[<declaration_mode>] [<type>] <identifier> = ]while <expression>
<local_block_loop>

在哪里:

  • 方括号 ( []) 中的部分可以出现零次或一次。
  • <declaration_mode> 是变量的 声明模式
  • <type> 是可选的,就像几乎所有的 Pine Script™ 变量声明一样(参见类型
  • <identifier> 是变量的 名称
  • <expression> 可以是文字、变量、表达式或函数调用。它在循环的每次迭代中被评估。当它评估为 时true,循环执行。当它评估为 时,循环 false停止。请注意,表达式的评估仅在每次迭代之前进行。对循环内表达式值的更改只会对下一次迭代产生影响。
  • <local_block_loop> 由零个或多个语句组成,后跟一个返回值,返回值可以是一组值。它必须缩进四个空格或一个制表符。它可以包含break退出循环的语句,也可以continue包含退出当前迭代并继续下一个迭代的语句。
  • 分配给 <identifier> 变量的值是 <local_block_loop> 的返回值,即循环最后一次迭代计算出的最后一个值, 如果未执行循环,则为na 。

这是使用 while 结构而不是 for结构编写的for部分的第一个代码示例

//@version=5
indicator("`for` loop")
lookbackInput = input.int(50, "Lookback in bars", minval = 1, maxval = 4999)
higherBars = 0
lowerBars = 0
if barstate.islast
    var label lbl = label.new(na, na, "", style = label.style_label_left)
    // Initialize the loop counter to its start value.
    i = 1
    // Loop until the `i` counter's value is <= the `lookbackInput` value.
    while i <= lookbackInput
        if high[i] > high
            higherBars += 1
        else if high[i] < high
            lowerBars += 1
        // Counter must be managed "manually".
        i += 1
    label.set_xy(lbl, bar_index, high)
    label.set_text(lbl, str.tostring(higherBars, "# higher bars\n") + str.tostring(lowerBars, "# lower bars"))

注意:

  • 必须在while的本地块内明确将计数器i增加一 。
  • 我们使用 += 运算符将计数器加一。lowerBars += 1相当于lowerBars := lowerBars + 1

让我们使用while结构来计算阶乘函数

//@version=5
indicator("")
int n = input.int(10, "Factorial of", minval=0)

factorial(int val = na) =>
    int counter = val
    int fact = 1
    result = while counter > 0
        fact := fact * counter
        counter := counter - 1
        fact

// Only evaluate the function on the first bar.    
var answer = factorial(n)
plot(answer)

注意:

  • 我们使用 input.int() 作为输入,因为我们需要指定一个minval值来保护我们的代码。虽然 input() 也支持“int”类型值的输入,但它不支持参数minval
  • 我们将脚本的功能打包成一个factorial() 函数,该函数接受必须计算其阶乘的值作为参数。我们已使用 来int val = na声明函数的参数,这表示如果调用函数时没有参数,如factorial(),则val参数将初始化为 na ,这将阻止while循环的执行, 因为其counter > 0表达式将返回 na。 因此, while 结构将result变量初始化为 na。反过来,由于 的初始化result是我们函数本地块的返回值,因此函数将返回 na
  • 注意while局部块的最后一行 :。它是局部块的返回值,因此是 while 结构最后一次迭代fact的值 。
  • 初始化result不是必需的;我们这样做是为了提高可读性。我们也可以使用:
while counter > 0
    fact := fact * counter
    counter := counter - 1
    fact
Original text
Rate this translation
Your feedback will be used to help improve Google Translate