在编写策略时,我们经常会在一行代码里用到好几个运算符,比如 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)。
其实你不用死记硬背这张表,拿不准的时候,直接加括号()明确运算顺序,永远是最稳妥的做法。
通过括号强制改变运算顺序
我们可以用括号()把表达式的某一部分括起来,强行改变默认的运算顺序。因为括号的优先级最高,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()函数把结果画到图上。我们期望通过 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中使用嵌套括号
有时表达式比较复杂,需要多层括号互相嵌套。这种情况下,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。
相关文章阅读




