Pine Script 入门:从零写出第一个 TradingView 指标
Pine Script 是 TradingView 自带的脚本语言,用来写指标和策略。它的语法接近简化版的 Python,但有一个关键区别:它默认按「每根 K 线执行一次」来思考,而不是按「整个数据集」思考。理解这一点,大部分困惑会消失。
从哪里开始写
图表底部的 Pine 编辑器(Pine Editor)打开就能写。写完点「添加到图表」,脚本立刻出现在图上。
三个入口:
- 图表底部标签栏 → Pine 编辑器
- 右键图表 → 添加指标 → 打开脚本编辑器
- 指标搜索框输入「pine」也能找到入口
第一个脚本:一条均线
//@version=6
indicator("My EMA", overlay = true)
len = input.int(55, "周期")
src = close
myEma = ta.ema(src, len)
plot(myEma, color = color.new(color.orange, 0), linewidth = 2, title = "EMA")
逐行解释:
//@version=6:版本声明,必须是第一行。版本号决定可用函数,写你编辑器能通过的最新版本即可。indicator(...):声明这是一个指标。overlay = true表示画在价格图上,而不是单独开一个副图。input.int(...):生成一个可在设置里调整的参数。第一个值是默认值,第二个是显示名。ta.ema(...):内置的指数移动平均函数。plot(...):把计算结果画成线。
核心概念:序列
Pine 里几乎所有变量都是「序列」——它保存每一根 K 线上的值。
close // 每根 K 线的收盘价,是一条序列
close[1] // 上一根 K 线的收盘价
close[10] // 十根之前
[n] 这个写法是 Pine 的核心。做条件判断时经常用到:
isUp = close > close[1] // 这根比上一根高
isNewHigh = high == ta.highest(high, 20) // 创 20 根新高
注意 == 是比较,= 是赋值。这是新手第一个坑。
plot 与 plotshape 的区别
| 函数 | 画什么 | 用在哪 |
|---|---|---|
plot |
连续的线 | 均线、通道、波动率 |
plotshape |
单个图形标记 | 买卖信号、三角、圆点 |
plotchar |
字符 | 轻量标记 |
bgcolor |
背景色 | 状态区间 |
fill |
两条线之间填色 | 通道、区间 |
信号类指标几乎都用 plotshape:
longSignal = ta.crossover(close, myEma)
plotshape(longSignal, title = "做多", style = shape.triangleup,
location = location.belowbar, color = color.green, size = size.small)
location.belowbar 让标记出现在 K 线下方,这是多头信号的惯例。
避免未来函数的唯一规则
不要用当前 K 线的收盘价判断当前 K 线。 在实时行情里 close 一直在变,用它算出的信号会在盘中反复出现和消失,看起来像「重绘」。
正确做法是判断上一根已经收盘的 K 线:
confirmed = barstate.isconfirmed // 这根 K 线是否已收盘
signal = ta.crossover(close[1], myEma[1]) and confirmed
或者更简单:所有判断都用 [1] 索引,只在收盘时触发。这是判断一个脚本是否可信的最快方法——打开源码搜有没有 barstate.isconfirmed 或 [1]。
五个最常见的编译错误
| 报错关键词 | 原因 | 怎么改 |
|---|---|---|
Undeclared identifier |
变量名拼错或没定义 | 检查大小写,Pine 区分大小写 |
Cannot use 'plot' in local scope |
在 if 块里写了 plot | 把 plot 提到全局,用条件控制颜色或值 |
Mismatched input |
缩进或括号不配对 | Pine 用缩进表示层级,统一用 4 空格 |
The 'input' function... |
在函数内部声明 input | input 只能写在全局作用域 |
Cannot call 'ta.ema' with argument |
参数类型错,比如传了字符串 | ta.ema 的第二个参数必须是整数 |
调试方法
Pine 没有断点调试器。最实用的办法是用 label 或 plot 把中间变量打出来:
plot(myEma, color = color.orange)
plot(close, color = color.gray)
plotchar(bar_index, "index", "", location.top)
想看某个数值,就 plot 出来看形状对不对。这比读报错快得多。
要不要自己写指标
判断标准很简单:
- 想验证一个想法:值得写,二十行代码就够。
- 想做一个完整可用的交易系统:不建议。信号系统的复杂度在边界处理(跳空、数据缺失、换月),不在核心逻辑。
- 只是想要现成信号:不要自己写。写一个能用的信号指标,成本远高于订阅一个。
相关阅读
写完之后怎么验证它有没有未来函数,见《指标信号会重绘吗》;脚本怎么以邀请制发布给别人用,见《TradingView 邀请制指标怎么用》;用脚本做信号后如何设提醒,见《TradingView 警报怎么设》。