Pine Script™ 中的条件结构是if和 switch。它们可以用于:
- 对于它们的副作用,即当它们不返回值但执行某些操作时,例如将值重新分配给变量或调用函数。
- 返回一个值或一个元组,然后可以将其分配给一个(或多个,如果是元组)变量。
条件结构,如for 和while结构,可以嵌入;您可以在另一个结构中使用 if或 switch 。
某些 Pine Script™ 内置函数无法从条件结构的本地块内调用。它们是: alertcondition()、 barcolor()、 fill()、 hline()、 indicator()、 library()、 plot()、 plotbar()、 plotcandle()、 plotchar()、 plotshape()、 strategy()。这并不意味着它们的功能不能通过脚本评估的条件来控制——只是不能通过将它们包含在条件结构中来完成。请注意,虽然input*.()
本地块中允许函数调用,但它们的功能与脚本全局范围内的功能相同。
条件结构中的局部块必须缩进四个空格或制表符。
用于其副作用的if结构具有以下语法:
if <expression>
<local_block>
{else if <expression>
<local_block>}
[else
<local_block>]
在哪里:
- 方括号 (
[]
) 中的部分可以出现零次或一次,大括号 ({}
) 中的部分可以出现零次或多次。 - <表达式> 必须是“bool”类型或者可以自动转换为该类型,这仅适用于“int”或“float”值(请参阅类型系统页面)。
- <local_block> 由零个或多个语句组成,后跟一个返回值,该返回值可以是值的元组。它必须缩进四个空格或制表符。
- 可以有零个或多个子句。
else if
- 可以有零个或一个
else
子句。
当if后面的 计算结果为true时,将执行第一个本地块,if 结构的执行结束,并返回在本地块末尾计算的值。
当if后面的 计算结果为false时,将计算后续子句(如果有)。当 one 的 计算结果为true时,执行其本地块,if 结构的执行结束,并返回在本地块末尾计算的值。else if
当没有 计算为true 并且else
存在子句时,将执行其本地块,if 结构的执行结束,并返回在本地块末尾计算的值。
当没有 的计算结果为true 并且不else
存在子句时,将返回na 。
例如,使用if 结构的副作用对于管理策略中的订单流很有用。虽然通常可以使用调用when
中的参数 来实现相同的功能strategy.*()
,但使用if 结构的代码更易于阅读:
if (ta.crossover(source, lower))
strategy.entry("BBandLE", strategy.long, stop=lower,
oca_name="BollingerBands",
oca_type=strategy.oca.cancel, comment="BBandLE")
else
strategy.cancel(id="BBandLE")
可以使用 if 结构将代码的执行限制在特定的柱上,就像我们在这里将标签的更新限制在图表的最后一个柱上一样:
//@version=5
indicator("", "", true)
var ourLabel = label.new(bar_index, na, na, color = color(na), textcolor = color.orange)
if barstate.islast
label.set_xy(ourLabel, bar_index + 2, hl2[1])
label.set_text(ourLabel, str.tostring(bar_index + 1, "# bars in chart"))
注意:
ourLabel
我们仅在脚本的第一个栏上 初始化变量,因为我们使用var声明模式。用于初始化变量的值由 label.new()函数调用提供,该函数返回一个指向它创建的标签的标签 ID。我们使用该调用来设置标签的属性,因为一旦设置,它们将持续存在,直到我们更改它们为止。- 接下来发生的是,在每个连续的柱上,Pine Script™ 运行时将跳过 的初始化
ourLabel
,并评估if 结构的条件 ( barstate.islast )。它在所有柱上返回false
,直到最后一个柱,因此脚本在零柱之后的大多数历史柱上不执行任何操作。 - 在最后一个柱上,barstate.islast 变为 true 并且结构的本地块执行,在每个图表上修改更新我们的标签的属性,该属性显示数据集中的柱数。
- 我们希望在没有背景的情况下显示标签的文本,因此我们 在label.new()函数调用中将标签的背景设置为na ,并用于标签的y位置,因为我们不希望它一直移动。通过使用前一个柱的高值 和低值的平均值,标签不会移动,直到下一个实时柱打开。
hl2[1]
- 我们在label.set_xy()调用中使用 将标签向右偏移两个条。
bar_index + 2
用于返回一个或多个值的if结构 具有以下语法:
[<declaration_mode>] [<type>] <identifier> = if <expression>
<local_block>
{else if <expression>
<local_block>}
[else
<local_block>]
在哪里:
- 方括号 (
[]
) 中的部分可以出现零次或一次,大括号 ({}
) 中的部分可以出现零次或多次。 - <declaration_mode> 是变量的声明模式
- 是可选的,就像在几乎所有 Pine Script™ 变量声明中一样(请参阅types)
- 是变量的名称
- <表达式> 可以是文字、变量、表达式或函数调用。
- <local_block> 由零个或多个语句组成,后跟一个返回值,该返回值可以是值的元组。它必须缩进四个空格或制表符。
- 分配给该变量的值是 <local_block> 的返回值, 如果没有执行本地块,则为na 。
这是一个例子:
//@version=5
indicator("", "", true)
string barState = if barstate.islastconfirmedhistory
"islastconfirmedhistory"
else if barstate.isnew
"isnew"
else if barstate.isrealtime
"isrealtime"
else
"other"
f_print(_text) =>
var table _t = table.new(position.middle_right, 1, 1)
table.cell(_t, 0, 0, _text, bgcolor = color.yellow)
f_print(barState)
可以省略else块。在这种情况下,如果condition
为 false,则会将空值(na
、false
或""
)分配给该 var_declarationX
变量。
这是一个示例,显示 当没有执行本地块时如何返回na 。如果在这里, 则返回na :close > open``false
x = if close > open
close
脚本可以包含if
嵌套结构if
和其他条件结构。例如:
if condition1
if condition2
if condition3
expression
但是,从性能角度来看,不建议嵌套这些结构。如果可能,通常更优化的做法是使用多个逻辑运算符组成单个if
语句,而不是多个嵌套if
块:
if condition1 and condition2 and condition3
expression
开关 结构有两种形式。可以切换键表达式的不同值:
[[<declaration_mode>] [<type>] <identifier> = ]switch <expression>
{<expression> => <local_block>}
=> <local_block>
另一种形式不使用表达式作为键;它打开不同表达式的求值:
[[<declaration_mode>] [<type>] <identifier> = ]switch
{<expression> => <local_block>}
=> <local_block>
在哪里:
- 方括号 (
[]
) 中的部分可以出现零次或一次,大括号 ({}
) 中的部分可以出现零次或多次。 - <declaration_mode> 是变量的声明模式
- 是可选的,就像在几乎所有 Pine Script™ 变量声明中一样(请参阅types)
- 是变量的名称
- <表达式> 可以是文字、变量、表达式或函数调用。
- <local_block> 由零个或多个语句组成,后跟一个返回值,该返回值可以是值的元组。它必须缩进四个空格或制表符。
- 分配给该变量的值是 <local_block> 的返回值, 如果没有执行本地块,则为na 。
- 最后的允许您指定一个返回值,该返回值充当结构中没有执行其他情况时使用的默认值。
=> <local_block>
仅执行switch结构的一个本地块。因此,它是一个不会因情况而异的**结构化交换机。因此,声明是不必要的。break
这两种形式都可以作为用于初始化变量的值。
让我们看一个 使用表达式的switch示例:
//@version=5
indicator("Switch using an expression", "", true)
string maType = input.string("EMA", "MA type", options = ["EMA", "SMA", "RMA", "WMA"])
int maLength = input.int(10, "MA length", minval = 2)
float ma = switch maType
"EMA" => ta.ema(close, maLength)
"SMA" => ta.sma(close, maLength)
"RMA" => ta.rma(close, maLength)
"WMA" => ta.wma(close, maLength)
=>
runtime.error("No matching MA type found.")
float(na)
plot(ma)
注意:
- 我们要打开的表达式是变量,它是“input int”类型(有关“ input
maType
”限定符是什么的解释,请参见此处)。由于它在脚本执行期间无法更改,这保证了用户选择的任何 MA 类型都将在每个柱上执行,这是像 ta.ema()这样的函数的要求 ,这些函数需要一个“简单 int”参数作为其参数。length
- 如果没有找到 的匹配值
maType
,则交换机 将执行由 引入的最后一个本地块=>
,该块充当包罗万象的角色。我们在该块中生成运行时错误。我们还以float(na)
这样的方式结束它,以便本地块返回一个其类型与结构中其他本地块的类型兼容的值,以避免编译错误。
这是不使用表达式的switch结构的示例:
//@version=5
strategy("Switch without an expression", "", true)
bool longCondition = ta.crossover( ta.sma(close, 14), ta.sma(close, 28))
bool shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))
switch
longCondition => strategy.entry("Long ID", strategy.long)
shortCondition => strategy.entry("Short ID", strategy.short)
注意:
- 我们使用开关 来选择要发出的适当策略顺序,具体取决于
longCondition
或shortCondition
“bool”变量是否为true
。 longCondition
和的建筑条件shortCondition
是排他性的。虽然它们可以false
同时存在,但它们不能true
同时存在。 因此,仅执行switch结构的一个本地块这一事实对我们来说不是问题。- 我们在进入 switch结构之前评估对ta.crossover() 和ta.crossunder() 的调用。不这样做(如以下示例所示)将阻止在每个柱上执行函数,这将导致编译器警告和不稳定的行为:
//@version=5
strategy("Switch without an expression", "", true)
switch
// Compiler warning! Will not calculate correctly!
ta.crossover( ta.sma(close, 14), ta.sma(close, 28)) => strategy.entry("Long ID", strategy.long)
ta.crossunder(ta.sma(close, 14), ta.sma(close, 28)) => strategy.entry("Short ID", strategy.short)
当结构体中使用多个局部块时,其所有局部块的返回值类型必须匹配。这仅适用于在声明中使用结构体为变量赋值的情况,因为变量只能有一种类型,如果语句在其分支中返回两种不兼容的类型,则无法正确确定变量类型。如果该结构未分配到任何位置,则其分支可以返回不同的值。
这段代码编译得很好,因为close 和open都是以下类型float
:
x = if close > open
close
else
open
此代码无法编译,因为第一个本地块返回一个float
值,而第二个本地块返回 a string
,并且 - 语句的结果if
分配给x
变量:
// Compilation error!
x = if close > open
close
else
"open"