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

Pine Script(121):取整到整十整百整千位,以及截断小数

#Pine Script入门教学

取整到整十位

Pine Script 有几个函数可以对数值进行取整。这些函数利用数值的小数部分将其取整为整数。例如,将 42.80 变为 43。

但如果我们想将数值取整到整十位呢?这将使得 42.80 变为 40,87.1 变为 90。通过这种方式,我们可以将计算出的仓位大小取整到最接近的整十股,或者以整十为单位输出数值,以方便阅读。

有三种方法可以实现取整到十位。让我们来逐一了解。

四舍五入到整十位

第一种方法是进行四舍五入。当个位数字为5或更高时,我们向上取整;否则向下取整。这样,128.9 会变为 130,而 203 则会被取整为 200。

下面的这个小函数可以将数值四舍五入到最接近的整10位:

// RoundToTens() 函数将指定的值四舍五入到
// 最近的整十位。
RoundToTens(value) =>
    math.round(value / 10.0) * 10

这个 RoundToTens() 函数有一个参数 value。在函数内部,我们首先将该参数除以 10.0。(如果我们用整数10相除,Pine Script 会舍弃小数部分,因此我们使用 10.0。)这样做会将小数点(.)向左移动一位。例如,56 会变为 5.6。

然后,我们使用 Pine Script 的 math.round() 函数将该数字取整为整数,这会使 5.6 变为 6。之后,我们再乘以10,将小数点向右移回一位。最终的结果是一个与原始参数数量级相同的值。

要使用该函数,我们只需用一个数值作为其参数来调用它即可。例如:

RoundToTens(2532)    // 2530
RoundToTens(-9.75)   //  -10

取整范例

以下是更多的示例数字以及 RoundToTens() 返回的取整结果:

原始值 四舍五入到十位
3 0
21 20
49 50
101 100
2532 2530
0.01 0
-0.01 0
-3.6 0
-9.75 -10
-28 -30
-456 -460
na 错误;不能对 na 参数调用用户定义的函数。
“1.83” 错误;不能对字符串值调用此函数。

当我们取整到十位时,取整后的值可能变大(例如 49 变为 50),也可能变小(例如 -456 变为 -460)。

向上取整到整十位

第二种方法是始终向上取整到整十位。这会使得 42 和 48 都变为 50。

下面的自定义 Pine Script 函数演示了如何实现这一点:

// RoundToTensUp() 函数将指定的值向上取整到下一个
// 整数十 (10s) 值。
RoundToTensUp(value) =>
    math.ceil(value / 10.0) * 10

这个 RoundToTensUp() 函数同样只有一个数值参数(value)。在函数内部,我们首先除以 10.0 来移动小数点,然后使用 Pine Script 的 math.ceil() 函数向上取整为整数,最后再乘以10,以恢复到与函数参数相同的数量级。

要使用这个函数,我们用一个数值调用它,像这样:

RoundToTensUp(2532)    // 2540
RoundToTensUp(-9.75)   //    0

取整范例

以下是 RoundToTensUp() 函数对其他一些示例值的返回结果:

原始值 向上取整到十位
3 10
21 30
49 50
101 110
2532 2540
0.01 10
-0.01 0
-3.6 0
-9.75 0
-28 -20
-456 -450
na 错误;不能对 na 参数调用用户定义的函数。
“1.83” 错误;不能对字符串值调用此函数。

当我们向上取整到十位时,取整后的值总是会变大。也就是说,正数变得更大(例如101变为110),负数则更接近0(例如-28变为-20)。

向下取整到整十位

第三种也是最后一种方法是,始终向下取整到最接近的整十位。这会使得 22 和 28 都变为 20。

当我们在计算仓位大小时,这种方法能确保我们的风险不会超过设定的最大风险水平。

下面的这个小型 Pine Script 函数可以将数值向下取整到整十位:

// RoundToTensDown() 函数将指定的值向下取整到下一个
// 整数十 (10s) 值。
RoundToTensDown(value) =>
    math.floor(value / 10.0) * 10

RoundToTensDown() 函数内部,我们首先将 value 参数除以 10.0,这一步会移动小数点一个位置。然后,我们使用 Pine Script 的 math.floor() 函数向下取整。最后,我们将该结果乘以10,以便将小数点移回其原始位置。

以下是如何使用该函数:

RoundToTensDown(2532)    // 2530
RoundToTensDown(-9.75)   //  -10

取整范例

以下是 RoundToTensDown() 函数对其他各种值的返回结果:

原始值 向下取整到十位
3 0
21 20
49 40
101 100
2532 2530
0.01 0
-0.01 -10
-3.6 -10
-9.75 -10
-28 -30
-456 -460
na 错误;不能对 na 参数调用用户定义的函数。
“1.83” 错误;不能对字符串值调用此函数。

当我们向下取整到十位时,取整后的值总是会变小。对于正数,其值会变小(例如49变为40)。对于负数,其值也会变小、离0更远(例如-3.6变为-10)。

脚本范例

现在,让我们看看这些自定义的取整函数在 TradingView 脚本中是如何运作的。下面的指标会绘制一个指数移动平均线(EMA),然后我们使用 RoundToTens() 函数将该平均值四舍五入到最接近的整十位。

该脚本的完整代码如下:

//@version=5
indicator(title="Round to tens example", overlay=true)

// RoundToTens() 函数将指定的值四舍五入到
// 最近的整十位。
RoundToTens(value) =>
    math.round(value / 10.0) * 10

// 计算并绘制一个指数移动平均线
emaValue = ta.ema(close, 20)
plot(emaValue, color=color.orange, linewidth=2, title="EMA")

// 显示四舍五入到十位的EMA
plot(RoundToTens(emaValue), color=color.teal, linewidth=3,
     title="EMA Rounded to Tens")

这个指标首先通过 indicator() 函数定义其脚本设置,用于命名该脚本并将其叠加显示在主图的交易品种上。

然后,我们把 RoundToTens() 函数加入脚本。(我们当然也可以在这里使用 RoundToTensDown()RoundToTensUp() 函数。)

接下来,我们使用 Pine Script 的 ta.ema() 函数计算 EMA。我们将这个20周期的平均值存储在 emaValue 变量中。

然后我们用 plot() 函数绘制这个变量。由于没有设置绘图类型,Pine Script 会默认创建一个标准的常规线图。这条线以橙色(color.orange)显示,并且比正常更粗(linewidth=2)。

之后,我们创建另一个绘图。这个绘图显示的是取整到整十位的平均值。因此,我们调用 RoundToTens() 函数并传入 emaValue 变量。这条线以青色(color.teal)显示。

该指标在图表上看起来是这样的:

从图中我们可以看到,当布伦特原油 CFD (Brent Oil CFD) 的移动平均线越过55时,取整到十位的值从50跳升到60。当平均线突破65时,也发生了类似的情况。

总结

  • 要实现取整到整十位,我们首先将待取整的数值除以10.0,然后对结果进行取整,最后再乘以10。
  • 我们所使用的取整函数,决定了最终是进行四舍五入(math.round() 函数的功能)、始终向上取整(math.ceil() 函数的功能),还是始终向下取整(math.floor() 函数的功能)。

取整到整百位

Pine Script 提供了几种对数值进行取整的方法。标准的取整函数会处理数值的小数部分,将其变为整数。例如,将 842.90 变为 843,将 372.25 变为 372。

但如果我们想将数值取整到整百位呢?这将使得 842 变为 800,372 转换为 400。通过这种方式,我们可以将计算出的仓位大小向下取整到最接近的整百股,或者以整百为单位显示成交量,以方便阅读。

有三种不同的方法可以实现取整到百位。让我们来逐一探讨:

四舍五入到整百位

第一种选择是进行四舍五入。当小数点(.)前的最后两位数字为50或更高时,我们向上取整;否则向下取整。这将使得 363 变为 400,348.7 变为 300。

下面的这个自定义函数可以将数值四舍五入到最接近的整100位:

// RoundToHundreds() 函数将指定的值四舍五入到
// 最近的整百位。
RoundToHundreds(value) =>
    math.round(value / 100.0) * 100

这个 RoundToHundreds() 函数有一个参数 value。在函数内部,我们首先将该参数除以 100.0。(如果我们用整数100相除,Pine Script 会舍弃小数部分,因此我们使用 100.0。)这样做会将小数点(.)向左移动两位。例如,520 会变为 5.20。

然后,我们使用 Pine Script 的 math.round() 函数将该数字取整为整数,这会使 5.20 变为 5。之后,我们再乘以100,将小数点向右移回两位。最终的结果是一个与原始参数数量级相同的值。

要使用该函数,我们只需用一个数值或变量来调用它即可。例如:

RoundToHundreds(102)     //  100
RoundToHundreds(190.95)  //  200
RoundToHundreds(983)     // 1000

取整范例

以下是 RoundToHundreds() 函数对其他一些值的返回结果:

原始值 四舍五入到百位
3 0
75 100
102 100
190.95 200
983 1000
4312 4300
0.01 0
-0.01 0
-4.2 0
-8.75 0
-329 -300
-992 -1000
na 错误;不能对 na 参数调用用户定义的函数。
“1.83” 错误;不能对字符串值调用此函数。

从表中我们可以看出,当我们取整到百位时,取整后的值可能变大(例如 983 变为 1000),也可能变小(例如 102 变为 100)。

向上取整到最接近的整百位

另一种方法是始终向上取整到下一个整百位。这样,620 和 673 都会变为 700。

下面的自定义函数实现了所需的代码:

// RoundToHundredsUp() 函数将指定的值向上取整到下一个
// 整数百 (100s) 值。
RoundToHundredsUp(value) =>
    math.ceil(value / 100.0) * 100

这个 RoundToHundredsUp() 函数同样只有一个参数(value)。在函数内部,我们首先除以 100.0 来移动小数点,接着使用 Pine Script 的 math.ceil() 函数向上取整为整数,然后我们再乘以100,以恢复到与函数参数相同的数量级。

要使用这个函数,我们用一个数调用它,像这样:

RoundToHundredsUp(102)      //  200
RoundToHundredsUp(190.95)   //  200
RoundToHundredsUp(983)      // 1000

取整范例

以下是 RoundToHundredsUp() 函数对其他值的返回结果:

原始值 向上取整到百位
3 100
75 100
102 200
190.95 200
983 1000
4312 4400
0.01 100
-0.01 0
-4.2 0
-8.75 0
-329 -300
-992 -900
na 错误;不能对 na 参数调用用户定义的函数。
“1.83” 错误;不能对字符串值调用此函数。

如上所示,取整后的值总是会变大。也就是说,一个像 102 这样的正数会被取整为 200。而像 -329 这样的负数则会更接近0(变为-300)。

向下取整到最接近的整百位

第三种也是最后一种方法是,始终向下取整到最接近的整百位。这会使得 119 和 189 都变为 100。

当我们在计算仓位大小时,这种方法能确保我们最终不会买入过多的股票。

下面的这个自定义函数可以将数值向下取整到下一个整百位:

// RoundToHundredsDown() 函数将指定的值向下取整到下一个
// 整百位。
RoundToHundredsDown(value) =>
    math.floor(value / 100.0) * 100

在这个 RoundToHundredsDown() 函数内部,我们首先将 value 参数除以 100.0,这一步会移动小数点两个位置。然后,我们使用 Pine Script 的 math.floor() 函数向下取整。最后,我们将该结果乘以100,以便将小数点(.)移回其原始位置。

要使用该函数,只需用一个数值或变量来调用它即可。例如:

RoundToHundredsDown(102)     // 100
RoundToHundredsDown(190.95)  // 100
RoundToHundredsDown(983)     // 900

取整范例

以下是 RoundToHundredsDown() 函数对其他各种值的返回结果:

原始值 向下取整到百位
3 0
75 0
102 100
190.95 100
983 900
4312 4300
0.01 0
-0.01 -100
-4.2 -100
-8.75 -100
-329 -400
-992 -1000
na 错误;不能对 na 参数调用用户定义的函数。
“1.83” 错误;不能对字符串值调用此函数。

当我们向下取整到百位时,取整后的值总是更小或保持不变。对于正数,其值会变小(例如983变为900)。对于负数,其值也会变小、离0更远(例如-4.2取整为-100)。

脚本范例

现在,让我们在实践中使用这些自定义的取整函数。下面的指标会绘制一个简单移动平均线(SMA),然后 RoundToHundreds() 函数将该平均值四舍五入到最接近的整百位。

该脚本的完整代码如下:

//@version=5
indicator(title="Round to hundreds example", overlay=true)

// RoundToHundreds() 函数将指定的值四舍五入到
// 最近的整百位。
RoundToHundreds(value) =>
    math.round(value / 100.0) * 100

// 计算并绘制一个简单移动平均线
smaValue = ta.sma(close, 20)
plot(smaValue, color=color.silver, linewidth=2, title="SMA")

// 显示四舍五入到百位的平均值
plot(RoundToHundreds(smaValue), color=color.navy, 
     linewidth=3, title="SMA Rounded to Hundreds")

我们首先通过 indicator() 函数来定义指标的设置,用于命名该脚本并将其叠加显示在主图的交易品种上。

然后,我们插入了上面讨论过的自定义 RoundToHundreds() 函数。(当然,我们也可以在这里使用 RoundToHundredsDown()RoundToHundredsUp() 函数。)

接下来,我们使用 Pine Script 的 ta.sma() 函数计算 SMA。我们将这个20周期的平均值存储在 smaValue 变量中。然后 plot() 函数将该变量的值显示在图表上。由于没有设置绘图类型,Pine Script 会默认创建一个常规的线图。这条线以银灰色(color.silver)显示。

之后我们创建另一个绘图。这个绘图显示的是取整到整百位的平均值。为了得到这个值,我们用 smaValue 变量调用 RoundToHundreds() 函数。这条实线以海军蓝(color.navy)显示。

该指标在图表上看起来是这样的:

如此 Tesla 图表所示,一旦移动平均线上涨超过450,取整后的平均值便从400跳升至500的水平。当平均线相继越过550和650时,也发生了类似的情况。

总结

  • 要实现取整到整百位,我们首先将待取整的数值除以100.0,然后对结果进行取整,最后再乘以100。
  • 我们所使用的取整函数,决定了最终是进行四舍五入(math.round() 函数的功能)、始终向上取整(math.ceil() 函数的功能),还是始终向下取整(math.floor() 函数的功能)。

取整到整千位

Pine Script 有几个函数可以对数值进行取整。它们会处理数值的小数部分,将其转换为整数。例如,将 12.50 变为 13。

但如果我们想将数值取整到整千位呢?这将使得 450 变为 1000,2234 变为 2000。这对于绘制成交量是一种有用的方式。或者,在交易低价加密货币时,将仓位大小取整到最接近的千位。

有三种不同的方法可以实现取整到千位。让我们来逐一探讨:

四舍五入到整千位

我们可以采取的第一种方法是进行四舍五入。当小数点(.)前的最后三位数字为500或更高时,我们向上取整;否则向下取整。这将使得 4680 变为 5000,8230 变为 8000。

下面的这个自定义函数可以将数值四舍五入到最接近的整千位:

// RoundToThousands() 函数将指定的数值向上或向下舍入到
// 最近的整千位。
RoundToThousands(value) =>
    math.round(value / 1000.0) * 1000

这个 RoundToThousands() 函数有一个参数:value。在函数内部,我们首先将该数值除以 1000.0。(如果使用整数除法,Pine Script 会舍弃小数部分,因此我们使用 1000.0。)这个除法运算会将小数点(.)向左移动三位。这样,4375.82 就会变为 4.37582。

然后,我们使用 Pine Script 的 math.round() 函数将该值取整为整数。对于 4.37582,结果是 4。之后,我们再乘以1000,以便将小数点向右移回三位。该函数的结果是一个与原始参数数量级相同的取整值。

要使用该函数,我们只需用一个数值或变量来调用它即可。例如:

RoundToThousands(2285)      //  2000
RoundToThousands(9982)      // 10000
RoundToThousands(-2010.01)  // -2000

取整范例

以下是 RoundToThousands() 函数对其他一些值的返回结果:

原始值 四舍五入到千位
5.25 0
275 0
980 1000
2285 2000
9982 10000
0.01 0
-0.01 0
-25 0
-689 -1000
-41260 -41000
na 错误;不能对 na 参数调用用户定义的函数。
“1.83” 错误;不能对字符串值调用此函数。

从表中我们可以看出,当我们四舍五入到千位时,取整后的值可能变大(例如 980 变为 1000),也可能变小(例如 2285 变为 2000)。

向上取整到整千位

第二种方法是始终向上取整到下一个整千位。这将使得 2104.5 和 2900 都被取整为 3000。

下面的 Pine Script 函数可以实现这种取整:

// RoundToThousandsUp() 函数将指定的数值向上取整到下一个
// 整数千 (1000s) 值。
RoundToThousandsUp(value) =>
    math.ceil(value / 1000.0) * 1000

这个 RoundToThousandsUp() 函数同样只有一个参数(value)。在函数内部,我们首先除以 1000.0 来移动小数点。然后使用 Pine Script 的 math.ceil() 函数将结果向上取整为整数。我们之后再乘以1000,以恢复到原始的数量级。

以下是如何调用这个函数:

RoundToThousandsUp(2285)      //  3000
RoundToThousandsUp(9982)      // 10000
RoundToThousandsUp(-2010.01)  // -2000

取整范例

以下是该函数对一些示例值的返回结果:

原始值 向上取整到千位
5.25 1000
275 1000
980 1000
2285 3000
9982 10000
0.01 1000
-0.01 0
-25 0
-689 0
-41260 -41000
na 错误;不能对 na 参数调用用户定义的函数。
“1.83” 错误;不能对字符串值调用此函数。

如表所示,当我们取整到下一个千位时,其值总是会变大。也就是说,像 2285 这样的正数会被取整为 3000。而像 -689 这样的负数在被取整为 0 后,就不再是负数了。

向下取整到整千位

第三种方法是始终向下取整到最接近的整千位。这将使得像 1200 和 1975.25 这样的值都变为 1000。

下面的这个 Pine Script 自定义函数实现了这种取整:

// RoundToThousandsDown() 函数将指定的数值向下取整到下一个
// 整千位。
RoundToThousandsDown(value) =>
    math.floor(value / 1000.0) * 1000

RoundToThousandsDown() 函数内部,我们首先将 value 参数除以 1000.0,这一步会移动小数点三个位置。然后,我们使用 Pine Script 的 math.floor() 函数向下取整。最后我们再乘以1000,以便将小数点移回其原始位置。

要使用该函数,我们只需用一个数值或变量来调用它即可。例如:

RoundToThousandsDown(2285)      //  2000
RoundToThousandsDown(9982)      //  9000
RoundToThousandsDown(-2010.01)  // -3000

取整范例

以下是 RoundToThousandsDown() 函数对其他值的返回结果:

原始值 向下取整到千位
5.25 0
275 0
980 0
2285 2000
9982 9000
0.01 0
-0.01 -1000
-25 -1000
-689 -1000
-41260 -42000
na 错误;不能对 na 参数调用用户定义的函数。
“1.83” 错误;不能对字符串值调用此函数。

当我们向下取整到最近的整千位时,取整后的值总是更小或保持不变。对于正数,其值会变小(例如275变为0)。对于负数,其值也会变小、离0更远(例如-25取整为-1000)。

脚本范例

现在,让我们看看一个 TradingView 脚本是如何使用这些自定义取整函数的。下面的指标会绘制一个加权移动平均线(WMA),然后 RoundToThousands() 函数将该平均值取整到最接近的千位。

该脚本的完整代码如下:

//@version=5
indicator(title="Round to thousands example", overlay=true)

// RoundToThousands() 函数将指定的数值向上或向下舍入到
// 最近的整千位。
RoundToThousands(value) =>
    math.round(value / 1000.0) * 1000

// 计算并绘制 WMA
wmaValue = ta.wma(close, 10)
plot(wmaValue, color=color.orange, linewidth=2, title="WMA")

// 绘制舍入到最近的千位的平均值
plot(RoundToThousands(wmaValue), color=color.fuchsia,
     linewidth=3, title="WMA Rounded to Thousands")

首先,我们通过 indicator() 函数来配置指标的设置,用于命名该脚本并将其叠加显示在主图的交易品种上。

然后,我们引入了早先讨论过的 RoundToThousands() 函数。(当然,我们也可以在这里使用 RoundToThousandsUp()RoundToThousandsDown() 函数;它们的用法是相同的。)

接下来,我们使用 Pine Script 的 ta.wma() 函数计算 WMA。我们将这个10周期的平均值存储在 wmaValue 变量中。然后 plot() 函数将该变量的值显示在图表上。由于没有设置绘图类型,Pine Script 会默认创建一个常规的线图。这条线以橙色(color.orange)显示。

之后我们创建第二个绘图。这个绘图显示的是取整到最接近的千位的平均值。因此,我们用 wmaValue 变量调用 RoundToThousands() 函数。这些值显示为一条紫红色(color.fuchsia)的线。

该指标在图表上看起来是这样的:

如此 Ethereum (ETH/USD) 期货图表所示,一旦平均线越过3500,取整后的值就从3000跳升至4000的水平。每当平均线移动到两个整数千位之间的中点之上时,都会发生类似的情况。

总结

  • 要实现取整到整千位,我们首先将待取整的数值除以1000.0,然后对结果进行取整,最后再乘以1000。
  • 我们所使用的取整函数,决定了最终是进行四舍五入(使用 math.round())、始终向上取整(使用 math.ceil()),还是始终向下取整(使用 math.floor())。

截断(truncation):直接切掉小数部分

Pine Script 可以通过多种方式对数字进行取整。其中一种选择是截断(truncation)。当我们截断一个数值时,该数字的小数部分会被直接移除 。换句话说,就是将数值的小数部分直接切掉,从而得到一个整数 。

截断操作会将 10.34 和 10.98 都变为 10,也会将 -4.75 和 -4.10 都转换为 -4。

有两种执行截断的方式:

  • 截断为整数。
  • 截断到指定的小数位数。

下面我们来逐一探讨。

截断为整数

Pine Script 的 int() 函数可以将一个浮点值截断为一个整数 。其原理是该函数会直接丢弃数值的小数部分。

int() 的默认语法格式如下 :

int(x)

x 指的是我们希望转换为整数的值。

要使用 int(),我们只需用希望截断的值来调用它即可。例如:

int(9.10)    // 返回: 9
int(3.85)    // 3
int(-1.97)   // -1
int(-0.25)   // 0
int(2)       // 2

截断范例

为了更好地理解 int() 的截断方式,下表展示了该函数对一些示例值的返回结果:

原始值 int() 截断后的值
5.92991 5
3.72 3
1.23 1
0.00002 0
0.000 0
-0.00009 0
-1.12 -1
-4.75 -4
-9.8953 -9
na na
“1.83” 错误;不能对字符串值调用 int()

从表中我们可以看出,int() 既不向上也不向下取整,而是直接删除数值的小数部分。这就是 -9.8953 被截断为 -9,以及 1.23 变为 1 的原因。

脚本范例

让我们在一个完整的脚本中使用 int()。下面的指标会绘制一条指数移动平均线及其被截断后的版本。我们将使用 Pine Script 的标签来精确展示这两个值的差异。该指标的完整代码如下:

//@version=5
indicator(title="Truncate to whole number example", overlay=true)

// 计算45周期的指数移动平均线及其
// 截断后的整数版本
emaValue     = ta.ema(close, 45)
emaTruncated = int(emaValue)

// 绘制EMA及其截断值
plot(emaValue, color=color.teal, linewidth=2, title="EMA")
plot(emaTruncated, color=color.orange, linewidth=2, 
     title="EMA Truncated")

// 每30根K线,用一个文本标签显示EMA及其截断值
if bar_index % 30 == 0
    label.new(x=bar_index, y=emaValue, color=color.black,
         textcolor=color.white, 
         text="EMA: " + str.tostring(emaValue, "0.000") + 
             "\nTruncated: " + str.tostring(emaTruncated, "0.000"))

这个指标首先通过 indicator() 函数来配置其设置,用于命名该脚本并将其叠加显示在主图的交易品种上。

接着,ta.ema() 函数计算45周期的指数移动平均线 (EMA)。我们将这个平均值存储在 emaValue 变量中。然后,我们使用 int() 函数将其截断为整数,并将结果存储在 emaTruncated 变量中。

下一步,plot() 函数在图表上显示这些值。EMA 以青色 (color.teal) 显示,而被截断的值则以橙色 (color.orange) 出现。由于我们没有明确指定绘图类型,Pine Script 默认会创建一个常规的线图。

为了看清 EMA 及其截断值的差异,我们创建一个文本标签。但我们不在每一根K线上都创建,因为那样会让每个标签都难以阅读。因此,一个 if 语句会检查当前的K线编号(bar_index)是否为30的倍数。当取模运算符(%)返回0时,即为真。

如果条件成立,if 内的代码就会调用 label.new() 函数。这会在当前K线(bar_index)和移动平均线的值(emaValue)所在的位置创建一个标签。其背景为黑色(color.black),文字为白色(color.white)。

标签的文本内容是通过 + 运算符拼接起来的几个字符串片段。其中有字面字符串,也有通过 str.tostring() 函数将数值转换为文本的动态内容。我们正是通过这种方式在标签文本中显示 EMA 及其截断值的。

在图表上,该指标会绘制移动平均线和截断后的值。每隔一段K线,一个文本标签就会显示这两条绘图线的精确数值:

(标签可能会显示在价格K线的后面。要让它们显示在前面,请将脚本的“视觉顺序”(Visual Order)设置为“置于顶层”(Bring to Front)。)

截断到指定的小数位数

另一种方法是截断到指定的小数位数。这会切掉超出特定数量的任何小数。

例如,这将 2.99 变为 2.9,也可以将 6.2092 变为 6.20。

自定义函数

目前,Pine Script 没有内置函数可以实现按小数位数进行截断。但没关系,我们可以自己创建一个:

// Truncate() 函数将给定的数值截断到指定的
// 小数位数。
Truncate(number, decimals) =>
    factor = math.pow(10, decimals)
    int(number * factor) / factor

这个自定义的 Truncate() 函数有两个参数:一个是需要被截断的值(number),另一个是说明结果应保留多少位小数(decimals)。

在函数内部,我们首先将10进行 decimals 次幂的运算,这会得到一个修正因子,我们将用它来向右移动小数点(.)。

然后,在 int() 函数内部,我们将 number 值与 factor 变量相乘。这一步首先将小数点向右移动,然后 int() 将结果截断为整数。最后,我们将这个截断后的结果再除以 factor 变量,从而将小数点向左移回其原始位置。

让我们来看一个例子。假设我们想将 12.8934 截断到2位小数。当我们将10的2次幂时,得到100。它乘以输入值 12.8934 得到 1289.34。当我们用 int() 对该值进行截断时,得到 1289。最后我们再除以100,以恢复正确的数量级,这样就得到了 12.89 这个最终结果。

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

Truncate(12.89, 1)      // 返回: 12.8
Truncate(1.209, 2)      // 1.20
Truncate(383.7924, 0)   // 383

截断范例

为了更好地理解该函数的返回值,下表将一些示例值截断到1位小数:

原始值 截断到1位小数
5.92991 5.9
3.72 3.7
1.23 1.2
0.00002 0.0
0.000 0.0
-0.00009 0.0
-1.12 -1.1
-4.75 -4.7
-9.8953 -9.8
na 错误;不能对 na 参数调用函数。
“1.83” 错误;不能对字符串参数调用此函数。

自定义的 Truncate() 函数与四舍五入不同。它并非总是向上或向下取整,而是简单地切掉小数。这对数值符号的正负有不同的影响。

负数值(如-4.75)会变大(-4.7),因为舍弃小数部分对负数来说相当于向上取整;而正数值则会变小(1.23变为1.2),相当于向下取整。

脚本范例

让我们看看脚本如何使用 Truncate()。像上面一样,下面的脚本会绘制两个值:一个是简单移动平均线(SMA),另一个是该平均线被截断到指定小数位数后的值。

每隔一定数量的K线,我们会创建一个标签来显示平均线及其截断值的精确数值。

该指标的完整代码如下:

//@version=5
indicator(title="Truncate to decimals example", overlay=true)

// Truncate() 函数将给定的数值截断到指定的
// 小数位数。
Truncate(number, decimals) =>
    factor = math.pow(10, decimals)
    int(number * factor) / factor

// 创建一个输入来设置要截断到的小数位数
decimalAmount = input.int(1, title="Number of Decimals", minval=0)

// 计算简单移动平均线及其截断后的版本
smaValue     = ta.sma(close, 20)
smaTruncated = Truncate(smaValue, decimalAmount)

// 绘制SMA及其截断值
plot(smaValue, color=color.purple, linewidth=2, title="SMA")
plot(smaTruncated, color=color.yellow, linewidth=2,
     title="SMA Truncated")

// 每30根价格K线,创建一个标签来显示
// SMA值及其截断到小数后的版本
if bar_index % 30 == 0
    label.new(x=bar_index, y=smaValue, style=label.style_label_up,
         color=#f2f2f2, textcolor=color.black, 
         text="SMA: " + str.tostring(smaValue, "0.000") + 
             "\nTruncated: " + str.tostring(smaTruncated, "0.000"))

indicator() 函数首先配置指标的设置,用于为脚本命名并将其叠加显示在主图的交易品种上。

然后,我们引入了上面讨论过的自定义 Truncate() 函数。

接着,我们使用 input.int() 函数创建一个整数输入选项。这个输入的名称是 Number of Decimals。它用于指定 Truncate() 函数应使用的小数位数。我们为其设置了默认值为1,最小值为0。我们将这个输入值存储在 decimalAmount 变量中,之后可以通过访问该变量来获取输入的当前值。

然后,ta.sma() 函数计算20周期的收盘价(close)的简单移动平均线。我们将这个平均值存储在 smaValue 变量中。接着我们对该变量调用 Truncate() 函数,将其截断到由输入选项(decimalAmount)设置的小数位数。我们将截断后的值存入 smaTruncated 变量。

plot() 函数随后绘制 SMA 及其截断值。前者显示为一条紫色(color.purple)的线;后者则以黄色(color.yellow)显示。由于我们没有设置绘图类型,Pine Script 默认会为两者创建常规的线图。

最后一段代码是一个 if 语句。这个语句判断当前的K线编号(bar_index)是否为30的倍数。当它是时,K线编号对30取模(%)的结果等于(==)零。通过这种方式,if 语句可以每30根K线执行一次。

if 语句内部,label.new() 函数创建一个文本标签。这个绘图显示在当前K线(bar_index)的 SMA 值(smaValue)位置。其样式指向上方(label.style_label_up)。背景为浅灰色,通过十六进制颜色值 #f2f2f2 设置,其上的字母以黑色(color.black)显示。

标签的文本内容是通过 + 运算符拼接起来的几个字符串片段。其中两个是 str.tostring() 函数的调用。第一个将 SMA 的值转换为字符串,另一个则将截断后的值转换为文本。这使得两个数值都能与标签所需的字符串片段兼容。

在图表上,该脚本会显示移动平均线及其截断值。在其标准设置下,这些值被截断到1位小数:

如果我们把脚本的输入选项改为2,移动平均线就会被截断到两位小数。这会将标签更改为:

你可以亲自试用该脚本,看看它是如何运作的。(如果你将脚本添加到图表,标签可能会部分显示在价格K线的下方。要让标签显示在K线之上,请将脚本的“视觉顺序”(Visual Order)设置为“置于顶层”(Bring to Front)。)

截断与四舍五入的对比

截断与四舍五入(向上或向下取整)会产生不同的结果。当我们进行四舍五入时,我们会根据一个数的小数部分来决定是应该向上还是向下取整。但对于截断,我们不关心小数部分(只是直接扔掉它)。

  • 当我们四舍五入时,我们将一个数转换为其最接近的整数。这将 2.8 变为 3,5.2 变为 5。小数部分为 .5 的值会被向上取整;低于此值的小数部分则会被向下舍去。
  • 然而,截断是不同的。当我们截断时,我们移除一个数的小数部分。也就是说,我们切掉小数部分,从而得到一个整数。通过这种方式,2.8 变为 2,而 5.2 也被变为 5。

注意事项

看待这两者差异的另一种方式如下:当我们截断时,小数点(.)前的数值永远不会改变。但如果我们进行四舍五入,该值则可能向上或向下改变。

示例值对比

以下是四舍五入和截断操作对一些示例值的不同结果:

原始值 四舍五入为整数 (math.round()) 截断为整数 (int())
5.92991 6 5
3.72 4 3
1.23 1 1
0.00002 0 0
0.000 0 0
-0.00009 0 0
-1.12 -1 -1
-4.75 -5 -4
-9.8953 -10 -9
na 0 na
“1.83” 错误;不能对字符串调用 math.round() 错误;不能对字符串调用 int()

如上所示,截断和四舍五入有时可以得到相同的结果。但这只发生在我们将一个正数向下取整时(例如 1.23 变为 1),以及我们将一个负数向上取整时(例如 -1.12 变为 -1)。在其他情况下,四舍五入和截断会得出不同的结果。

由于这些结果会根据数值的符号(正或负)而有所不同,截断操作能提供我们通过四舍五入无法实现的结果。

总结

  • 当我们截断一个数时,我们是直接丢弃其小数部分。
  • 与四舍五入不同,截断永远不会改变小数点(.)前的数值。
  • 要截断为整数,我们使用 Pine Script 的 int() 函数。
  • 通过一个自定义函数,我们也可以截断到指定的小数位数。
赞(0)
未经允许不得转载:图道交易 » Pine Script(121):取整到整十整百整千位,以及截断小数
分享到

评论 抢沙发

登录

找回密码

注册