条件结构
介绍
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` 用于其副作用
用于其副作用的if结构具有以下语法:
在哪里:
- 方括号 (
[]
) 中的部分可以出现零次或一次,花括号 ({}
) 中的部分可以出现零次或多次。 - <expression> 必须是“bool”类型或可自动转换为该类型,这仅适用于“int”或“float”值(请参阅类型系统页面)。
- <local_block> 由零个或多个语句组成,后跟一个返回值,返回值可以是值的元组。必须缩进四个空格或一个制表符。
- 可以有零个或多个
else if
子句。 - 可以有零个或一个
else
子句。
当if后面的 <expression> 计算结果为 true时,将执行第一个本地块, if 结构的执行结束,并返回在本地块末尾计算的值。
如果if后面的 <expression>
求值为
false,则将求值后续else if
子句(如果有)。如果其中一个子句的 <expression> 求值为
true,则执行其本地块,
结束if
结构的执行,并返回在本地块末尾求值的值。
当没有 <expression> 被评估为
true
并且else
存在子句时,将执行其本地块,
if
结构的执行结束,并返回在本地块末尾评估的值。
当所有 <expression> 均未求值为
真
且不else
存在子句时,
将返回na 。
例如,使用if
结构来处理副作用可能有助于管理策略中的订单流。虽然通常可以使用调用when
中的参数来实现相同的功能,但使用ifstrategy.*()
结构的代码
更易于阅读:
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"))
注意:
- 由于我们使用var声明模式,因此我们
ourLabel
仅在脚本的第一个条上初始化变量 。用于初始化变量的值由 label.new() 函数调用提供,该函数调用返回指向其创建的标签的标签 ID。我们使用该调用来设置标签的属性,因为一旦设置,它们将一直存在,直到我们更改它们。 - 接下来发生的事情是,在每个连续的条形图上,Pine Script™ 运行时将跳过 的初始化
ourLabel
,并 评估if 结构的条件 ( barstate.islastfalse
)。它会返回所有条形图,直到最后一个条形图,因此脚本在条形图零之后的大多数历史条形图上不执行任何操作。 - 在最后一根柱线上, barstate.islast 变为真,并且结构的本地块执行,在每个图表上修改更新我们的标签的属性,显示数据集中的柱线数量。
- 我们想要显示没有背景的标签文本,因此我们
在
label.new()函数调用中将标签的背景设为na
,并使用来表示标签的y位置,因为我们不希望它一直移动。通过使用前一个条形图的
最高值
和
最低值的平均值
,标签直到下一个实时条形图打开时才会移动。
hl2[1]
- 我们
bar_index + 2
在 label.set_xy() 调用中使用来将标签向右偏移两个条。
`if` 用于返回值
用于返回一个或多个值的if结构具有以下语法:
在哪里:
- 方括号 (
[]
) 中的部分可以出现零次或一次,花括号 ({}
) 中的部分可以出现零次或多次。 - <declaration_mode> 是变量的 声明模式
- <type> 是可选的,就像几乎所有的 Pine Script™ 变量声明一样(参见类型)
- <identifier> 是变量的 名称
- <expression> 可以是文字、变量、表达式或函数调用。
- <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
为假,则会为变量分配一个空值(na
、false
或) 。""
var_declarationX
这是示例,说明
当未执行任何本地块时如何返回naclose > open
。如果在false
此处,
则返回na :
x = if close > open
close
脚本可以包含if
嵌套结构if
和其他条件结构。例如:
if condition1
if condition2
if condition3
expression
但是,从性能角度来看,不建议嵌套这些结构。如果可能,if
使用多个逻辑运算符而不是多个嵌套if
块来编写单个语句通常是更理想的选择:
if condition1 and condition2 and condition3
expression
`switch`结构
switch结构 有两种形式。一种是针对某个键表达式的不同值进行切换:
另一种形式不使用表达式作为键;它开启不同表达式的评估:
在哪里:
- 方括号 (
[]
) 中的部分可以出现零次或一次,花括号 ({}
) 中的部分可以出现零次或多次。 - <declaration_mode> 是变量的 声明模式
- <type> 是可选的,就像几乎所有的 Pine Script™ 变量声明一样(参见类型)
- <identifier> 是变量的 名称
- <expression> 可以是文字、变量、表达式或函数调用。
- <local_block> 由零个或多个语句组成,后跟一个返回值,返回值可以是值的元组。必须缩进四个空格或一个制表符。
- 分配给变量的值是 <local_block> 的返回值, 如果没有执行本地块,则为na 。
- 最后
=> <local_block>
允许您指定一个返回值,该返回值作为在结构中没有其他情况被执行时使用的默认值。
switch
结构只执行一个局部块
。因此,它是一个不会
出现任何情况的结构化 switch。因此,不需要语句。break
两种形式都可以用作初始化变量的值。
用表达式进行 `switch`
让我们看一个 使用表达式的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)
注意:
- 我们要打开的表达式是变量
maType
,它是“输入 int”类型(请参阅此处了解“输入”限定符的解释)。由于它在脚本执行期间无法更改,因此这保证了用户选择的任何 MA 类型都将在每个条上执行,这是ta.ema()等函数的要求, 这些函数需要“简单 int”作为其length
参数。 - 如果未找到匹配的值
maType
,则 switch 将执行由引入的最后一个本地块=>
,该块充当一个捕获所有块的角色。我们在该块中生成一个运行时错误。我们还以 结束它,float(na)
以便本地块返回一个类型与结构中其他本地块的类型兼容的值,以避免编译错误。
没有表达式的`switch`
这是一个不使用表达式的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
值,而第二个本地块返回一个string
,并且语句的结果if
被分配给x
变量:
// Compilation error!
x = if close > open
close
else
"open"