用户自定义函数是由程序员编写的函数,不同于 Pine Script内置提供的函数。它们用于封装脚本中需要有条件执行或重复执行的自定义计算,或者将逻辑集中在一个位置,以提升模块化程度和代码可读性。当现有的内置函数无法满足需求时,程序员通常会编写自定义函数来扩展脚本的功能。
一个函数定义由两个主要部分组成:函数头(Header) 和 函数体(Body)。
函数头(Header)
函数头声明了函数的签名,也就是函数的名称和参数。脚本通过创建一个包含函数名并跟随括号的表达式来调用该函数(例如 f())。
函数体(Body)
函数体是紧随函数头之后的代码。每一次函数调用,都会执行函数体中由表达式和语句定义的任务。
用户自定义函数的通用特性和限制
无论函数的格式、位置或用途如何,所有用户自定义函数都遵循以下共同特性和限制:
- 函数的定义必须位于全局作用域。程序员不能在另一个函数的函数体内,或其他任何结构的局部代码块中定义函数。
- 函数不能修改其已声明的参数,也不能修改任何全局变量。
- 函数体内可以调用大多数其他函数,但不能调用自身,也不能调用必须从全局作用域调用的函数。
- 函数的每一次书写调用,在所有执行过程中都必须具有一致的参数类型,因此传入的参数类型也必须一致。
- 每一次调用都会返回函数体中最后一个语句或独立表达式的计算结果,并且该结果会继承调用中使用的最强类型限定符。与参数类型一样,返回值类型在不同执行中也必须保持一致。
- 每一次对函数的书写调用都会基于函数定义创建一个新的作用域。在该作用域中创建的参数、变量和表达式都是独立的,并且拥有各自的历史记录;不同的函数调用不会直接相互影响。
函数头语法
[export ]<functionName>([[[paramQualifier ]<paramType> ]<paramName>[ = defaultValue], …]) =>
其中:
- 方括号 [] 中的内容表示可选语法,尖括号 <> 中的内容表示必需语法。
- export 是一个可选关键字,用于将函数从库中导出,使其可以在其他脚本中使用。详情请参阅 Libraries 页面。
- functionName 是函数的标识符(名称)。脚本通过引用该标识符并跟随括号来调用函数。
- paramName 是已声明参数的标识符。脚本在每次函数调用时,可以为该参数提供具体的参数值(值或引用)。函数头中可以声明零个或多个参数。
- defaultValue 是参数的默认值。如果未指定默认值,则每次调用函数时都必须为该参数提供参数;如果指定了默认值,则传参是可选的。
- paramQualifier 和 paramType 是限定符和类型关键字,它们共同指定参数的限定类型。在大多数情况下,这些关键字是可选的。如果未包含它们,编译器会自动推断参数的类型信息。更多内容请参阅 Declaring parameter types 部分。
单行函数 – 示例1
单行函数的函数体与函数头位于同一行代码中。该格式非常适合用于定义紧凑的函数,这类函数只执行简单的语句,并且不使用条件结构或循环。定义单行函数的语法如下:
<functionHeader> => {statement, }<returnExpression>
其中,functionHeader 用于声明函数的名称和参数,其含义与上一节中的说明一致。花括号中的 statement 表示函数在返回结果之前要执行的零个或多个语句或表达式,函数体中的每一条独立语句都必须使用逗号分隔。returnExpression 是函数体中的最后一个表达式、变量或元组,每一次函数调用都会返回对该部分代码求值后的结果。
下面的示例以单行格式定义了一个 add() 函数。该函数包含两个参数 val1 和 val2。函数体中只有一个 + 运算,根据参数的类型不同,该运算可以执行数值相加或字符串拼接。每次调用该函数,都会返回该运算的结果:
add(val1, val2) => val1 + val2
在脚本中包含了该函数定义之后,就可以在不同的位置调用 add(),并为 val1 和 val2 传入不同的参数。每一次调用所返回的值类型,取决于传入参数的类型。例如,在下面的脚本中,会执行多次 add() 调用,然后将其返回结果传递给 plot() 函数的 series、title 和 linewidth 参数。

下面逐行解析代码:
- 指定脚本版本。
- 声明这是一个指标脚本,并设置指标名称。
- 定义一个单行函数 add()。
- 调用 add() 函数,并把返回结果存入变量 a。
- 把变量 a 画成一条线。
- 最终效果:在图表上画出一条线,其数值等于每根 K 线的 open + close。

单行函数 – 示例2
例如,下面的脚本以单行格式定义了一个 zScore() 函数。该函数用于计算某个源数据序列在 length 根 K 线上的 Z-Score(标准分数)。函数体中声明了两个变量 mean 和 sd,分别用于保存该序列的平均值和标准差。函数体中的最后一个表达式使用这两个变量来计算并返回函数的结果。脚本在每一根 K 线上都会调用一次 zScore() 函数,使用 close 作为源数据参数、20 作为长度参数,然后将计算结果绘制出来。

核心部分是 zScore 函数的定义。函数使用多行单行函数写法,通过箭头符号 => 声明。函数接收两个参数:source 表示数据序列,如收盘价 close,length 表示计算周期,如 20 根 K 线。函数内部首先计算 mean = ta.sma(source, length),即 source 的简单移动平均,用于反映周期内的均值;然后计算 sd = ta.stdev(source, length),即标准差,用于衡量数据的波动性。最后,函数返回 (source - mean) / sd,即标准分数(Z-score),表示当前值与均值的偏离程度以标准差为单位。
在函数定义之后,脚本调用 zScore 函数:float osc = zScore(close, 20)。这里使用收盘价作为源数据,计算 20 根 K 线周期的 Z-score,并将结果存入变量 osc。由于 Z-score 随每根 K 线变化,因此 osc 实际上是一个随时间变化的序列(series float),每根 K 线都有对应的值。
最后,脚本通过 plot 函数将 osc 绘制在独立面板上。plot(osc, "Z-score", osc > 0 ? color.green : color.red, style = plot.style_columns) 指定了绘制的数据为 osc,图例名为 “Z-score”,并根据值的正负设置颜色:正值为绿色,负值为红色,同时使用柱状图风格 plot.style_columns 展示每根柱子的高度。这样,独立面板上便能直观显示价格相对于均值的标准差偏离,绿色柱表示高于均值,红色柱表示低于均值。

本文系统介绍了 TradingView Pine Script 中用户自定义函数的概念、定义方法及使用技巧。文章首先讲解了函数的组成,包括函数头部的名称与参数声明以及函数体中表达式和语句的执行逻辑,并区分了单行函数与多行函数的写法与适用场景。随后通过具体示例,如 add() 和 zScore(),展示了函数的实际应用,包括如何封装重复计算、处理序列数据、返回计算结果以及在脚本中调用函数。
总体而言,通过对函数定义、调用、序列计算及绘图技巧的详细解析,读者不仅能够掌握 Pine Script 中自定义函数的使用方法,还能够灵活构建可复用、模块化的指标脚本,为日后的策略开发和指标优化提供坚实基础。

%20(1).jpg)
.jpg)
.jpg)





