保持敬畏之心
交易是一场持久战

Pine Script(2):运算符及其优先级

在编写策略时,我们经常会在一行代码里用到好几个运算符,比如 close > open and volume > 2000。但你有没有想过一个问题:在一行复杂的计算中,电脑到底会先算哪个、后算哪个?

这个问题不是钻牛角尖,它直接关系到你策略逻辑的生死。如果搞不清楚计算的先后顺序,代码最终执行的结果,可能跟你设想的完全是两码事。一个微小的顺序错误,就可能导致你的买卖信号在错误的时间出现,甚至让止损计算完全失效。这个计算的先后顺序,在编程里就叫“运算符优先级”。

这跟你上小学时学的“先乘除,后加减”是同一个道理。Pine Script 给每个运算符都设定了固定的“辈分”,在计算时永远是“辈分”高的运算符先执行。

有了这个规则,Pine Script 才能确保每一行代码,无论多复杂,都能以一种统一、可预测的方式来执行,避免产生歧义。

举个最经典的例子:2 + 10 * 5

如果让一个不了解优先级规则的人从左到右算,结果是 12 * 5 = 60。但实际上,因为乘法 * 的“辈分”比加法 + 高,Pine Script 会先算 10 * 5 得到 50,再用 2 去加,最终结果是 52。你看,只是顺序不同,结果就差了很远。如果这是一个计算风险或资金的公式,那后果就不堪设想了。

为了帮你彻底避免踩中这类“逻辑地雷”,下面这张表,就是 Pine Script 官方的“运算符辈分排行榜”。优先级越高的运算符,排位越靠前,也就会被越先计算。强烈建议你收藏起来,时常对照。

优先级 运算符 名称 示例与说明
10 ( ) 括号 (high + low + close) / 3(括号拥有最高优先级,可强制改变运算顺序。此示例计算K线的平均价格。)
9 [ ] 历史引用运算符 close[1](获取系列数据的前一个值,如此处获取上一根K线的收盘价。)
8 + 一元正号 +close  (表示一个正数,通常是可选的,因为数值默认为正。)
- 一元负号 -ta.atr(14)  (取一个值的负数,例如将ATR指标值转为负数用于计算。)
not 逻辑“非” not (close > open)  (对布尔值取反。如果close > open为真,则结果为假。)
7 * 乘法 ta.atr(14) * 2  (计算14周期ATR指标值的两倍,常用于设定止损距离。)
/ 除法 ta.sma(close, 10) / ta.sma(close, 20)  (计算短期均线与长期均线的比率。)
% 求模 (取余数) bar_index % 20 == 0  (判断当前K线序号是否为20的倍数,常用于周期性执行任务。)
6 + 二元加法 low + ta.atr(14)  (将最低价与ATR值相加,可用于计算一个动态支撑位。)
- 二元减法 high - low  (计算K线的振幅范围。)
5 > 大于 close > ta.sma(close, 50)  (判断收盘价是否在50周期简单移动平均线之上。)
< 小于 ta.rsi(close, 14) < 30  (判断RSI指标值是否进入超卖区域。)
>= 大于或等于 volume >= ta.sma(volume, 20)  (判断成交量是否大于或等于其20周期的均量。)
<= 小于或等于 high <= high[1]  (判断当前K线的最高价是否未超过前一根K线的最高价。)
4 == 等于 ta.cross(close, ta.sma(close, 10)) (判断收盘价是否与10周期均线发生交叉。注意:在Pine Script中,使用ta.cross函数来判断交叉比直接用 == 更可靠。)
!= 不等于 strategy.position_size != 0  (判断当前是否存在持仓。)
3 and 逻辑“与” close > open and volume > ta.sma(volume, 20)  (判断是否同时满足两个条件:收阳线且成交量高于均量。)
2 or 逻辑“或” close < ta.lowest(low, 10) or close > ta.highest(high, 10)  (判断价格是否突破了过去10根K线的最低价或最高价。)
1 ?: 条件三元运算符 close > open ? color.green : color.red  (如果close > open为真,则返回绿色;否则返回红色。常用于动态设定颜色。)

从上表可以看出,加号(+)和减号(-)既可以作为一元运算符,也可以作为二元运算符。当运算符只作用于单个操作数时,我们称之为一元运算符(例如 -close,用于获取收盘价的负值);当它作用于两个操作数时,则被称为二元运算符(例如 high - low)。

此外,表中还有一些运算符的优先级是相同的。当一个表达式中包含多个优先级相同的运算符时,它们将按照从左到右的顺序进行计算。例如,加法(+)和减法(-)的优先级相同,因此表达式 9 - 3 + 22 - 3 的计算结果是 25(计算过程:9 - 3 得 6,6 + 22 得 28,28 - 3 得 25)。

Ps:您无需死记硬背所有规则;在不确定时,使用括号 () 来明确指定运算顺序,永远是最佳实践。

通过括号强制改变运算顺序

我们可以通过括号 () 将表达式的某些部分括起来,从而改变其默认的运算顺序。由于括号的优先级是最高的,TradingView 会最先计算括号内的表达式。

例如表达式 10 + 9 * close 会先执行乘法 9 * close,再与 10 相加,因为乘法的优先级高于加法。但如果我们写成 (10 + 9) * close,程序则会先计算 10 + 9,再将结果与 close 相乘。

在某些场景下,我们必须使用括号才能确保计算的正确性。例如,下面这个脚本尝试计算每根K线的中点:

//@version=5
indicator(title="Mr Chen", overlay=true)

// 尝试计算中点
plot(high + low / 2, color=color.blue, linewidth=2)

代码中,我们用 indicator() 函数设置了指标属性,并用 plot() 函数来绘图 (TradingView, n.d.)。我们期望通过 high + low / 2 来绘制出K线的中点。

但当把这个指标添加到图表后,它的实际表现如下图所示:

很明显,计算结果出错了。问题就出在 high + low / 2 这个表达式上,我们忽略了运算符的优先级规则。由于除法(/)的优先级高于加法(+),代码实际执行的是先计算 low / 2,再将结果与 high 相加。这显然不是我们想要的K线中点。

为了修正这个错误,我们必须使用括号来强制改变运算顺序,像这样将 high + low 括起来:

//@version=5
indicator(title="Mr Chen", overlay=true)

// 正确计算中点
plot((high + low) / 2, color=color.blue, linewidth=2)

当我们把修改后的脚本应用到图表上,它就能正确地绘制出每根K线的中点了:

在 Pine 中使用嵌套括号

有时我们会遇到复杂的表达式,需要将多层括号相互嵌套。在这种情况下,TradingView的Pine会遵循从内向外的原则,即最先计算最里层的括号。

我们以下面的变量 x 的计算为例:

x = (7 % 3) * (4 + (6 / 2))

遵循从内向外的原则,Pine首先计算最里层的 (6 / 2),结果为3。表达式变为:

x = (7 % 3) * (4 + 3) 

接下来,程序会依次计算余下的括号:

x = 1 * 7           // 因为 (7 % 3) 的余数是 1, 而 (4 + 3) 等于 7

最终,变量 x 的值为7:

x = 7

总结

一个表达式中多个运算符的计算顺序取决于两点:优先级和计算方向。优先级高的运算符先于优先级低的进行计算。当优先级相同时,则遵循从左到右的顺序。而括号 () 拥有最高的优先级,我们可以利用它来强制改变默认的运算顺序。懂了没,是不是很简单?pine的学习难度将会比MQL4容易很多,感兴趣的加学长微信进群交流:u31u31。

赞(0)
未经允许不得转载:图道交易 » Pine Script(2):运算符及其优先级
分享到

评论 抢沙发