保持敬畏之心
交易是一场持久战

Pine Script(110):判断连续期货与永续加密货币期货

#Pine Script入门教学

判断品种是否为连续期货

期货是带有杠杆并在指定日期到期的衍生品。为了绘制它们的长期价格走势,TradingView 允许我们使用所谓的连续期货图表。这些合成的交易代码,将多个不同到期月份的合约连接在了一起。

TradingView 平台提供两种类型的、在交易所交易的连续期货:

  • 1! 后缀:以当前合约月份在前的连续期货。
  • 2! 后缀:以下一个合约月份在前的连续期货。

这些连续期货的共同点在于,它们的交易代码 (ticker) 都是以一个感叹号 (!) 结尾的。接下来,就让我们看看如何利用这个特性,让 Pine Script 来识别连续期货。


自定义函数

下面的这个自定义 Pine Script 函数,可以识别当前图表的品种是否为连续期货:

// IsContinuousFuture() 函数用于判断当前品种是否为一个
// 在交易所交易的连续期货。如果是,则返回'true',否则返回'false'。
IsContinuousFuture() =>
    str.endswith(syminfo.ticker, "!") and syminfo.type == "futures"

这个 IsContinuousFuture() 函数不接受任何参数,我们只需直接调用它即可。当品种是连续期货时,该函数返回 true,否则返回 false

为了得到这个布尔值,函数内部的代码进行了两次比较。首先,它判断该品种的交易代码 (ticker) 是否以 ! 结尾。为了实现这个判断,str.endswith() 函数会评估 syminfo.ticker 变量是否以 “!” 字符结尾。如果是,该函数返回 true,否则返回 false

第二个判断,是看该品种的资产类别是否为期货。当 syminfo.type 变量等于 (==) 字符串 "futures" 时,这个条件就成立了。目前看来,TradingView 似乎没有以 ! 结尾的非期货品种,那为什么还要多加这个判断呢?

这是因为,检查 syminfo.type 几乎不消耗任何计算性能,但它却能在未来为我们带来巨大的好处。因为,如果多年以后 TradingView 添加了以 ! 结尾的非期货品种,我们的代码得益于这个判断,依然能够正确运行。

该函数使用 and 运算符来组合这两个判断。这意味着,必须两者都为 true,它们的组合结果才会是 true。只要其中一个或两个判断为 false,函数的最终结果就是 false


函数特性

  • 该函数在每一根K线上都返回相同的信息。为了避免 Pine Script 进行不必要的重复计算,我们可以将其返回值储存在一个 var 变量中。
  • 该函数无法识别加密货币期货。那些永续期货没有到期日,TradingView 将它们归类为‘crypto’(加密货币),而不是‘futures’(期货)。

快速上手示例

让我们看看如何在实践中应用这个自定义函数。

场景一:判断品种是连续期货

要判断当前图表的品种是否为连续期货,我们可以这样做:

// 判断当前图表品种是否为连续期货。
// 如果是,则用一个标签来显示这个信息。
if IsContinuousFuture()
    label.new(bar_index, high, "This is a continuous future!")

这个 if 语句调用了 IsContinuousFuture() 函数。当图表品种是连续期货时,该函数返回 trueif 语句内的代码便会执行。

这段代码使用 label.new() 函数创建了一个标签,它会显示在K线的最高价处 (bar_index, high),并告诉我们这个品种是一个连续期货。

场景二:判断品种不是连续期货

要测试一个品种不是连续期货,我们可以在函数前加上 not 运算符:

// 验证当前图表的品种不是一个连续期货合约。
if not IsContinuousFuture()
    label.new(bar_index, high, "This ain't a continuous future.")

这个 if 语句同样调用了 IsContinuousFuture() 函数。通常情况下,当品种是连续期货时,函数返回 true,不是时返回 false。但我们在前面加上了 not 运算符,这会得到相反的结果:当品种是连续期货时,表达式为 false;不是时,则为 true

因此,如果品种确实不是连续期货,label.new() 函数就会创建一个文本标签来说明这一点。

场景三:设置变量值

另一个应用场景是,根据品种是否为连续期货,来设定一个变量的值。我们可以通过条件运算符 (?:)、switch 语句或 if/else 语句来实现。

下面是一个使用 if/else 语句的例子:

// 根据图表品种的类型来设定绘图颜色
plotColour = if IsContinuousFuture()
    color.orange
else
    color.teal

// 计算并绘制20周期的EMA,其颜色取决于
// 该品种是否为连续期货。
plot(ta.ema(close, 20), color=plotColour)

这段代码会根据当前品种是否为连续期货,来为 plotColour 变量赋予橘色 (color.orange) 或青色 (color.teal)。

接下来,plot() 函数会使用这个 plotColour 变量的颜色,来显示20周期的指数移动平均线 (EMA)。该均线通过 ta.ema() 函数计算得出。


判断其他品种是否为连续期货

默认情况下,IsContinuousFuture() 自定义函数返回的是针对当前图表品种的判断结果。

但这个函数也可以处理从后台加载的其他品种的数据,从而判断另一个品种是否为连续期货。

在 Pine Script 代码中,我们可以这样实现:

// 将IsContinuousFuture()函数传递给 request.security(),
// 来判断背景数据加载的品种是否为连续期货。
dailyOilFuture = request.security("CL1!", "1D", IsContinuousFuture())
dailyOilSpot   = request.security("USOIL", "1D", IsContinuousFuture())

// 在最后一根K线上,格式化一个字符串并创建一个标签来显示结果。
if barstate.islast
    labelText = str.format("Is CL1! a continuous future? {0}\n" + 
         "Is USOIL a continuous future? {1}", dailyOilFuture, 
         dailyOilSpot)

    label.new(bar_index, high, labelText, textcolor=color.white)

这里的 request.security() 函数发出了两个背景数据请求。第一个请求的是CME的原油连续期货 ("CL1!"),另一个请求的则是追踪相同油价的CFD ("USOIL")。我们将 IsContinuousFuture() 函数作为参数,传递给了这两个数据请求。

这使得 IsContinuousFuture() 函数能够基于 request.security() 所获取的交易代码,返回 truefalse,而不是针对当前图表的品种进行判断。

因此,当 label.new() 函数在图表的最后一根K线上 (barstate.islast) 创建一个标签时,这个标签会告诉我们 CL1! 是一个连续期货,而 USOIL 不是。

通过这种方式,IsContinuousFuture() 自定义函数就可以获取那些甚至没有显示在我们当前图表上的品种的信息。


完整示例脚本

让我们在一个完整的脚本中使用 IsContinuousFuture() 函数。下方的指标会测试当前图表的品种是否为连续期货。

我们将这个判断结果转换成一个条件性的文本,然后将它与品种的交易代码和数据源等信息一起,组合成一个更大的字符串。最后,我们在一个标签中显示这个文本,从而在图表上表明该品种是否为连续期货。

该指标的完整代码如下:

//@version=5
indicator(title="Continuous future example script", overlay=true)

// IsContinuousFuture() 函数用于判断当前品种是否为一个
// 在交易所交易的连续期货。如果是,则返回'true',否则返回'false'。
IsContinuousFuture() =>
    str.endswith(syminfo.ticker, "!") and syminfo.type == "futures"

// 在图表的最后一根K线上,生成文本来显示该品种
// 是或不是连续期货,并在一个文本标签中显示出来。
if barstate.islast
    continuousText = IsContinuousFuture() ? "is" : "is NO"

    labelText = str.format("{0} trading at {1}\n{2} a continuous future.", 
         syminfo.ticker, syminfo.prefix, continuousText)

    label.new(bar_index, high, labelText,
         color=color.teal, textcolor=color.white, size=size.large)

代码解析

首先,我们调用 indicator() 函数。我们通过 title 参数为脚本命名,并通过 overlay 参数使脚本叠加显示在主图的交易品种上。

然后,我们将上文讨论过的 IsContinuousFuture() 自定义函数复制粘贴到脚本中。

接下来,一个 if 语句会判断脚本当前是否正在图表的最后一根价格K线上进行计算。当条件成立时,barstate.islast 变量为 true,Pine Script 随之执行 if 语句内的代码。

这段代码首先会判断当前品种是否为连续期货:

continuousText = IsContinuousFuture() ? "is" : "is NO"

这里的 continuousText 变量,其值来源于 IsContinuousFuture() 函数。当该函数返回 true 时,条件运算符 (?:) 会返回字符串 "is" (是);否则,当函数返回 false 时,运算符则返回 "is NO" (不是)。这个结果随后被赋给该变量。

然后,我们使用 str.format() 函数来构建一个更长的、格式化的字符串。我们为该函数提供了一个带有三个占位符的文本模板。Pine Script 会用相应的变量值来替换每一个占位符:

  • {0} 会被替换为来自 syminfo.ticker 变量的品种交易代码。
  • {1} 会被替换为来自 syminfo.prefix 变量的品种数据源。
  • {2} 则会被替换为我们刚才创建的 continuousText 变量的值。

str.format() 将模板转换成格式化字符串后,我们就得到了一个能说明当前图表品种是否为连续期货的完整文本。我们将这个文本储存在 labelText 变量中。

最后,label.new() 函数创建了实际的文本标签。我们将这个标签放置在K线的最高价处 (bar_index, high)。其文本内容正是我们刚刚创建的 labelText 变量。标签的颜色为青色 (color.teal),文字为白色 (color.white),并且尺寸比常规要大 (size.large)。

在图表上,该指标的标签会告诉我们当前图表的品种是否为连续期货,同时也会显示其交易代码和数据源。对于下图,我们可以看到 FESX1! 是一个连续期货。如果我们切换图表,标签内容也会随之更新。


内容总结

TradingView 的连续期货品种,其交易代码 (symbol) 以一个感叹号 (!) 结尾。

要判断一个品种是否为连续期货,我们进行两项测试:

  1. 首先,我们使用 str.endswith() 函数,判断其交易代码(通过 syminfo.ticker 变量获取)是否以 “!” 结尾。
  2. 为了进一步确认,我们再判断该品种的资产类别(通过 syminfo.type 变量获取)是否为 "futures"

当这两个条件都满足时,该品种就是一个连续期货;否则,它就是其他类型的品种。

我们自定义的 IsContinuousFuture() 函数,使得在我们的 Pine Script 代码中可以轻松地应用上述步骤。

判断品种是否为永续加密货币期货

交易加密货币有多种方式,其中一个选项就是永续合约 (perpetual futures)。这些带杠杆的衍生品,与常规期货相比,没有到期日,这正是它们被称为“永续”的原因。

TradingView 平台对永续合约主要采用两种命名约定:

  • 交易代码 (ticker) 以 PERP 结尾的永续合约。
    • 例如币安 (Binance) 交易所的 BTCPERPETHUSDTPERP
  • 交易代码以 .P 结尾的永续合约。
    • 例如 ByBit 的 BTCUSD.P、OKX 的 LTCUSDT.P 以及 MEXC 的 ETHUSDT.P

要判断一个交易品种是否为永续合约,我们可以检查其交易代码。当品种的交易代码以 PERP.P 结尾时,它很可能就是一个永续合约。接下来,让我们看看如何让 Pine Script 来做出这个判断。


自定义函数

下面的这个自定义 Pine Script 函数,可以判断当前品种是否为加密货币永续合约:

// IsPerpetualFuture() 函数用于判断当前品种是否为
// 加密货币永续合约。如果是,则返回'true',否则返回'false'。
IsPerpetualFuture() =>
    syminfo.type == "crypto" and
         (str.endswith(syminfo.ticker, "PERP") or 
         str.endswith(syminfo.ticker, ".P"))

这个 IsPerpetualFuture() 函数没有任何参数,我们只需直接调用它即可。当品种是永续合约时,该函数返回 true,否则返回 false

函数逻辑解析

为了得到这个布尔值,函数内部的代码进行了三次评估。

  1. 首先,它判断该品种是否为加密货币。当 syminfo.type 变量等于 (==) "crypto" 时,这个条件成立。因为其他 TradingView 品种的交易代码也可能以 PERP 结尾(例如 EUREX 的 PERP 期货),所以这个检查能确保我们只针对加密货币进行判断。
  2. 接下来,我们判断该品种的交易代码是否以 PERP.P 结尾。我们通过 str.endswith() 函数来实现这个判断。这个字符串函数用于检查一个文本是否以另一个指定的文本结尾。这里,它会测试 syminfo.ticker 变量(即品种的交易代码)是否以 "PERP"".P" 结尾。
  3. or 运算符将两个 str.endswith() 的函数调用组合起来,这意味着只要两个字符串测试中有一个为 true,其组合结果就是 true。然后,and 运算符再将这个结果与资产类别的检查结果相结合。只有当“资产类别为加密货币”并且“交易代码以指定后缀结尾”这两个条件都为 true 时,整个函数才会返回 true。如果其中一个或两个条件为 false,那么函数的最终结果就是 false

函数特性

  • 该函数在每一根K线上都返回相同的结果。为了提高效率,我们可以将其返回值储存在一个 var 变量中,这能让 Pine Script 只在第一根K线上执行一次该函数(而不是在每根K线上都重复计算)。
  • 该函数无法识别常规的期货合约。TradingView 将那些有到期日的衍生品归类为‘futures’(期货),而不是‘crypto’(加密货币)。

快速上手示例

让我们看看这个自定义函数的实际应用。

场景一:判断品种是永续合约

要判断当前图表的品种是否为永续合约,我们可以这样编码:

// 判断当前图表品种是否为永续合约
if IsPerpetualFuture()
    label.new(bar_index, high, "This is a perpetual future!")

这个 if 语句调用了 IsPerpetualFuture() 函数。如果图表品种是永续合约,该函数返回 trueif 语句内的代码便会执行。

这段代码使用 label.new() 函数创建了一个标签,它会显示在K线的最高价处,并告诉我们这个品种是一个永续合约。

场景二:判断品种不是永续合约

要判断一个品种不是永续合约,我们可以在函数前加上 not 逻辑运算符:

// 验证该品种不是一个永续合约
if not IsPerpetualFuture()
    label.new(bar_index, high, "This is NO perpetual future")

这个 if 语句同样调用了 IsPerpetualFuture()。当品种是永续合约时,函数返回 true,不是时返回 false。但我们在前面加上了 not 运算符,这会得到逻辑上的相反结果:当品种是永续合约时,表达式为 false;不是时,则为 true

因此,如果品种确实不是永续合约,label.new() 函数就会创建一个文本标签来说明这一点。

场景三:根据是否为永续合约来设置变量

另一个应用场景是,根据品种是否为永续合约,来设定一个变量的值。我们可以通过条件运算符 (?:)、switch 语句或 if/else 语句来实现。

下面是一个使用 if/else 语句的例子:

// 根据图表品种的类型来决定背景颜色
backColour = if IsPerpetualFuture()
    color.new(color.blue, 90)
else
    color.new(color.orange, 80)

// 将背景颜色更改为该变量的值
bgcolor(backColour)

这段代码会根据当前品种是否为永续合约,来为 backColour 变量赋予一个带有透明度的蓝色 (color.blue) 或橘色 (color.orange)。

然后 bgcolor() 函数会使用这个颜色,从上到下地渲染图表的背景。


判断其他品种是否为永续合约

IsPerpetualFuture() 返回的值,默认是基于当前图表的品种。

但这个函数也可以处理从后台加载的其他品种的数据,从而判断另一个品种是否为永续合约。

下面的 Pine Script 示例演示了这一点:

// 使用 IsPerpetualFuture() 函数与 request.security() 结合,
// 来判断背景数据加载的品种是否为永续合约
dailyBtcSpot = request.security("COINBASE:BTCUSD", "D", IsPerpetualFuture())
dailyBtcFut  = request.security("BYBIT:BTCUSD.P", "D", IsPerpetualFuture())

// 在最后一根K线上,创建一个字符串并在标签中显示结果
if barstate.islast
    labelText = str.format("Is BTCUSD a perpetual future? {0}\n" + 
         "Is BTCUSD.P a perpetual future? {1}", dailyBtcSpot, dailyBtcFut)

    label.new(bar_index, high, labelText, textcolor=color.white)

这里的 request.security() 函数请求了两个品种的背景数据。第一个加载的是 Coinbase 的 BTCUSD 现货,另一个则获取 ByBit 的 BTCUSD 永续合约。我们将 IsPerpetualFuture() 函数作为参数,传递给了这两个背景数据请求。

这使得 IsPerpetualFuture() 函数能够基于 request.security() 所获取的交易代码,返回 truefalse,而不是针对当前图表的品种进行判断。

因此,当代码的 label.new() 函数在图表的最后一根K线上 (barstate.islast) 创建一个标签时,这个标签会显示 BTCUSD 不是一个永续合约,而 BTCUSD.P 是。

这正是 IsPerpetualFuture() 自定义函数如何获取那些甚至没有显示在我们当前图表上的品种的信息。

完整示例脚本

让我们在一个完整的脚本中应用 IsPerpetualFuture() 函数。下方的指标会测试当前图表的品种是否为永续合约。

我们将这个判断结果转换成一个条件性的文本,然后将它与品种的交易代码和数据源等信息一起,组合成一个更完整的字符串。最后,我们在一个标签中显示这个文本,从而在图表上表明该品种是否为永续合约。

该指标的完整代码如下:

//@version=5
indicator(title="Perpetual future example script", overlay=true)

// IsPerpetualFuture() 函数用于判断当前品种是否为
// 加密货币永续合约。如果是,则返回'true',否则返回'false'。
IsPerpetualFuture() =>
    syminfo.type == "crypto" and
         (str.endswith(syminfo.ticker, "PERP") or 
         str.endswith(syminfo.ticker, ".P"))

// 在图表的任一最后一根K线上,生成一段文本来说明该品种是否为
// 永续合约,并在一个文本标签中显示结果。
if barstate.islast
    perpFutureText = IsPerpetualFuture() ? "is" : "is NOT"

    labelText = str.format("{0} at {1}\n{2} a perpetual future.",
         syminfo.ticker, syminfo.prefix, perpFutureText)

    label.new(bar_index, high, labelText, color=color.orange,
         textcolor=color.white, size=size.large)

代码解析

我们首先调用 indicator() 函数,这会为脚本命名并将其叠加在主图上。

然后,我们包含了上文讨论过的 IsPerpetualFuture() 自定义函数。

之后,一个 if 语句会判断脚本当前是否正在图表的最后一根K线上进行计算,这是通过 barstate.islast 变量来实现的。当该变量为 true 时,Pine Script 便会执行 if 语句内的代码。

这段代码首先会评估当前品种是否为永续合约:

perpFutureText = IsPerpetualFuture() ? "is" : "is NOT"

这里的 perpFutureText 变量,其值来源于条件运算符 (?:)。该运算符会评估 IsPerpetualFuture() 函数的返回值。

  • 当该函数返回 true 时,条件运算符会返回字符串 "is" (是)。
  • 如果函数返回 false,运算符则返回 "is NOT" (不是)。 这个结果随后被赋给 perpFutureText 变量。

接下来,str.format() 函数会构建一个更长的字符串。它使用一个带有三个占位符 ({0}, {1}, {2}) 的文本模板,Pine Script 会用相应的变量值来替换每一个占位符:

  • {0} 被替换为来自 syminfo.ticker 变量的品种交易代码。
  • {1} 被替换为来自 syminfo.prefix 变量的品种数据源。
  • {2} 则被替换为我们刚才创建的 perpFutureText 变量的字符串值。

str.format() 从这个模板生成字符串后,我们就得到了一个能说明当前图表品种是否为永续合约的完整文本,并将其储存在 labelText 变量中。

最后,label.new() 函数在图表上显示这个文本。它在K线的最高价处 (bar_index, high) 绘制一个标签,其文本内容就是 labelText 变量。标签的颜色为橘色 (color.orange),文字为白色 (color.white),并且尺寸比常规要大 (size.large)。

在图表上,这个标签会告诉我们当前品种是否为永续合约,同时也会显示其交易代码和数据源。对于下图,我们可以看到 ByBit 的 ETHUSD.P 被正确地识别为了永续合约。如果我们切换图表,标签内容也会随之更新。


内容总结

  • 在 TradingView 上,加密货币永续合约的交易代码 (ticker) 以 PERP.P 结尾。
  • str.endswith() 函数可以用来测试品种的交易代码 (syminfo.ticker) 是否以 "PERP"".P" 结尾。
  • 为了进行确认,我们再通过 syminfo.type 变量来检查该品种是否为加密货币。
  • 当交易代码和资产类别都符合条件时,该品种就是一个永续合约;否则,它就是其他类型的品种。
  • 我们自定义的 IsPerpetualFuture() 函数,使得在我们的 Pine Script 代码中可以轻松地使用和重用上述步骤。
赞(0)
未经允许不得转载:图道交易 » Pine Script(110):判断连续期货与永续加密货币期货
分享到

评论 抢沙发

登录

找回密码

注册