库
介绍
Pine Script™ 库是包含可在指标、策略或其他库中重复使用的函数的出版物。它们可用于定义常用函数,因此不必在需要它们的每个脚本中包含其源代码。
库必须先发布(私下或公开),然后才能在其他脚本中使用。所有库均以开源形式发布。公共脚本只能使用公共库,并且必须是开源的。保存在 Pine Script™ Editor 中的私有脚本或个人脚本可以使用公共或私有库。库可以使用其他库,甚至可以使用其自身的先前版本。
库程序员应该熟悉 Pine Script™ 的类型命名法、范围和用户定义函数。如果您需要复习合格类型,请参阅用户手册中的类型系统页面 。有关用户定义函数和范围的更多信息,请参阅 用户定义函数页面。
您可以在TradingView的社区脚本中浏览会员公开发布的库脚本。
创建库
库是一种特殊的脚本,以 library() 声明语句开头,而不是 indicator() 或 strategies()。库包含可导出的 function、 method、 UDT和enum定义,当由另一个脚本导入时,它们构成库中唯一可见的部分。与其他脚本类型一样,库也可以在其全局范围内包含 Pine Script™ 代码。程序员通常使用库的全局代码来演示其他脚本如何使用其导出的结构。
库脚本具有如下结构,其中必须包含一个或多个可导出的函数或类型:
//@version=5
// @description <library_description>
library(title, overlay)
<script_code>
//@type <type_description>
//@field <field_name> <field_description>
// ...
export type <UDT_identifier>
<field_type> <field_name>[ = <value>]
...
//@enum <enum_description>
//@field <field_name> <field_description>
// ...
export enum <enum_name>
<field_name>[ = <field_title>]
...
//@function <function_description>
//@param <parameter> <parameter_description>
//@returns <return_value_description>
export <function_name>([simple/series] <parameter_type> <parameter_name> [= <default_value>] [, ...]) =>
<function_code>
<script_code>
注意:
//@description
、、、、、和编译器注释是可选的, 但我们强烈建议您使用它们。这些注释记录了库的代码并填充了默认库描述,作者可以在发布库时使用它们//@enum
。//@type
@field
// @function
// @param
// @returns
- export关键字 是强制性的。
- <parameter_type> 是强制性的,与指标或策略中的用户定义函数参数定义相反,它们是无类型的。
- <script_code> 可以是指标中通常使用的任何代码,包括输入。
这是一个示例库:
//@version=5
// @description Provides functions calculating the all-time high/low of values.
library("AllTimeHighLow", true)
// @function Calculates the all-time high of a series.
// @param val Series to use (`high` is used if no argument is supplied).
// @returns The all-time high for the series.
export hi(float val = high) =>
var float ath = val
ath := math.max(ath, val)
// @function Calculates the all-time low of a series.
// @param val Series to use (`low` is used if no argument is supplied).
// @returns The all-time low for the series.
export lo(float val = low) =>
var float atl = val
atl := math.min(atl, val)
plot(hi())
plot(lo())
库函数
库中的函数定义与指标和策略中的用户定义函数略有不同。对于库函数主体中可以包含的内容存在限制。
在库函数签名(其第一行)中:
- export关键字 是强制性的。
- 必须明确提及每个参数所需的参数类型。
- 简单 或 系列关键字可以限制允许的 合格参数类型(下一节将解释它们的用法)。
这些是对库函数施加的限制:
- 它们不能使用库全局范围内的变量,除非它们被限定为“const”。这意味着您不能使用从脚本输入初始化的全局变量,或者全局声明的数组。
request.*()
不允许拨打电话。input.*()
不允许拨打电话。plot*()
,fill()
并且bgcolor()
不允许拨打电话。
库函数总是返回限定为“简单”或“系列”的结果。您不能在需要“const”或“输入”限定值的地方使用它们,就像一些内置函数的情况一样。例如,库函数不能用于计算plot()show_last
调用中参数
的参数
,因为它需要“输入 int”值。
合格类型控制
根据函数内部每个参数的使用方式,自动检测调用库函数时提供的参数的限定类型。如果参数可以用作“系列”,则将其限定为系列。如果不能,则尝试使用“简单”类型限定符。这解释了为什么此代码:
export myEma(int x) =>
ta.ema(close, x)
使用 调用时将起作用myCustomLibrary.myEma(20)
,即使
ta.ema()的
length
参数需要“简单 int”参数。当 Pine Script™ 编译器检测到“系列”长度不能与
ta.ema()一起使用时,它会尝试“简单”限定符,在这种情况下是允许的。
虽然库函数不能返回“const”或“input”值,但它们可以编写为产生“简单”结果。这使得它们在比返回“series”结果的函数更多的上下文中有用,因为一些内置函数不允许“series”参数。例如,
request.security()
要求其参数为“简单字符串” symbol
。如果我们编写一个库函数以以下方式组装参数symbol
,则该函数的结果将不起作用,因为它属于“series string”限定类型:
export makeTickerid(string prefix, string ticker) =>
prefix + ":" + ticker
但是,通过将参数限定符限制为“简单”,我们可以强制函数产生“简单”结果。我们可以通过在参数类型前加上 simple 关键字来实现这一点:
export makeTickerid(simple string prefix, simple string ticker) =>
prefix + ":" + ticker
请注意,为了使函数返回“简单”值,在其计算中不能使用任何“系列”值;否则结果将是“系列”值。
也可以使用 series 关键字作为库函数参数类型的前缀。但是,由于参数默认被限定为“series”,因此使用 series 修饰符是多余的。
用户定义类型和对象
库可以导出用户定义类型 (UDT),并且库函数可以返回这些类型的对象。
要导出 UDT,请在其定义前加上 export 关键字,类似于导出函数:
//@version=5
library("Point")
export type point
int x
float y
bool isHi
bool wasBreached = false
导入该库并创建其UDT对象的脚本
point
看起来有点像这样:
//@version=5
indicator("")
import userName/Point/1 as pt
newPoint = pt.point.new()
注意:
- 该代码无法编译,因为没有发布“Point”库,并且脚本不显示任何内容。
userName
需要替换为库发布者的 TradingView 用户名。- 我们使用内置
new()
方法从 UDT 创建一个对象point
。 point
我们在对库的UDT的引用前面加上在importpt
语句 中定义的别名 ,就像我们使用导入库中的函数时一样。
如果任何导出的函数或方法接受或返回 该类型的对象,或者另一个导出的UDT的字段 接受该类型的实例,则库必须导出 UDT 。
当库仅在内部使用
UDT时
,它不需要导出类型。以下库point
在内部使用该类型,但它仅导出函数drawPivots()
,该函数没有该point
类型的参数或返回point
对象:
//@version=5
library("PivotLabels", true)
// We use this `point` UDT in the library, but it does NOT require exporting because
// 1. The exported function's parameters do not use the UDT.
// 2. The exported function does not return a UDT result.
type point
int x
float y
bool isHi
bool wasBreached = false
fillPivotsArray(qtyLabels, leftLegs, rightLegs) =>
// Create an array of the specified qty of pivots to maintain.
var pivotsArray = array.new<point>(math.max(qtyLabels, 0))
// Detect pivots.
float pivotHi = ta.pivothigh(leftLegs, rightLegs)
float pivotLo = ta.pivotlow(leftLegs, rightLegs)
// Create a new `point` object when a pivot is found.
point foundPoint = switch
pivotHi => point.new(time[rightLegs], pivotHi, true)
pivotLo => point.new(time[rightLegs], pivotLo, false)
=> na
// Add new pivot info to the array and remove the oldest pivot.
if not na(foundPoint)
array.push(pivotsArray, foundPoint)
array.shift(pivotsArray)
array<point> result = pivotsArray
detectBreaches(pivotsArray) =>
// Detect breaches.
for [i, eachPoint] in pivotsArray
if not na(eachPoint)
if not eachPoint.wasBreached
bool hiWasBreached = eachPoint.isHi and high[1] <= eachPoint.y and high > eachPoint.y
bool loWasBreached = not eachPoint.isHi and low[1] >= eachPoint.y and low < eachPoint.y
if hiWasBreached or loWasBreached
// This pivot was breached; change its `wasBreached` field.
point p = array.get(pivotsArray, i)
p.wasBreached := true
array.set(pivotsArray, i, p)
drawLabels(pivotsArray) =>
for eachPoint in pivotsArray
if not na(eachPoint)
label.new(
eachPoint.x,
eachPoint.y,
str.tostring(eachPoint.y, format.mintick),
xloc.bar_time,
color = eachPoint.wasBreached ? color.gray : eachPoint.isHi ? color.teal : color.red,
style = eachPoint.isHi ? label.style_label_down: label.style_label_up,
textcolor = eachPoint.wasBreached ? color.silver : color.white)
// @function Displays a label for each of the last `qtyLabels` pivots.
// Colors high pivots in green, low pivots in red, and breached pivots in gray.
// @param qtyLabels (simple int) Quantity of last labels to display.
// @param leftLegs (simple int) Left pivot legs.
// @param rightLegs (simple int) Right pivot legs.
// @returns Nothing.
export drawPivots(int qtyLabels, int leftLegs, int rightLegs) =>
// Gather pivots as they occur.
pointsArray = fillPivotsArray(qtyLabels, leftLegs, rightLegs)
// Mark breached pivots.
detectBreaches(pointsArray)
// Draw labels once.
if barstate.islastconfirmedhistory
drawLabels(pointsArray)
// Example use of the function.
drawPivots(20, 10, 5)
如果 TradingView 用户发布了上述库,则可以这样使用:
//@version=5
indicator("")
import TradingView/PivotLabels/1 as dpl
dpl.drawPivots(20, 10, 10)
枚举类型
库还可以导出 枚举类型,允许其他脚本导入预定义的命名值集,以帮助控制变量、条件表达式和 集合接受的值。
例如,此库导出一个State
枚举,其中三个字段代表不同的信号状态:long
、short
和neutral
。这些字段表示枚举类型的变量、表达式或集合
可以采用的可能值:
//@version=5
library("Signal")
//@enum An enumeration of named signal states.
//@field long Represents a "Long" signal.
//@field short Represents a "Short" signal.
//@field neutral Represents a "Neutral" signal.
export enum State
long = "Long"
short = "Short"
neutral = "Neutral"
导入此库的脚本可以在其逻辑中使用枚举的成员(值)
State
作为命名状态。这里,我们展示了一个简单的假设脚本,该脚本导入用户发布的“Signal”库
userName
并使用Signal.State
枚举将三个可能值之一分配给mySignal
变量:
//@version=5
indicator("")
import userName/Signal/1 as Signal
// Calculate the median and quarter range values.
float medianValue = ta.median(close, 100)
float rangeValue = ta.range(close, 100) * 0.25
// Calculate upper and lower channel values.
float upper = medianValue + rangeValue
float lower = medianValue - rangeValue
//@variable Returns `Signal.State.long`, `Signal.State.short`, or `Signal.State.neutral` based on the price action.
Signal.State mySignal = switch
close > upper => Signal.State.long
close < lower => Signal.State.short
=> Signal.State.neutral
plot(close, color = mySignal == Signal.State.long ? color.green : mySignal == Signal.State.short ? color.red : na)
与导出UDT类似,当库的导出函数或方法接受或返回枚举的成员时,或者当导出的UDT的字段 接受该枚举类型 的值 时,库必须导出该枚举 。
发布库
在您或其他 Pine Script™ 程序员可以重复使用任何库之前,必须先发布它。如果您想与所有 TradingViewers 分享您的库,请公开发布它。要私下使用它,请使用私人出版物。与指标或策略一样,发布库时的活动图表将同时出现在其小部件(表示 TradingView 脚本流中的库的小占位符)和脚本页面(用户单击小部件时看到的页面)中。
私有库可以在公共的受保护或仅限邀请的脚本中使用。
将示例库添加到图表并设置一个干净的图表以我们想要的方式显示库图后,我们使用 Pine 编辑器的“发布脚本”按钮。出现“发布库”窗口:
注意:
- 我们保留库的标题(library()
title
声明语句中的参数 用作默认值)。虽然您可以更改出版物的标题,但最好保留其默认值,因为该参数用于在 import 语句中引用导入的库。当您的出版物标题与库的实际名称匹配时,它会让库用户的工作更轻松。title
- 默认描述是根据 我们在库中使用的编译器注释构建的。我们将不加修饰地发布该库。
- 我们选择公开发布我们的库,以便所有 TradingViewers 都可以看到它。
- 我们无法选择除“开放”之外的可见性类型,因为库始终是开源的。
- 库的类别列表与指标和策略的类别列表不同。我们选择了“统计和指标”类别。
- 我们添加了一些自定义标签:“历史”、“最高”和“最低”。
公共库的目标用户是其他 Pine 程序员;您对库功能的解释和记录得越好,其他人使用它们的机会就越大。在出版物代码中提供示例来演示如何使用库功能也会有所帮助。
家庭规则
在我们的脚本发布内部规则中, Pine 库被视为“公共领域”代码,这意味着如果您在开源脚本中调用其函数或重用其代码,则无需获得其作者的许可。但是,如果您打算在受保护的公共出版物或仅限邀请的出版物中重用 Pine Script™ 库函数中的代码,则需要获得其作者的明确许可才能以该形式重用。
无论是使用库函数还是重用其代码,您都必须在出版物描述中注明作者。在开源评论中注明作者也是一种很好的形式。
使用库
使用来自另一个脚本的库(可以是指标、策略或另一个库)是通过 import 语句完成的:
在哪里:
- <username>/<libraryName>/<libraryVersion> 路径将唯一标识该库。
- 必须明确指定 <libraryVersion>。为了确保使用库的脚本的可靠性,无法自动使用库的最新版本。每次库的作者发布库更新时,库的版本号都会增加。如果您打算使用库的最新版本,则需要在 导入 语句中更新 <libraryVersion> 值。
- 该
as <alias>
部分是可选的。使用时,它定义将引用库函数的命名空间。例如,如果您使用别名导入库allTime
(如下例所示),您将以 引用该库的函数allTime.<function_mame>()
。当未定义别名时,库的名称将成为其命名空间。
要使用我们在上一节中发布的库,我们的下一个脚本将需要一个 import 语句:
import PineCoders/AllTimeHighLow/1 as allTime
当您输入库作者的用户名时,您可以使用编辑器的ctrl
+
space
/ cmd
“自动完成”命令显示一个弹出窗口,提供与可用库匹配的选择:
这是一个重用我们库的指标:
//@version=5
indicator("Using AllTimeHighLow library", "", true)
import PineCoders/AllTimeHighLow/1 as allTime
plot(allTime.hi())
plot(allTime.lo())
plot(allTime.hi(close))
注意: