将数值取整到品种的最小变动价位(tick size)
Tick size(最小变动价位)指的是一个交易品种可能发生的最小价格变动。当一个交易品种的价格波动时,其变动量至少是一个 tick size(而不可能小于这个值)。
E-mini S&P 500 future (迷你标普500指数期货) 的 tick size 是 0.25。大多数股票的最小价格变动是 0.01。而一些外汇货币对则以 0.00001 为单位进行增减。
当我们将数值取整到交易品种的 tick size 时,我们实际上是让这个数值采用与图表品种相同的价格增量。这样做有几个好处:它在图表上看起来更美观;我们可以用有效价格提交订单(而不是介于两个 tick 之间的无效价格);它可以将止损位取整到实际的市场价格(从而精确计算风险);并且它能将指标值绘制在交易品种实际可以触及的价格水平上。
在 Pine Script 中,有三种方式可以实现向交易品种的 tick size 取整:
- 四舍五入到最接近的 tick。
- 始终向上取整到下一个 tick。
- 或始终向下取整到最接近的 tick。
下面我们来逐一探讨。
四舍五入到最接近的 Tick
Pine Script 的 math.round_to_mintick() 函数可以将一个数值向上或向下取整到最接近的 tick 。
该函数的默认语法格式如下 :
math.round_to_mintick(number)
number 指的是我们希望取整到最接近 tick 的数值。
math.round_to_mintick() 会返回一个浮点值,该值被取整到交易品种的最小可能价格变动单位,其中平局情况向上取整 。
要使用该函数,我们只需用一个字面数值、变量或函数来调用它即可。例如:
// 将数值取整到 E-mini S&P 500 期货的最小变动单位 0.25
math.round_to_mintick(2.69) // 2.75
math.round_to_mintick(132.923) // 133.00
math.round_to_mintick(-38.32) // -38.25
// 将K线的中点价 ([high - low] / 2) 取整到 tick
math.round_to_mintick(hl2)
// 将简单移动平均线取整到 tick size
math.round_to_mintick(ta.sma(close, 12))
取整范例
让我们更仔细地看看 math.round_to_mintick() 的返回值。下表将一些数值取整到 E-mini S&P 500 期货的最小 tick size,即 0.25:
| 原始值 | 四舍五入到最近的 tick |
|---|---|
| 5.92991 | 6.00 |
| 3.72 | 3.75 |
| 1.23 | 1.25 |
| 0.00002 | 0.00 |
| 0.000 | 0.00 |
| -0.00009 | 0.00 |
| -1.12 | -1.00 |
| -4.75 | -4.75 |
| -9.8953 | -10.00 |
| na | 0 |
| “1.83” | 错误;不能对字符串值调用函数(需要浮点值)。 |
如上所示,math.round_to_mintick() 会选择一个最接近该交易品种可能值范围的数值。有时它会向上取整(例如 1.23 变为 1.25);有时则会向下取整(例如 -9.8953 变为 -10.00)。
脚本范例
让我们看看如何在完整的 TradingView 脚本中使用 math.round_to_mintick()。下方的指标会将一个20周期的简单移动平均线(SMA)取整到当前图表品种的 tick size。其完整代码如下:
//@version=5
indicator(title="Round to tick example", overlay=true)
// 计算并绘制 20-bar SMA
smaValue = ta.sma(close, 20)
plot(smaValue, color=color.orange, linewidth=2, title="SMA")
// 在最后一根历史K线上,用一个文本标签显示原始SMA值
// 和取整到 tick 后的版本
if barstate.islastconfirmedhistory
smaRounded = math.round_to_mintick(smaValue)
label.new(x=bar_index + 1, y=close, style=label.style_label_left,
color=color.teal, textcolor=color.white, size=size.large,
text=syminfo.ticker + "'s SMA: " + str.tostring(smaValue, "0.0000") +
"\nSMA rounded to tick: " + str.tostring(smaRounded, "0.0000"))
该指标首先通过 indicator() 函数来指定其设置,用于命名脚本并将其叠加显示在主图的交易品种上。
接着,ta.sma() 函数计算简单移动平均线。我们将这个20周期的平均值存储在 smaValue 变量中。然后 plot() 函数将该变量以橙色(color.orange)的常规线图形式绘制出来。
之后,一个 if 语句检查 barstate.islastconfirmedhistory 变量。该变量仅在图表的最后一根历史K线上为 true。由于这根K线在每个图表上只出现一次,这为我们提供了一个只创建一次标签(而不是重复创建)的便捷方法。
在 if 语句内部,math.round_to_mintick() 函数将 SMA 的值(smaValue)取整到最接近的 tick。我们将这个取整后的值存入 smaRounded 变量。
然后,label.new() 函数创建一个新的文本标签。这个标签显示在收盘价(close)的位置,并向右平移一根K线(bar_index + 1)。它指向左侧(label.style_label_left),背景为青色(color.teal),文字为白色(color.white)且字号较大(size.large)。
标签的文本内容由几个字符串片段拼接而成。我们使用 syminfo.ticker 变量来包含交易品种的名称。然后添加原始的 SMA 值,通过 str.tostring() 函数将其从数值转换为文本。最后,我们再添加取整后的 SMA 值(smaRounded),同样用 str.tostring() 格式化为文本。
该指标在一个 Micro E-mini S&P 500 期货图表上的效果如下:
这里的 SMA 值为 4,471.175。math.round_to_mintick() 函数将该值向上取整到了下一个 tick,即 4,471.25。
math.round_to_mintick() 的特性
在 Pine Script 版本4及更早的版本中,math.round_to_mintick() 的名称是 round_to_mintick() 。除了名称不同外,其函数的行为(和结果)并未改变。
始终向上取整到下一个 Tick
第二种方法是始终将数值向上取整到下一个 tick。这会使得一个数值保持不变或变得更高,并与图表交易品种的值范围保持一致。
自定义函数
Pine Script 没有内置函数来实现这种取整。但我们可以自己创建一个:
// RoundToTickUp() 函数将给定的值向上取整到下一个 tick,
// 使用图表交易品种的 tick size。
RoundToTickUp(value) =>
math.ceil(value / syminfo.mintick) * syminfo.mintick
这个 RoundToTickUp() 函数有一个参数:value,它指明我们希望取整的数值。
在函数内部,我们首先将 value 除以 syminfo.mintick 变量。该变量返回图表交易品种的 tick size。对于 E-mini S&P 500 期货,该值为 0.25。这个除法运算告诉我们 value 值中包含了多少个 tick。
比方说,要取整的数是 11.82,tick size 是 0.25。这意味着这个数等同于 47.28 个 tick。
接下来,我们用 Pine Script 的 math.ceil() 函数将这个 tick 数量向上取整为整数。对于 47.28 的例子,它会返回 48 个 tick。然后我们需要将这些 tick 转回为价格值。所以我们将其乘以 syminfo.mintick。这将 48 个 tick 变为了 12.00 这个价格。
要使用该函数,我们只需用一个字面数值、变量或函数来调用它即可。例如:
// E-mini S&P 500 期货的 tick size 为 0.25 的示例值:
RoundToTickUp(10.345) // 10.50
RoundToTickUp(-6.219) // -6.00
// 将K线的中点价 ([high - low] / 2) 向上取整到 tick
RoundToTickUp(hl2)
// 将简单移动平均线向上取整到 tick size
RoundToTickUp(ta.sma(close, 12))
取整范例
让我们看看自定义的 RoundToTickUp() 函数会生成什么样的值。下表将一些数值向上取整到 E-mini S&P 500 期货的 0.25 tick size:
| 原始值 | 向上取整到最近的 tick |
|---|---|
| 5.92991 | 6.00 |
| 3.72 | 3.75 |
| 1.23 | 1.25 |
| 0.00002 | 0.25 |
| 0.00 | 0.00 |
| -0.00009 | 0.00 |
| -1.12 | -1.00 |
| -4.75 | -4.75 |
| -9.8953 | -9.75 |
| na | 错误;不能对 na 参数调用用户定义的函数。 |
| “1.83” | 错误;不能对字符串参数调用此函数。 |
如上所示,当我们向上取整到最接近的 tick 时,负数值会变得更接近0。而正数值也会变得更大。
脚本范例
下面的指标展示了我们如何在完整的脚本中使用 RoundToTickUp() 函数。该指标会将一个30周期的加权移动平均线 (WMA) 向上取整到当前图表品种的 tick size。其代码如下:
//@version=5
indicator(title="Round to tick up example", overlay=true)
// RoundTickUp() 函数将给定的值向上取整到下一个 tick,
// 使用图表交易品种的 tick size。
RoundTickUp(value) =>
math.ceil(value / syminfo.mintick) * syminfo.mintick
// 计算并绘制 WMA
wmaValue = ta.wma(close, 30)
plot(wmaValue, color=color.fuchsia, linewidth=2, title="WMA")
// 在最后一根历史K线上,用一个文本标签显示原始WMA值
// 和向上取整后的版本
if barstate.islastconfirmedhistory
wmaRounded = RoundTickUp(wmaValue)
label.new(x=bar_index + 1, y=close, style=label.style_label_left,
color=color.new(color.blue, 85), textcolor=color.black,
size=size.large, text=syminfo.ticker + "'s WMA: " +
str.tostring(wmaValue, "0.0000") +
"\n\nWMA rounded up to nearest tick:\n" +
str.tostring(wmaRounded, "0.0000"))
代码首先通过 indicator() 函数来设置指标的选项,用于命名脚本并将其叠加在图表上。
然后我们引入了上面讨论过的自定义 RoundToTickUp() 函数。
接着,ta.wma() 函数计算30周期的加权移动平均线。计算结果存储在 wmaValue 变量中。然后 plot() 函数将该变量绘制在图表上,这条常规线图以紫红色 (color.fuchsia) 显示。
下一步,一个 if 语句检查 barstate.islastconfirmedhistory 变量。该变量仅在图表的最后一根历史K线上为 true。在这根K线上,我们首先将 WMA 向上取整到最接近的 tick,即对 wmaValue 变量调用 RoundToTickUp() 函数。我们将结果存储在 wmaRounded 变量中。
然后 label.new() 函数创建一个新的文本标签。这个标签出现在收盘价 (close) 的位置,并向未来偏移一根K线 (bar_index + 1)。它指向左侧 (label.style_label_left),并有一个透明的蓝色背景。文字以黑色、大号字体 (size.large) 显示。
标签的文本内容是几个字符串的组合。我们使用 syminfo.ticker 变量来包含交易品种的符号。第一个 str.tostring() 函数调用包含了转换成文本的 WMA 值。另一个 str.tostring() 调用则包含了取整后的 WMA 值。
在一个 Micro E-mini S&P 500 期货图表上,该指标的效果如下:
这里的 RoundToTickUp() 函数将 4,472.0591 的WMA值向上取整到了下一个 tick,即 4,472.25。
始终向下取整到最接近的 Tick
第三种也是最后一种方法是,始终将数值向下取整到下一个 tick。其结果是一个保持不变或变得更低的数值,并与图表交易品种的值范围保持一致。
自定义函数
Pine Script 没有内置函数来实现这种取整。但没关系,我们可以自己创建一个:
// RoundToTickDown() 函数将给定的值向下取整到最近的 tick,
// 通过使用图表交易品种的 tick size。
RoundToTickDown(value) =>
math.floor(value / syminfo.mintick) * syminfo.mintick
这个 RoundToTickDown() 函数接受一个参数:value。这个参数是我们希望取整的数值。
在函数内部,我们首先将 value 除以图表交易品种的 tick size。我们通过 Pine Script 的 syminfo.mintick 变量来获取后者。这个除法运算告诉我们 value 值中包含了多少个 tick。
比方说,要取整的数是 28.425,而交易品种的 tick size 是 0.25。在这种情况下,这个数等同于 113.7 个 tick。
接下来,我们用 Pine Script 的 math.floor() 函数将这个 tick 数量向下取整为整数。对于 113.7 的例子,它会返回 113 个 tick。然后我们需要将这个 tick 数量转回为价格值。所以我们将其乘以 syminfo.mintick 变量。这将 113 转为了 28.25 这个价格值。
要使用该函数,只需用一个字面数值、变量或函数来调用它即可。例如:
// E-mini S&P 500 期货 (tick size: 0.25) 的示例值
RoundToTickDown(10.345) // 10.25
RoundToTickDown(-6.219) // -6.25
// 将K线的中点价 ([high - low] / 2) 向下取整到 tick
RoundToTickDown(hl2)
// 将简单移动平均线向下取整到 tick size
RoundToTickDown(ta.sma(close, 12))
取整范例
让我们更仔细地看看 RoundToTickDown() 函数的返回值。下表将一些数值向下取整到 E-mini S&P 500 期货的 0.25 tick size:
| 原始值 | 向下取整到 tick |
|---|---|
| 5.92991 | 5.75 |
| 3.72 | 3.50 |
| 1.23 | 1.00 |
| 0.00002 | 0.00 |
| 0.00 | 0.00 |
| -0.00009 | -0.25 |
| -1.12 | -1.25 |
| -4.75 | -4.75 |
| -9.8953 | -10.00 |
| na | 错误;不能对 na 参数调用用户定义的函数。 |
| “1.83” | 错误;不能对字符串参数调用此函数。 |
从表中我们可以看出,当我们向下取整到最接近的 tick 时,负数值会变得更小(离0更远)。同样地,正数值也会变得更小。
脚本范例
下面的指标展示了我们如何在完整的脚本中使用 RoundToTickDown() 函数。这段代码会将一个20周期的指数移动平均线 (EMA) 向下取整到当前图表品种的下一个 tick:
//@version=5
indicator(title="Round to tick down example", overlay=true)
// RoundToTickDown() 函数将给定的值向下取整到最近的 tick,
// 通过使用图表交易品种的 tick size。
RoundToTickDown(value) =>
math.floor(value / syminfo.mintick) * syminfo.mintick
// 计算并绘制 20-bar EMA
emaValue = ta.ema(close, 20)
plot(emaValue, color=color.teal, linewidth=2, title="EMA")
// 在最后一根历史K线上,用一个文本标签显示原始EMA值
// 和向下取整到 tick 的版本
if barstate.islastconfirmedhistory
emaRounded = RoundToTickDown(emaValue)
label.new(x=bar_index + 1, y=close, style=label.style_label_left,
color=color.new(color.orange, 70), textcolor=color.black,
size=size.large, text=syminfo.ticker + "'s EMA: " +
str.tostring(emaValue, "0.0000") +
"\n\nEMA rounded to nearest tick down:\n" +
str.tostring(emaRounded, "0.0000"))
该指标首先使用 indicator() 函数来定义两个设置:它的名称 (title) 和叠加 (overlay)。
然后我们引入了上面看过的自定义 RoundToTickDown() 函数。
下一步,ta.ema() 函数计算指数移动平均线。我们将这个20周期的平均值存储在 emaValue 变量中。然后 plot() 函数将该变量以青色 (color.teal) 的常规线图形式绘制在图表上。
在那之后,一个 if 语句检查 barstate.islastconfirmedhistory。该变量在最后一根历史K线上为 true,这是一个只执行一次代码的便利方法。在这根K线上,我们首先将 EMA 向下取整到最接近的 tick,即对 emaValue 变量调用 RoundToTickDown() 函数。我们将结果存储在 emaRounded 变量中。
然后,label.new() 函数创建一个新的文本标签。这个标签出现在收盘价 (close) 的位置,并向右平移一根K线 (bar_index + 1)。它的样式指向左侧 (label.style_label_left),并有一个橙色 (color.orange) 的背景,通过 color.new() 函数使其变得有些透明。标签的文字以黑色 (color.black)、大号字体 (size.large) 显示。
标签的文本内容通过加法操作符 (+) 拼接了几个字符串。首先我们用 syminfo.ticker 变量来包含交易品种的符号。然后是字面字符串,后面跟着两个 str.tostring() 函数调用。第一个将数值形式的 EMA 值转换为文本,另一个则对取整后的平均值做同样的操作。
当我们在一个 Micro E-mini S&P 500 期货图表上运行这个指标时,它看起来是这样的:
这里的移动平均线值 4,475.4808 被 RoundToTickDown() 向下取整到最接近的 tick,得到了 4,475.25 这个值。
总结
- Pine Script 的
math.round_to_mintick()函数将给定的值向上或向下取整到最接近的 tick size。 - Tick size 是一个交易品种可能发生的最小价格变动。
- 要实现始终向上或始终向下取整到下一个 tick,我们首先将数值除以 tick size,然后用
math.ceil()(向上)或math.floor()(向下)取整,最后再乘以 tick size。





