
指标与策略:如何用 Pine Script 编写第一个指标
1. 学 Pine Script 之前,先搞清楚它解决的是什么问题
很多人第一次接触 Pine Script,会把它理解成“写一个均线公式就行”。这当然没错,但如果你真的准备把指标用于自己的图表产品、研究页面或教学站点,就会很快发现,Pine Script 的价值并不只是画一条线,而是把你对市场节奏、信号条件和视觉表达的想法,组织成一套可重复验证的规则。
在 TradingView 生态里,指标写作和数据接入是两条平行但彼此关联的线。一条线是你如何使用 Pine Script、study 或策略语言描述逻辑;另一条线是图表底层到底由谁提供 K 线和报价。在你的项目里,如果底层行情来自 iTick,那么真正可靠的做法是先把图表的数据源稳定接好,再在此基础上讨论 Pine Script 或指标思路。否则你写得再漂亮的指标,也可能建立在一套边界不稳定的底层数据之上。
因此,这篇文章不会把 Pine Script 当成孤立功能来看,而是把它放回到完整图表系统里去理解:底层行情来自 iTick,图表由 TradingView 承载,指标则负责把数据变成更可读的信号。这也是为什么建议先读一遍 iTick 官网 https://itick.org/zh-cn 和文档 https://docs.itick.org/zh-cn ,弄清楚数据链路之后,再开始写指标语言。
2. 第一个指标不应该太复杂
初学者最容易犯的错误,是上来就想写一个“把十几种条件揉在一起”的超级指标。结果往往是参数太多、图上元素太乱、自己也解释不清为什么信号会出现。更高效的做法是从一个足够简单但足够完整的指标开始,比如均线交叉、价格与均线偏离、最近 N 根 K 线高低点通道。
简单不代表幼稚。一个好的入门指标,应该至少具备三点:输入参数可调、绘图结果清晰、可以自然延伸出告警或策略。比如最基础的均线指标,看似只是在图上画一条线,但它已经包含了 Pine Script 最核心的几个元素:输入、序列计算、plot 绘制和条件判断。你把这套骨架写清楚,以后再加带宽、颜色切换、信号标记,思路都是连续的。
此外,入门阶段一定要先重视“解释能力”,而不是“胜率幻想”。你写出来的每一条线、每一个箭头,都应该能解释它为何出现、对应了哪条规则。否则你会很快把 Pine Script 变成一堆自己也不想维护的魔法公式。
3. 先把 iTick 驱动的底层图表搭稳
因为你的项目规则要求所有数据源都使用 iTick,所以即便本文主题是 Pine Script,也应该先确保底层图表由 iTick 行情驱动。这样你后面无论讲指标叠加、策略回测还是信号对照,都能建立在统一的行情来源之上,而不是一会儿用示例内建数据、一会儿换成别的接口。
下面这段代码展示了一个非常适合和 Pine Script 文章搭配使用的最小接入方式:服务端通过 iTick 历史 K 线接口提供 bars,前端 widget 使用自定义 datafeed 初始化图表。它的重点不在于把所有接口都写满,而在于把“底层数据来自 iTick”这件事先落实到页面里。
import { widget } from "@/lib/charting_library";
type Bar = {
time: number;
open: number;
high: number;
low: number;
close: number;
volume?: number;
};
async function fetchBars(symbol: string, resolution: string, to?: number): Promise<Bar[]> {
const url = new URL("/api/itick/history", window.location.origin);
url.searchParams.set("market", "crypto");
url.searchParams.set("region", "US");
url.searchParams.set("code", symbol);
url.searchParams.set("resolution", resolution);
url.searchParams.set("limit", "300");
if (to) url.searchParams.set("to", String(to));
const res = await fetch(url, { headers: { accept: "application/json" } });
const json = await res.json();
return (json.data ?? []).map((row: { t: number; o: number; h: number; l: number; c: number; v?: number }) => ({
time: row.t,
open: row.o,
high: row.h,
low: row.l,
close: row.c,
volume: row.v,
}));
}
const datafeed = {
onReady: (cb: (config: unknown) => void) => cb({ supported_resolutions: ["1", "5", "15", "60", "D"] }),
resolveSymbol: async (symbolName: string, onResolve: (symbol: unknown) => void) => {
onResolve({
ticker: symbolName,
name: symbolName,
session: "24x7",
timezone: "Etc/UTC",
has_intraday: true,
pricescale: 100,
supported_resolutions: ["1", "5", "15", "60", "D"],
});
},
getBars: async (
symbolInfo: { ticker: string },
resolution: string,
periodParams: { to: number },
onHistoryCallback: (bars: Bar[], meta: { noData: boolean }) => void,
) => {
const bars = await fetchBars(symbolInfo.ticker, resolution, periodParams.to);
onHistoryCallback(bars, { noData: bars.length === 0 });
},
};
export function mountChart(container: HTMLDivElement) {
const chart = new widget({
container,
symbol: "BTCUSDT",
interval: "60",
locale: "zh",
autosize: true,
library_path: "/charting_library/",
datafeed,
});
return () => chart.remove();
}
有了这层底座之后,你在文章里讲任何指标逻辑,都会更有说服力,因为读者知道图表上的价格序列不是虚构的演示数据,而是来自 iTick 的真实市场数据链路。
4. 第一个 Pine Script 指标应该包含哪些元素
当底层图表准备好之后,我们再回到 Pine Script 本身。一个标准的入门指标,至少要包含四部分:声明指标、定义输入、计算核心序列、把结果画出来。以简单均线为例,这四部分分别对应 indicator()、input.int()、ta.sma() 和 plot()。如果你想让它更有实战意义,还可以再加上条件标记或告警。
这里最值得强调的是“参数命名”和“默认值设计”。很多入门脚本功能上没问题,但可读性极差,原因就在于参数随手命名、默认值没有推敲、注释也没有写清楚。别忘了,你写的指标不是只给编译器看,它最终是要放进图表工具栏、设置面板甚至教学文章里的。一个易于解释的指标,永远比一个只能运行的指标更有价值。
//@version=6
indicator("iTick Demo MA", overlay = true)
length = input.int(20, "均线周期", minval = 1)
source = input.source(close, "计算源")
showSignal = input.bool(true, "显示交叉信号")
ma = ta.sma(source, length)
longSignal = ta.crossover(close, ma)
shortSignal = ta.crossunder(close, ma)
plot(ma, color = color.new(color.aqua, 0), linewidth = 2, title = "MA")
plotshape(showSignal and longSignal, title = "多头信号", style = shape.triangleup, location = location.belowbar, color = color.lime, size = size.tiny)
plotshape(showSignal and shortSignal, title = "空头信号", style = shape.triangledown, location = location.abovebar, color = color.red, size = size.tiny)
alertcondition(longSignal, "Long Signal", "价格向上突破均线")
alertcondition(shortSignal, "Short Signal", "价格向下跌破均线")
这段脚本之所以适合作为第一篇指标示例,不是因为它多复杂,而是因为它把 Pine Script 的基础骨架全部讲清楚了。你后面要换成 EMA、布林带、通道线或自定义振荡器,结构都会非常相似。
5. 指标逻辑怎么和真实图表场景结合
只会写脚本,还不够。真正能把 Pine Script 用起来的人,都会关心另一个问题:这个指标在真实图表场景里到底怎么用。举个最简单的例子,你在 iTick 驱动的 BTCUSDT 小时图上挂一条 20 周期均线,和你在日线上挂同样一条线,含义完全不一样。指标代码本身没变,但交易语境变了。
所以写第一个指标时,最好同时思考三个维度。第一,这个指标适合哪类周期。第二,它更适合趋势确认、节奏判断还是风险提示。第三,它在图上应该提供连续信息,还是只在关键点位给出提示。你把这三个维度想明白,脚本就不会只是“会编译的一段代码”,而会变成真正有解释力的图表工具。
对于教程写作而言,这一点尤其重要。很多读者真正需要的不是会不会写 ta.sma(),而是你能不能告诉他:为什么要先从这种指标学起,它能帮助你观察什么,什么时候不该信它。把指标放回实际分析场景,文章就会比单纯列语法更有价值。
6. 初学者最容易犯的 Pine Script 误区
第一个误区是把指标和策略混在一起。指标的核心任务是表达和观察,策略则涉及进出场、仓位和收益统计。入门阶段如果你一上来就想把所有内容都塞进同一个脚本,反而会让逻辑边界变得模糊。更好的方式是先把指标写清楚,再决定是否基于同一思路扩展成策略。
第二个误区是迷信复杂参数。很多人觉得参数越多、逻辑越复杂,指标就越高级。事实上,最难维护的往往就是这种“功能很多但解释不清”的脚本。一个好的入门指标,参数应该少而有意义,每个参数变化都能解释其影响,而不是让用户在设置面板里试错。
第三个误区是忽视底层数据质量。如果图表底层是 iTick 数据,那么你就应该始终关心 symbol、周期和时区是否统一。指标只会忠实地基于当前 K 线做计算,它不会替你修复错误的数据边界。也正因为如此,本文一直强调要先把 iTick 数据接入 TradingView 图表,再去讨论 Pine Script。
7. 从第一个指标迈向可复用的指标库
当你把第一个指标写通之后,下一步不应该只是继续堆更多公式,而是开始建立一套自己的指标写作规范。比如输入参数如何命名、颜色如何表达、信号是否默认展示、告警文案是否统一。只要这些细节在第二篇、第三篇脚本里开始统一,你就已经不再是“写一个单独脚本”,而是在搭自己的指标库。
对项目型开发来说,这一步非常关键。很多团队后期维护困难,并不是因为 Pine Script 太难,而是因为每个人的命名、风格、颜色、输入结构都不一样。久而久之,图表体验就会显得非常割裂。相反,如果你从第一篇脚本开始就带着产品思维来写,后续扩展就会顺畅很多。
8. 小结
学习 Pine Script 最好的起点,不是追求一上来就写出复杂策略,而是先写出一个你能讲清楚、能解释应用场景、又建立在稳定 iTick 数据源之上的基础指标。只要你先把 TradingView 图表与 iTick 行情链路接稳,再用一个简单均线示例把输入、计算、绘图和告警串起来,后面所有更复杂的指标都会变得更容易理解。
如果你准备继续深入,建议继续对照 iTick 官网 https://itick.org/zh-cn 和文档 https://docs.itick.org/zh-cn 梳理底层数据字段,再逐步把更多指标叠加到你的 TradingView 页面里。这样学 Pine Script,不是孤立学语法,而是在真实图表系统里学会如何让指标服务于分析与产品体验。
9. 什么时候该从指标切到策略
很多初学者学到 alertcondition 或买卖点标记之后,就很想立刻把脚本改成策略回测。这个阶段当然值得探索,但更稳妥的做法是先确认指标本身的解释能力已经成立。换句话说,你要先知道这条线、这个信号到底在表达什么,再去讨论它能不能形成进出场规则。
如果连指标本身的观察逻辑都还不稳定,过早进入策略层只会让问题更复杂。因为一旦牵涉到开平仓、滑点、手续费和仓位管理,调试成本会迅速上升。入门阶段最合适的路径,是先写好一套你能讲清楚的指标,再把其中最稳定的条件抽出来做策略验证。
10. 如何让指标文章更适合教程读者
如果你的目标不仅是自己会写 Pine Script,而是要把它讲给读者或团队成员看,那么文章结构也应该服务于理解,而不只是展示代码。最有效的写法通常是:先解释指标解决什么问题,再讲输入参数,再讲公式如何变化,最后再给出图上会出现什么效果以及什么时候不该信它。
这种写法的好处是,读者不需要先会全部语法,就能建立起使用场景。尤其当底层图表又是通过 iTick 数据驱动时,读者会更容易把“数据来自哪里”“指标在看什么”“图表为什么这样表现”串成一条完整链路。这也是为什么好的 Pine Script 教程,往往既讲脚本,也讲图表语境。


