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

Pine Script(106):获取品种点(pip)大小,制作基于pip的输入选项

#Pine Script入门教学

获取品种的点 (pip) 大小

在外汇交易中,点 (pip) 是衡量货币对价格变化的标准单位。外汇交易的盈亏,通常首先以“点”来表示,然后再换算成美元(或其他货币)。

一个“点”的大小,源于历史上货币对最小的可能价格变动单位。对于那些最初以4位小数报价的货币对(例如 EUR/USD 和 GBP/USD),一个点代表 0.0001 的价格变化。而对于那些使用2位小数的货币对(例如 EUR/JPY),一个点则代表 0.01

然而,从那以后,货币对的报价增加了一位小数。例如,EUR/USD 现在最小的价格变动单位是 0.00001,而 EUR/JPY 则以 0.001 为单位进行交易。

这些更精细的报价并没有改变“点”的传统含义。相反,这些更小的价格变动单位被称为小数点的点 (fractional pips) 或“步”,它们是常规点的十分之一。


获取交易品种的“点”大小

在 Pine Script 中,有两种方式可以获取一个交易品种的“点”大小:

  1. 检索当前图表交易品种的“点”大小,这是我们在大多数情况下所需要的。
  2. 获取任意 TradingView 交易品种(即图表当前品种之外的其他品种)的“点”大小。

让我们先来深入了解第一种方法。


自定义函数

通过下面的自定义函数,我们可以获取当前图表交易品种的“点”大小:

// GetPipSize() 函数返回交易品种的“点”大小。
// 对于非外汇品种,它返回其 tick 大小;
// 对于外汇货币对,它返回其完整的“点”大小。
GetPipSize() =>
    syminfo.mintick * (syminfo.type == "forex" ? 10 : 1)

这个 GetPipSize() 函数通过两部分代码来计算“点”的大小。

第一部分是 syminfo.mintick 变量。它返回的是该品种的最小可能价格变动。对于货币对,这个值其实是小数点的“点”(即“步”)的大小。因为我们感兴趣的是完整的“点”,所以我们需要对这个值进行修正。

为了修正它,我们进行一次乘法运算。当该品种的资产类别 (syminfo.type) 等于 (==) "forex"(外汇)时,条件运算符 (?:) 会返回 10 作为乘数;否则,我们乘以 1

对于外汇货币对,这能将一个小数点的“点”(例如 0.00001)转换成一个完整的“点”(0.0001)。而对于其他非外汇品种,它会保持其原有的 tick 大小不变。

每当我们需要以“点”为单位进行计算时,都可以使用 GetPipSize() 函数。例如:

// 以“点”为单位计算ATR
atrPips = ta.atr(14) / GetPipSize()

// 计算30个“点”以外的价格目标
priceTarget = close + (30 * GetPipSize())

// 也可以:将品种的“点”大小储存在变量中
// (以备后续使用)
pipSize = GetPipSize()

完整示例脚本

下面我们来看一下如何在一个完整的 TradingView 脚本中应用 GetPipSize() 函数:

//@version=5
indicator(title="Display instrument pip size", overlay=true)

// GetPipSize() 函数返回交易品种的“点”大小。
// 对于非外汇品种,它返回其 tick 大小;
// 对于外汇货币对,它返回其完整的“点”大小。
GetPipSize() =>
    syminfo.mintick * (syminfo.type == "forex" ? 10 : 1)

// 在最后一根已确认的历史K线上,显示该品种的“点”大小
if barstate.islastconfirmedhistory
    label.new(x=bar_index + 2, y=close, style=label.style_label_left,
         color=color.navy, textcolor=color.white, size=size.large, 
         text=syminfo.ticker + "'s pip size is:\n" + 
             str.tostring(GetPipSize()))

代码解析

这个指标首先使用 indicator() 函数来定义其设置。这行代码为脚本命名,并将其叠加显示在主图上。

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

接下来,一个 if 语句检查 barstate.islastconfirmedhistory 变量。该变量只在图表的最后一根已确认的历史K线上才为 true。当脚本运行到该K线时,label.new() 函数会创建一个新的文本标签。

这个标签被显示在收盘价 (close) 处,并向右移动2根K线 (bar_index + 2) 的位置。它的箭头指向左边 (label.style_label_left),并拥有一个海军蓝 (color.navy) 的背景和白色 (color.white) 的文字。

标签的文本内容包含几个部分。首先,我们使用 syminfo.ticker 变量来包含品种的交易代码。然后是一个描述性的文本,最后是该品种的“点”大小,我们通过调用 GetPipSize() 函数来获取这个值。

因为 GetPipSize() 函数返回的是一个数字,而这里我们需要拼接文本,所以我们使用 str.tostring() 函数将“点”的大小转换为字符串。

当这个指标在一个 EURUSD 图表上运行时,标签会显示其“点”的大小为 0.0001

如果我们切换到一个不同的交易品种,标签也会随之改变。对于 USDJPY,它报告的“点”大小是 0.01(而该品种实际的最小变动单位是 0.001):


获取任意品种的“点”大小

第二种方法是获取任意 TradingView 交易品种的“点”大小。这给予了我们极大的灵活性,我们的代码可以独立于当前图表的品种,来使用任何外汇品种的“点”大小进行计算。

要实现这一点,我们需要使用 Pine Script 的后台数据加载功能。接下来我们看看如何操作。


自定义函数

下面的这个自定义函数,可以获取任意 TradingView 交易品种的“点”大小:

// GetPipSizeSymbol() 函数以非重绘的方式,返回通过'security'函数
// 加载的、指定品种的“点”大小。
GetPipSizeSymbol(symbol) =>
    pipSizeCalc = syminfo.mintick * (syminfo.type == "forex" ? 10 : 1)
    request.security(symbol, "D", pipSizeCalc[1], 
         lookahead=barmerge.lookahead_on)

这个 GetPipSizeSymbol() 函数有一个参数:symbol。它用于指定我们想要获取其“点”大小的那个品种的交易代码。

在函数内部,我们首先使用 syminfo.minticksyminfo.type 变量来计算“点”的大小。这采用了与上文讨论的相同的方法。我们将计算结果储存在 pipSizeCalc 变量中。

之所以要先创建一个变量,是因为当我们加载背景数据时,我们可以将一个包含了所需计算逻辑的变量传递过去。这能简化代码,Pine Script 会在另一个品种的数据环境中,执行这个变量的计算。

这个背景数据加载,正是我们接下来通过 request.security() 函数所做的事情。我们向该函数传递了四个参数:

  • 第一个 symbol,是 GetPipSizeSymbol() 函数自身的参数。
  • 通过 "D" 字符串参数,我们指定加载日线数据。
  • pipSizeCalc 变量则指定了在那个日线时间周期上需要执行何种计算。

为了防止所谓的“脚本重绘”问题,我们在请求时启用了 barmerge.lookahead_on,将另一个品种的数据系列与当前图表的K线开盘时间进行同步。由于“点”的大小是品种的固定属性,每根K线上都相同,这里不会引入未来数据。

我们可以这样来使用这个自定义的 GetPipSizeSymbol() 函数:

// 从OANDA获取GBP/USD的“点”大小
gbpUsdPips = GetPipSizeSymbol("OANDA:GBPUSD")

// 从默认交易所获取EUR/USD的“点”大小
eurUsdPips = GetPipSizeSymbol("EURUSD")

// 获取特斯拉的“点”大小(这将返回其默认的tick大小)
tslaPips = GetPipSizeSymbol("TSLA")

完整示例脚本

下面我们来看一下如何在一个完整的 TradingView 指标中应用这个自定义函数:

//@version=5
indicator(title="Get pip size of any instrument", overlay=true)

// 创建一个输入框,用以选择我们想获取其“点”大小的品种
symbol = input.symbol("FX:EURUSD", title="Symbol")

// GetPipSizeSymbol() 函数以非重绘的方式,返回通过'security'函数
// 加载的、指定品种的“点”大小。
GetPipSizeSymbol(symbol) =>
    pipSizeCalc = syminfo.mintick * (syminfo.type == "forex" ? 10 : 1)
    request.security(symbol, "D", pipSizeCalc[1], 
         lookahead=barmerge.lookahead_on)

// 在每根K线上获取另一个品种的“点”大小
// (这能为Pine Script提供所需的计算一致性)
pipSizeSymbol = GetPipSizeSymbol(symbol)

// 在最后一根已确认的历史K线上,创建一个标签来显示
// 指定品种的“点”大小
if barstate.islastconfirmedhistory
    label.new(x=bar_index + 1, y=hl2, style=label.style_label_left,
         color=color.new(color.maroon, 70), size=size.large, 
         text=symbol + " has\na pip size of:\n" + 
             str.tostring(pipSizeSymbol))

代码解析

这个指标的代码以 indicator() 函数开始,为脚本命名并将其叠加显示在主图的交易品种上。

然后,我们使用 input.symbol() 函数创建了一个品种搜索输入框。这个标题为‘Symbol’的设置,让我们能方便地选择想要查询其“点”大小的品种,它默认是来自FXCM的EUR/USD货币对。我们用 symbol 变量来跟踪这个输入的值。

之后,我们包含了前面讨论过的 GetPipSizeSymbol() 自定义函数。

然后我们使用这个函数来获取一个品种的“点”大小。我们调用 GetPipSizeSymbol() 并传入 symbol 输入变量,然后将返回的“点”大小存入 pipSizeSymbol 变量中。(因为 request.security() 引用了前一根K线的数据,所以我们需要在每一根K线上都执行 GetPipSizeSymbol(),以避免 Pine Script 错过任何计算。)

接下来,一个 if 语句检查 barstate.islastconfirmedhistory。该变量只在图表的最后一根已确认的历史K线上才为 true。在这根K线上,我们使用 label.new() 函数来创建一个新的文本标签。

这个标签被显示在K线的中点 (hl2) 处,并向右偏移一根K线 (bar_index + 1) 的位置。它的箭头指向左边 (label.style_label_left),并显示为褐红色 (color.maroon),通过 color.new() 函数设置了70%的透明度。文本使用了大号 (size.large) 字体。

标签的文本由几个部分拼接而成。首先是 symbol 变量,它持有我们从输入框中选择的品种。然后是一些描述性文字。最后我们通过 pipSizeSymbol 变量来包含该品种的“点”大小。由于该变量返回的是一个数字,我们需要使用 str.tostring() 函数将其转换为文本。

当我们将这个脚本添加到图表时,它显示 EURUSD 的“点”大小为 0.0001

如果我们更改输入框中的品种,代码会在后台获取一个不同的品种数据,并且标签内容也会随之改变。假设我们从脚本设置中选择了 EUR/JPY 货币对,这会使标签显示其“点”大小为 0.01

如果我们使用输入框选择一个非外汇货币对的品种,标签则会简单地显示该品种的 tick 大小。例如:


内容总结

  • 点 (pip) 是外汇货币对价格变化的标准单位。
  • 大多数货币对,例如EUR/USD和GBP/USD,其“点”的大小为 0.0001。也有一些货币对,如EUR/JPY,使用 0.01 作为其“点”的大小。
  • Pine Script 的 syminfo.mintick 变量返回的是小数点的“点”(即“步”)的大小。要将其转换成一个完整的“点”,我们需要将其乘以 10

如何制作基于点 (pip) 的输入选项

我们知道,一个交易品种的tick大小代表了其价格的最小变动单位。一个处理“点”(pip) 的脚本可以直接在代码中定义这个数量。

然而,通过一个输入项来配置“点”的数量,会是更方便的做法,它省去了反复编辑代码的麻烦。这样的输入项可以帮助我们实现很多功能,例如基于特定点数设置止损或止盈订单,或者作为价格和突破的过滤器。

要创建一个基于“点”的输入项,我们通常执行以下两个步骤:

  1. 创建输入项
    • 使用 input.int() 函数创建一个整数输入框,用于定义“点”的数量。
    • 将这个输入值与我们自定义的 GetPipSize() 函数相乘。这能将抽象的“点数”转换为该品种在价格坐标上的具体数值。(例如,对于EUR/USD,10个点会变成 0.0010;对于USD/JPY,则会变成 0.10。)
  2. 在代码中使用:在脚本中需要处理“点”数量的地方,使用上一步计算出的结果。

接下来,让我们看看每一步的具体代码实现。


第一步:创建Pip输入项

首先,我们创建一个用于设置“点”数量的输入框。然后,我们将它的值转换成对应的价格变化量。

这一步的代码如下:

// 步骤 1. 创建一个指定点数(pips)的输入项。
// 然后将其值与 GetPipSize() 相乘,从而将点数转换为
// 该品种的价格标度值。
pipOffsetInput = input.int(2, title="Pips Offset", minval=0) * GetPipSize()

代码解析

这段代码使用 input.int() 函数创建了一个整数类型的输入选项。它的默认值为 2title 参数将该输入命名为 ‘Pips Offset’ (点数偏移量)。minval 参数则确保了输入的值总是大于或等于零。

虽然这个输入框设定了“点”的数量,但我们还不知道这个数量具体对应多少价格变化。为此,我们将这个输入值与我们自定义的 GetPipSize() 函数相乘。该函数返回的是该品种一个标准“点”的大小。

举个例子 :以 EUR/USD 为例,它的一个标准点是 0.0001。当我们将输入框的值设为 5 时,将 5 个点与 GetPipSize() 的返回值相乘,就会得到 EUR/USD 价格坐标上等效的数值,即 0.0005

我们将这个计算出的、代表了指定点数的价格值,储存在 pipOffsetInput 变量中,以备后用。

我们在这一步中创建的输入框,在设置面板中看起来是这样的:


第二步:在代码中使用输入值

现在,我们在脚本中应用这个基于“点”的输入项。具体用在何处,取决于哪部分代码需要用到这个“点”数。

假设我们想围绕一条指数移动平均线 (EMA) 创建一个价格通道(或称价格带)。我们希望通过输入项中的“点”数,来设定通道上下轨的距离。

在这种情况下,我们可以这样来使用这个输入值:

// 步骤 2. 在代码中使用由“点”衍生的价格值。
// 这里我们基于EMA,以一个指定的点数为距离,来设置上轨和下轨。
emaValue  = ta.ema(close, 40)
upperBand = emaValue + pipOffsetInput
lowerBand = emaValue - pipOffsetInput

代码解析

这里,ta.ema() 函数首先计算出EMA。该函数在收盘价 (close) 上运行,周期长度为 40。我们将其返回值存入 emaValue 变量。

为了计算上轨,我们将EMA的值加上我们基于“点”计算出的价格偏移量 (pipOffsetInput)。对于下轨,我们则从移动平均线的值中减去这个偏移量。

通过在这里使用输入变量,代码就能动态地使用用户在设置中输入的当前值。如果我们手动更改输入框的值,这里的计算结果也会随之更新。

完整示例脚本

让我们通过一个完整的脚本来看看如何应用基于“点”的输入。下方的指标会创建我们之前提到的40周期指数移动平均线价格通道。其中,“点”输入项用于定义上下通道轨距离移动平均线的距离。

当价格摆脱震荡区间并突破该通道时,我们会为图表背景上色。我们将用绿色代表买入信号,红色代表卖出信号。

该指标的完整代码如下:

//@version=5
indicator(title="Pip-based input example", overlay=true)

// GetPipSize() 函数返回交易品种的“点”大小。
// 对于非外汇品种,它返回其 tick 大小;
// 对于外汇货币对,它返回其完整的“点”大小。
GetPipSize() =>
    syminfo.mintick * (syminfo.type == "forex" ? 10 : 1)

// 步骤 1. 创建一个指定点数(pips)的输入项。
// 然后将其值与 GetPipSize() 相乘,从而将点数转换为
// 该品种的价格标度值。
pipOffsetInput = input.int(2, title="Pips Offset", minval=0) * GetPipSize()

// 计算40周期的指数移动平均线及其通道轨
emaValue  = ta.ema(close, 40)

// 步骤 2. 在代码中使用由“点”衍生的价格值。
// 这里我们基于EMA,以一个指定的点数为距离,来设置上轨和下轨。
upperBand = emaValue + pipOffsetInput
lowerBand = emaValue - pipOffsetInput

// 绘制平均线及其通道轨
plot(upperBand, color=color.orange, title="Upper Band")
plot(emaValue, color=color.aqua, title="Average")
plot(lowerBand, color=color.orange, title="Lower Band")

// 使用背景色高亮突破信号
bgcolor(close > upperBand ? color.new(color.green, 85) :
     close < lowerBand ? color.new(color.red, 85) : 
         na)

代码解析

我们首先使用 indicator() 函数来配置指标,这行代码为脚本命名,并将其放置在主图的交易品种之上。

然后,我们包含了 GetPipSize() 这个自定义函数。

接下来,我们创建了上文讨论过的基于“点”的输入项。

之后,ta.ema() 函数计算出收盘价 (close) 的40周期指数移动平均线。为了得到上轨,我们将这条移动平均线的值加上“点”输入项所代表的价格偏移量。对于下轨,我们则减去这个偏移量。

plot() 函数将这三个值(上轨、均线、下轨)都绘制在图表上。上下轨以橘色 (color.orange) 显示,EMA均线则为水蓝色 (color.aqua)。由于我们没有设置绘图类型,Pine Script 默认会创建常规的线图。

为了在图表上高亮显示信号,我们使用了 bgcolor() 函数。其中的条件运算符 (?:) 决定了具体使用哪种颜色。

  • 首先,运算符判断收盘价是否高于上轨。如果是,我们就使用通过 color.new() 函数设置了85%透明度的绿色 (color.green)。
  • 否则,第二个条件运算符会检查收盘价是否低于下轨。在这种情况下,我们使用一个透明的红色 (color.red)。
  • 如果这两个条件都不满足,我们就用 na 来关闭背景色。

在图表上,该指标初始时会创建一个距离移动平均线上下各2个“点”的价格通道,效果如下:

如果我们把‘Pips Offset’输入选项的值增加到 8,价格通道会变宽,从而过滤掉图表上的很多噪音。幸运的是,图中的 GBP/USD 突破信号依然被捕捉到了:


内容总结

要创建一个基于“点”的输入项,我们通常遵循以下步骤:

  1. 创建整数输入:首先,使用 input.int() 函数创建一个整数类型的输入选项,让用户可以设定“点”的数量。
  2. 转换为价格值:接着,我们将这个输入值与自定义的 GetPipSize() 函数的返回值相乘,从而将抽象的“点数”转换成一个具体的价格变化值。
  3. 在代码中使用:最后,在脚本中需要用到这个价格偏移量的地方,使用上一步计算出的结果。
赞(0)
未经允许不得转载:图道交易 » Pine Script(106):获取品种点(pip)大小,制作基于pip的输入选项
分享到

评论 抢沙发

登录

找回密码

注册