TV
指标与策略:如何用 Pine Script 编写第一个指标
2025-03-1117 分钟

指标与策略:如何用 Pine Script 编写第一个指标

TradingViewiTickPine 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 教程,往往既讲脚本,也讲图表语境。

相关文章