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

Pine Script(175):更改标签位置,set_x、set_y与set_xy

#Pine Script入门教学

哪些Pine Script函数可以改变TradingView标签的位置

在TradingView图表上,当Pine Script程序绘制一个标签时,这个标签会出现在特定的价格轴与时间轴坐标点上。通常情况下,标签会固定在该图表位置。但在某些场景下,我们创建标签后,需要把它移动到别处。那么该如何操作呢?

以下这些Pine Script函数可以把标签移动到不同的位置:

函数 描述
label.set_x() 把标签更新到新的时间轴坐标。
label.set_y() 把标签更改到不同的价格轴坐标。
label.set_xy() 把标签同时修改到不同的时间轴和价格轴坐标。
label.set_xloc() 调整标签时间轴坐标的类型(例如从K线编号切换为时间值,或反之)。
label.set_yloc() 把标签锚定至其所在的价格K线(或移除先前添加的锚定设置)。

为了更清晰地理解,我们可以把这些函数分为两类。一类只负责移动标签:label.set_x()label.set_y()label.set_xy();另一类在移动标签的同时还会改变其坐标类型:label.set_xloc()label.set_yloc()。下面我们逐一来看。

设置时间坐标

label.set_x()函数用于改变标签的X轴坐标。由于标签的价格坐标保持不变,该函数只会在图表上水平移动标签(即向左或向右移动)。

label.set_x()需要我们提供两个参数。第一是标签的标识符,用于指定要修改哪一个标签。第二是新的时间坐标,可以是一个K线编号,也可以是一个时间值。

我们分别来看这两种用法。若要把标签移动到某个K线编号,首先需要一个可供操作的标签,所以先用label.new()创建一个:

// 在价格中点(最高价与最低价的均值)创建一个标签
myLabel = label.new(bar_index, hl2)

这里的label.new()在当前K线的价格中点绘制了一个标签。函数会返回该标签独有的标识符,我们把它存入myLabel变量,以便后续通过这个变量来访问标签。

值得注意的是,我们并未指定label.new()使用K线编号作为其时间坐标,因为这是标签的默认行为。

接下来,若要改变标签的位置,就调用label.set_x()函数:

// 将标签的时间坐标向右移动一根K线
label.set_x(myLabel, bar_index + 1)

我们向该函数传入了两个参数。myLabel是包含标签标识符的变量,它告诉函数需要修改的是哪一个标签。bar_index变量加1则是标签新的时间坐标,此操作会把标签移动到当前K线右侧一根K线的位置。

label.set_x()的另一种用法是配合时间值。为演示其工作原理,我们先创建一个标签:

// 在当前K线的价格中点(hl2),创建一个使用时间坐标的标签
myLabel = label.new(time, hl2, xloc=xloc.bar_time)

这里的label.new()在当前K线的时间戳和价格中点处绘制了一个标签。由于标签默认使用K线编号,我们必须显式地告知label.new()使用时间值,做法是把xloc参数设为xloc.bar_time。函数返回的标识符同样被储存在myLabel变量中,以备后用。

然后,我们使用label.set_x()把标签移动到一个不同的时间点:

// 将标签的时间坐标更新至未来一根K线的位置。为计算
// 未来的时间点,我们将一根K线的周期时长(time - time[1])
// 添加到当前K线的时间戳上。
label.set_x(myLabel, time + (time - time[1]))

我们为label.set_x()提供了两个参数。myLabel变量告知函数要修改哪个标签。另一个参数则是一个时间值,这里我们基于当前K线的开盘时间(time)计算出一个未来的时间坐标,label.set_x()随即就会把标签移动到该位置。

设置价格坐标

label.set_y()函数用于改变标签的价格坐标。由于标签的时间坐标维持不变,该函数会沿着价格轴垂直移动标签(也就是向上或向下移动)。

要正常工作,label.set_y()需要知道目标标签的标识符以及新的价格轴坐标。

我们通过一个实例来了解其运作方式。为了有一个可操作的标签,首先调用label.new()函数:

// 在当前K线的最高价处创建一个标签
myLabel = label.new(bar_index, high)

这里label.new()在当前K线的最高价绘制了一个标签。为了方便后续访问,我们把函数返回的标识符存入myLabel变量。

现在,我们便可以使用label.set_y()来改变标签的价格轴坐标了:

// 将标签的价格坐标更新至当前K线最低价下方0.5%的位置
label.set_y(myLabel, low * 0.995)

我们用两个参数来执行此函数。第一个参数用于指定要修改哪个标签,这里我们使用myLabel变量。第二个参数是新的价格轴坐标,我们计算了一个位于当前K线最低价下方0.5%的坐标值。

只要标签当前不在此价格坐标,Pine Script就会把它移动到指定位置。

设置价格和时间坐标

label.set_xy()函数可以同时更新标签的价格轴和时间轴坐标。这使得标签可以在图表上进行任意的水平和垂直移动。

label.set_xy()需要知道三项信息:首先是标签的标识符,用以指定要修改哪个标签;其次是标签新的时间轴坐标;最后是新的价格轴坐标。

与前面讨论的label.set_x()类似,label.set_xy()的时间轴坐标既可以使用K线编号,也可以使用时间值。我们分别探讨这两种情况。

若要把标签移动到不同的K线编号,我们首先需要一个标签,所以用label.new()来创建:

// 在当前K线的最高价处放置一个标签
myLabel = label.new(bar_index, high)

这段代码在当前K线的最高价处绘制了一个标签。我们从该函数获取的标识符被存入myLabel变量,以供后续调用。

接下来,要改变标签的位置,我们调用label.set_xy()函数:

// 将标签的价格更改为当前K线的收盘价,
// 并将其时间坐标向右移动5根K线。
label.set_xy(myLabel, bar_index + 5, close)

我们向label.set_xy()传递了三个值。第一个值myLabel变量,通过标签标识符指定了要修改的标签。

第二个值是标签新的时间坐标。这里我们用当前K线编号(bar_index)加上5,这会把标签移动到当前K线右侧五根K线的位置(即图表上一个未来的位置)。

第三个值是新的价格轴坐标,这里是当前K线的收盘价。如果标签当前的位置不在此K线编号和价格的组合点,label.set_xy()就会把标签移动到该处。

另一种方式是结合时间值来使用label.set_xy()。为演示其工作原理,我们首先用label.new()创建一个标签:

// 在当前K线的最高价处绘制一个标签
myLabel = label.new(time, high, xloc=xloc.bar_time)

这段代码在当前K线的时间戳和最高价位置创建了一个标签。由于标签默认使用K线编号,我们通过把xloc参数设置为xloc.bar_time,明确地让函数改用时间值。从label.new()获取的标识符存入myLabel变量。

要把标签移动到新位置,我们调用label.set_xy()函数:

// 将标签的价格更新到当前收盘价,并将其
// 时间坐标更改为未来5天后的同一时间。
label.set_xy(myLabel, time + 5 * 86400000, close)

我们向label.set_xy()传递了三个值。首先是myLabel变量,它告诉函数要调整哪个标签。

其次是新的时间坐标。我们把当前K线的开盘时间(time)加上5倍的单日毫秒数,此操作会把标签移动到从当前K线算起五天后的一个未来图表坐标上。

第三个值是当前K线的收盘价(close)。只要标签当前不位于该时间和价格组合点,label.set_xy()就会让标签跳转到那个新位置。

设置X轴坐标类型

label.set_xloc()函数用于更改标签时间轴坐标的类型。这听起来可能有些复杂,但实际上它的作用就是指定标签的时间坐标是应该基于K线编号,还是基于时间值。

通常我们使用K线编号来定位标签。但有时,我们也需要计算一个精确的时间点来显示标签,这就要求标签使用时间值作为坐标。

当一个现有的标签正使用K线编号作为其时间轴坐标时,label.set_xloc()可以把它切换为使用时间值。同样地,当一个标签使用时间值时,label.set_xloc()则会把它切换回使用K线编号的模式。

label.set_xloc()需要三个参数:标签的标识符、标签新的时间轴坐标,以及要使用的时间坐标类型。

对于坐标类型,我们有两个选项。使用xloc.bar_time值,可以让标签采用时间值作为坐标;而xloc.bar_index值则让标签使用K线编号。下面我们分别看看这两种用法。

要把一个标签从使用K线编号切换为使用时间值,首先我们需要一个标签,所以先用label.new()创建:

// 在当前K线的收盘价处,创建一个基于K线编号的标签
myLabel = label.new(bar_index, close)

这里,label.new()在当前K线的收盘价(由bar_indexclose决定)位置绘制了一个标签。我们没有指定其时间坐标的类型,所以Pine Script默认使用K线编号。函数返回的标签标识符被我们存储在myLabel变量中,以供后续使用。

要切换该标签时间轴坐标的类型,我们调用label.set_xloc()函数:

// 让标签改用时间值,并将其移动到当前K线
// 右侧6小时的位置
label.set_xloc(myLabel, time + 6 * 3600000, xloc.bar_time)

我们向该函数传递了三个参数。第一个参数myLabel,通过其存储的标签标识符,指定了我们要修改的目标标签。

第二个参数是标签新的时间坐标。我们通过把当前K线的开盘时间(time)加上6小时对应的毫秒数,来计算出一个未来的时间点。

最后一个参数是xloc.bar_time,它告诉标签从此刻起,应使用时间值作为其X轴坐标。

现在,我们探讨label.set_xloc()的另一种应用场景:把标签从使用时间值切换回使用K线编号。我们同样先创建一个标签:

// 在K线的收盘价处,创建一个基于时间的标签
myLabel = label.new(time, close, xloc=xloc.bar_time)

这里的label.new()在当前K线的收盘价(由timeclose决定)位置绘制了一个标签。我们通过xloc参数把它设置为xloc.bar_time,这使得标签的时间轴坐标使用时间值。返回的标识符被存储在myLabel变量中。

接着,要改变该标签时间轴坐标的类型,我们调用label.set_xloc()函数:

// 将标签的坐标类型改回K线编号,并将其向右移动6根K线
label.set_xloc(myLabel, bar_index + 6, xloc.bar_index)

我们为label.set_xloc()提供了三个值。首先是标签标识符(myLabel),它告诉函数要修改哪一个标签。

其次是标签新的时间轴坐标。这里我们用当前K线编号(bar_index)加上6,此操作会把标签移动到当前K线右侧六根K线的位置(即一个未来的坐标)。

最后是xloc.bar_index值,它指示标签从现在开始,应使用K线编号作为其时间轴坐标。

设置Y轴锚定方式

label.set_yloc()函数用于配置标签的锚定方式。一个被锚定的标签总是会显示在对应价格K线的上方或下方,而无视其自身实际的价格坐标。

label.set_yloc()需要两个参数。第一是标签标识符,用以确定要修改哪个标签。第二是标签新的锚定方式。

Pine Script提供以下几种锚定方式:

  • yloc.abovebar:使标签显示在其时间轴坐标所在K线的上方。
  • yloc.belowbar:使标签显示在其时间轴坐标所在K线的下方。
  • yloc.price:让标签显示在我们设定的精确价格坐标上。这是新标签的默认行为,也是我们用来移除之前为标签设置的锚定效果的方式。

我们看看具体如何操作。首先需要一个可供操作的标签,所以调用label.new()函数:

// 在K线的最高价处绘制一个标签
myLabel = label.new(bar_index, high)

这段代码在当前K线的最高价处绘制了一个标签。为了方便后续访问,我们把其标识符存入myLabel变量。

要把此标签锚定到K线上,我们执行label.set_yloc()函数:

// 修改标签的Y轴行为;让它显示在价格K线的下方,
// 无论标签自身的价格坐标为何值
label.set_yloc(myLabel, yloc.belowbar)

我们向label.set_yloc()传递了两个参数。第一个是myLabel变量,它持有标签的标识符,函数据此得知要修改哪个标签。

另一个参数用于设定新的标签锚定方式。我们使用yloc.belowbar,来让标签始终显示在其时间坐标所对应的价格K线的下方。

总结

Pine Script提供了数个函数来更新标签的位置和显示方式。

  • label.set_x():更改标签的时间轴坐标。
  • label.set_y():修改标签的价格坐标。
  • label.set_xy():同时更新标签的时间和价格坐标。
  • label.set_xloc():设定标签的时间轴坐标是使用K线编号还是时间值。
  • label.set_yloc():将标签锚定在对应K线的上方或下方。

以上每个函数都需要一个标签标识符来确定要修改哪个标签。这个标识符由label.new()函数在创建标签时返回。

用label.set_x()更改标签的时间坐标

在我们的Pine Script代码创建标签之后,可以使用label.set_x()函数来更改该标签的时间坐标。

label.set_x()把标签移动到一个新的X轴坐标。由于标签的价格坐标保持不变,因此标签仅会在图表的时间轴上水平移动。

要更改一个标签的时间坐标,label.set_x()需要两个信息:要修改的是哪个标签,以及它的新时间坐标是什么。我们深入了解其工作原理。

函数语法格式

这是该函数的标准语法格式:

label.set_x(id, x)
  • id参数用于指定我们想要修改的标签的标识符。Pine Script正是通过这个标识符来识别要修改的具体标签,如果没有它,Pine Script将无从知晓我们想要更改哪个标签。这个标识符由label.new()函数在创建标签时返回。如果我们(不小心)为此参数传入了na值,label.set_x()将无法更改标签的时间坐标(但好在程序在这种情况下并不会抛出错误)。
  • x参数是一个数值,代表标签新的时间坐标。这个坐标既可以是K线编号,也可以是时间值,具体使用哪种值取决于该标签先前是如何定义的:标签默认使用K线编号,如果我们没有更改过这个设置,或者曾使用xloc.bar_index把标签的坐标类型设置回K线编号,那么该标签就使用K线编号,这意味着我们为x参数提供的值也必须是K线编号;如果label.new()label.set_xloc()函数早前已把标签的坐标类型设置为xloc.bar_time,那么该标签就使用时间值,此时传给x参数的也必须是一个时间值。

快速示例

综上所述,使用label.set_x()有两种方式:配合K线编号或配合时间值。我们快速浏览这两种用法。

先看K线编号。要把一个标签移动到不同的K线编号上,我们首先需要一个标签,所以用label.new()创建一个:

// 在价格中点(hl2)创建一个指向左侧的蓝绿色标签
myLabel = label.new(x=bar_index, y=hl2, color=color.teal,
	 style=label.style_label_left, size=size.large)

这段代码在当前K线的中点价格(由bar_indexhl2确定)处创建了一个新标签。标签的颜色为蓝绿色(color.teal),样式为指向左侧的箭头,尺寸设置为大号(size.large)。

我们没有告知label.new()标签应该使用K线编号还是时间值,因此它会采用默认的K线编号模式。

label.new()返回的标识符被我们存入myLabel变量,以便后续通过该变量来访问此标签。

接下来,我们更改该标签的时间坐标:

// 将标签的时间坐标向右移动一根K线
label.set_x(id=myLabel, x=bar_index + 1)

这里我们调用label.set_x()并传入了两个参数。第一个id=myLabel,通过我们之前保存的标识符,告诉函数要修改哪个标签。

另一个参数x=bar_index + 1,把当前K线的编号加1,以此作为新的时间坐标。此操作会把标签向右移动一根K线(相对于当前K线)。

再看时间值。label.set_x()也可以把标签移动到一个特定的时间值坐标,但这要求该标签已经在使用时间值作为其坐标类型。

我们创建一个新标签,并让它从一开始就使用时间值:

// 在K线的价格中点(hl2)创建一个基于时间的标签。
// 这个标签同样指向左侧,并以蓝绿色显示。
myLabel = label.new(x=time, y=hl2, xloc=xloc.bar_time,
	 color=color.teal, style=label.style_label_left, size=size.large)

这里的label.new()在当前K线的中点价格(由timehl2确定)处绘制了一个标签。xloc=xloc.bar_time参数告知函数,此标签应使用时间值作为其X坐标。

标签的颜色是蓝绿色(color.teal),样式指向左侧(label.style_label_left),尺寸也设置为大号(size.large)。

我们把label.new()返回的标识符存储在一个变量中,以备后用。

然后,我们使用label.set_x()把标签移动到另一个位置:

// 将标签的时间坐标更新到未来一根K线的位置。为计算
// 未来的时间点,我们将一根K线的周期时长(time - time[1])
// 添加到当前K线的时间戳上。
label.set_x(id=myLabel, x=time + (time - time[1]))

label.set_x()的第一个参数是myLabel,我们通过它来访问刚刚创建的标签。

对于新的时间坐标x,我们首先获取当前K线的时间戳(time),然后加上当前K线与前一根K线之间的时间差(time - time[1]),这个差值近似于一根K线的周期时长。这样计算的结果便是下一根K线大致的时间戳。最终效果是,label.set_x()把标签向右移动了一根K线的距离。

图表示例

以上两个示例所创建的标签,其外观是相同的。它在图表上的显示效果如下:

下面这段代码展示了如何把时间值示例中的代码片段整合为一个完整的Pine Script指标:

//@version=5
indicator(title="label.set_x() 快速示例", overlay=true)

// 判断脚本是否在图表的最后一根K线上执行计算
if barstate.islast
    // 在K线价格中点(hl2)创建一个基于时间的标签。
    // 它指向左侧并以蓝绿色显示。
    myLabel = label.new(x=time[3], y=hl2, xloc=xloc.bar_time,
         color=color.teal, style=label.style_label_left, size=size.large)

    // 将标签的时间坐标更新到未来一根K线的位置。为计算
    // 那个未来的时间点,将一根K线的周期时长(time - time[1])
    // 添加到当前K线的时间戳上。
    label.set_x(id=myLabel, x=time + (time - time[1]))

我们从indicator()函数开始,通过title参数为脚本命名,并通过overlay=true使脚本叠加显示在主图表上。

接着,一个if语句用来判断脚本是否正在处理图表的最后一根价格K线(barstate.islast)。当脚本运行到这一根K线时,Pine Script便会执行我们前面讨论过的代码:label.new()创建一个新标签,随后label.set_x()更新该标签的时间坐标。

关键字参数

label.set_x()的关键字参数是可选的。我在上面的示例中使用了它们,是为了让代码更易于阅读和理解。但我们完全可以省略id=x=这些可选部分,以节省一些输入量。

在Pine Script中,省略后的代码如下所示:

// 将标签的时间坐标向右移动一根K线
label.set_x(myLabel, bar_index + 1)

// 将标签的时间坐标更新至未来一根K线的位置
label.set_x(myLabel, time + (time - time[1]))

label.set_x()的使用方式

label.set_x()主要用于实现两个目的:把标签向其当前位置的左侧移动(即移动到时间上更早的位置),或者向右侧移动(即移动到时间上更晚的位置)。

在实际应用中,我们常常把label.set_x()if条件语句结合使用,这样就可以只在满足特定条件时才执行函数来移动标签。

如果我们不加任何条件地执行label.set_x(),那么该函数会在每一根K线上都更新标签的时间坐标。这会使得标签随着脚本处理的每一根新K线而持续移动。

如果标签的位置只需要在创建时设置一次,那么直接在label.new()函数中完成会更简洁,比后续再单独调用label.set_x()所需的代码更少。

要更改标签的价格坐标,我们应使用label.set_y()函数。而label.set_xy()函数则可以同时更新标签的价格和时间坐标。

示例脚本

我们通过一个完整的脚本来实践label.set_x()的用法。下面的指标会计算图表上所有K线的平均成交量。

我们把这个平均值绘制成一条线,并同时把其数值显示在一个标签里。这个标签我们只创建一次,之后在每根K线上持续更新它的位置。为此,我们便用到了label.set_x()函数。

指标的完整代码如下:

//@version=5
indicator(title="更改标签的时间坐标", overlay=true,
     scale=scale.left, precision=0)

// 仅创建一次持久化数组。在每根K线上,将该K线的成交量添加进去。
var volumeArray = array.new_float()
array.push(volumeArray, volume)

// 计算并绘制图表的平均成交量
avgVolume = array.avg(volumeArray)
plot(avgVolume, color=color.blue, linewidth=2)

// 仅创建一次持久化标签。后续代码会将其移动到每根新K线上。
var volumeLabel = label.new(x=na, y=na, color=#F0F8FF,
     style=label.style_label_left)

// 在每根K线上,更新标签的X和Y轴位置
label.set_x(volumeLabel, bar_index)
label.set_y(volumeLabel, avgVolume)

// 使用当前的平均成交量更新标签的文本
label.set_text(volumeLabel, "Average volume:\n" + 
     str.tostring(avgVolume, "###,###.00"))

首先,我们调用indicator()函数来配置指标的几项基本设置。通过title为脚本命名;overlay=true使指标叠加显示在主图表上。

scale=scale.left参数把脚本的价格刻度关联到左侧坐标轴(而非默认的右侧)。如果不这样做,成交量的数值会干扰主图表交易品种自身的价格刻度。precision=0则让脚本的绘图值显示为不带小数的整数。

接着,我们使用array.new_float()函数创建一个用于存储浮点数的数组。通过var关键字,Pine Script可以确保这个数组只在图表加载时创建一次(否则,数组的值会在每根K线上被重置)。

我们调用array.push()函数,把当前K线的成交量(volume)添加到数组中。由于此操作在每根K线上都会执行,因此到图表末尾时,我们就收集了所有历史K线的成交量数据。

array.avg()函数负责计算数组中所有数值的平均值,即每根K线的平均成交量。我们把结果存储在avgVolume变量中。

然后,plot()函数把这个平均成交量绘制出来。由于未指定绘图类型,Pine Script默认绘制一条常规的线图。这条平均成交量线以蓝色(color.blue)显示,并且线宽设置为2,比默认更粗。

为了在标签中也显示平均成交量,我们首先用label.new()创建一个标签:

// 仅创建一次持久化标签。后续代码会将其移动到每根新K线上。
var volumeLabel = label.new(x=na, y=na, color=#F0F8FF,
     style=label.style_label_left)

这会绘制一个颜色为#F0F8FF(爱丽丝蓝的十六进制色值)的标签。其样式为label.style_label_left,即一个箭头指向左侧的标签。

我们把标签的时间和价格坐标都设置为na。这暂时不会在图表上显示标签,但这没关系:我们稍后会立即把它更新到实际坐标。

为了方便后续操作,我们把label.new()返回的标识符存储在volumeLabel变量中。变量前的var关键字确保了该变量(及其所创建的标签对象)只被初始化一次。这样做非常高效,因为我们只需要一个标签来展示平均成交量,而无需在每根K线上都创建新标签。

但是,我们需要在每根K线上都更新标签的位置,这样它才能跟随最新的价格K线移动。所以我们执行以下代码:

// 在每根K线上,更新标签的X和Y轴位置
label.set_x(volumeLabel, bar_index)
label.set_y(volumeLabel, avgVolume)

这里的label.set_x()负责更新标签的时间坐标。我们通过volumeLabel变量指定要修改的标签,并使用bar_index变量把标签移动到当前K线的位置。

同时,我们用label.set_y()来更改标签的价格坐标。同样通过volumeLabel变量指定目标标签,并把新的价格坐标设置为当前的平均成交量(avgVolume)。

请注意,label.set_x()label.set_y()都在每根K线上无条件执行。这使得标签能够从一根K线移动到下一根,始终显示在图表的最右侧。

为了让标签信息保持最新,我们同样在每根K线上刷新其文本内容:

// 使用当前的平均成交量更新标签的文本
label.set_text(volumeLabel, "Average volume:\n" + 
     str.tostring(avgVolume, "###,###.00"))

label.set_text()函数用于更新标签的文本。该函数需要两个参数:第一个volumeLabel是要修改的标签的标识符。

另一个参数是标签的新文本。我们用+号把字符串字面量”Average volume:\n”与avgVolume变量的值连接起来。由于avgVolume是一个数值,我们用Pine Script的str.tostring()函数把它转换为格式化的字符串。

在图表上,该指标把所有K线的平均成交量绘制为一条实线。标签则指向最新的数值,并把它作为文本显示。在下面的欧元/美元图表中,我们可以看到近期的平均成交量有所上升:

label.set_x()的特性

当标签使用K线编号作为其时间坐标时,label.set_x()无法把标签移动到未来超过500根K线的位置。如果我们尝试这样做,Pine Script会生成如下错误信息:objects positioned using xloc.bar_index cannot be drawn further than 500 bars into the future(使用xloc.bar_index定位的对象不能被绘制到未来超过500根K线的位置)。

如果标签正在使用K线编号,但我们却提供了一个时间值给label.set_x(),也会触发同样的错误。要解决这个问题,我们应该向label.set_x()传入一个K线编号。或者,如果我们确实需要使用时间值,就必须先用label.set_xloc()函数把标签的坐标类型切换为时间模式。

对于历史K线,标签则没有这种限制。label.set_x()可以使用K线编号或时间值,把标签放置在历史上任何一根K线上。

总结

  • label.set_x()函数用于更改一个标签的时间坐标。
  • 该函数需要两个核心参数:标签的标识符(通过label.new()函数获取)和新的时间轴坐标。
  • 这个新坐标可以是K线编号或时间值,具体取决于标签当前的坐标类型。K线编号是默认类型。要让标签使用时间值,我们需要通过xloc.bar_time值进行设置。
  • 由于标签的价格坐标保持不变,label.set_x()的效果是沿着图表的时间轴水平移动标签。

用label.set_y()更改标签的价格坐标

在我们的Pine Script代码绘制出标签后,可以使用label.set_y()函数来更改该标签的价格坐标。

label.set_y()把标签移动到一个新的Y轴坐标。由于标签的时间坐标保持不变,该函数的效果是沿着图表的价格轴垂直移动标签(即向上或向下移动)。

要使用label.set_y(),我们需要提供两个信息:要修改的是哪个标签,以及它的新价格坐标是什么。我们来深入了解该函数的运作方式。

函数语法格式

该函数的标准语法格式如下:

label.set_y(id, y)
  • id参数用于指定我们想要更改其价格坐标的标签的标识符。Pine Script正是通过这个标识符来识别要修改的具体标签,否则它将无从知晓我们想要更改哪个标签。这个标识符由label.new()函数在创建标签时返回。如果为该参数传入na值,label.set_y()将无法更改标签的价格坐标(但好在这种情况下程序并不会抛出错误)。
  • y参数是一个数值,代表标签新的价格坐标。Pine Script会把标签移动到这个新坐标,除非我们之前已经通过yloc.abovebaryloc.belowbar值把该标签锚定到了价格K线上。一个被锚定的标签是无法被移动的。

快速示例

在使用label.set_y()更改标签的价格坐标之前,我们首先需要一个标签。我们可以调用Pine Script的label.new()函数来创建一个:

// 在K线最高价处创建一个指向上方的橙色标签
myLabel = label.new(x=bar_index, y=high, color=color.orange,
	 style=label.style_label_up, size=size.large)

这段代码在当前K线的最高价(由bar_indexhigh确定)处创建了一个标签。它的颜色是橙色(color.orange),标签样式为指向上方的箭头(label.style_label_up),并且尺寸设置为大号(size.large)。

我们把label.new()返回的标识符存储在myLabel变量中。

然后,我们使用这个变量来更新标签的价格坐标:

// 将标签的价格坐标更新至当前K线最低价下方0.5%的位置
label.set_y(id=myLabel, y=low * 0.995)

这里的label.set_y()把标签的价格坐标更改为当前K线最低价(low)下方0.5%的位置。我们通过myLabel变量来告知函数需要修改的是哪一个标签。

图表示例

上述快速示例所创建的标签,在图表上的效果如下所示:

以下代码展示了如何把上面的两个代码片段整合为一个完整的Pine Script指标:

//@version=5
indicator(title="label.set_y() 快速示例", overlay=true)

// 检查脚本是否正在最后一根已确认的历史K线上进行计算
if barstate.islastconfirmedhistory
    // 在K线最高价处创建一个指向上方的橙色标签
    myLabel = label.new(x=bar_index, y=high, color=color.orange,
         style=label.style_label_up, size=size.large)

    // 将标签的价格坐标更新至当前K线最低价下方0.5%的位置
    label.set_y(id=myLabel, y=low * 0.995)

我们从indicator()函数开始编写代码。title参数为脚本命名,而overlay=true使脚本叠加显示在主图表上。

接着,一个if语句判断脚本当前是否正在处理最后一根已确认的历史K线(通过barstate.islastconfirmedhistory判断)。如果条件为真,Pine Script便会执行我们前面讨论过的代码:label.new()绘制一个新标签,随后label.set_y()更新该标签的价格坐标。

关键字参数

label.set_y()idy关键字参数是可选的。我在前面的代码示例中使用了它们,是为了更清晰地展示函数需要哪些数据。但一旦我们熟悉了函数的用法,便可以省略它们,这样可以减少一些键盘输入量。

不使用关键字参数时,label.set_y()的调用方式如下:

// 将标签的价格坐标更新至当前K线最低价下方0.5%的位置
label.set_y(myLabel, low * 0.995)

label.set_y()的使用方式

我们使用label.set_y()主要有两个目的:把标签移动到比其当前位置更高的价格坐标,或者移动到更低的价格坐标。

在绝大多数情况下,我们会把label.set_y()放置在if条件语句内部。这样,函数只会在满足特定条件时才被执行,从而更新标签的位置。

当然,也可以在没有任何条件的情况下执行label.set_y()。这会导致标签的价格坐标在每一根K线上都被更新。

如果我们的脚本需要在创建标签后立即更改其价格,并且这种更改只发生一次,那么直接在label.new()函数中设置最终坐标会更加方便,所需的代码也比之后再单独调用label.set_y()要少。

如果我们想改变标签的时间坐标,则应改用label.set_x()函数。而通过label.set_xy()函数,我们可以同时更改标签的价格和时间坐标。

示例脚本

我们通过一个完整的脚本来实践label.set_y()。下面的指标会计算一条20周期的指数移动平均线(EMA)。每当价格向上穿越这条平均线时,我们就创建一个新的标签。

在发生穿越之后的K线上,我们会持续跟踪移动平均线的最高点。我们使用label.set_y()把标签的位置移动到这个最高价,并把该价格显示在标签内部。这样,我们就能轻松地看出自买入信号出现后,EMA上涨了多少。

该指标的完整代码如下:

//@version=5
indicator(title="更改标签的价格坐标", overlay=true)

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

// 创建持久化变量,用于跟踪标签和EMA最高值
var label maHighLabel = na
var highestMaValue = 0.0

// 当价格向上穿越EMA时,创建一个新的文本标签
if ta.crossover(close, emaValue)
    maHighLabel := label.new(bar_index, high, style=label.style_label_right,
         color=color.new(color.blue, 80))

    // 同时,重置EMA最高值
    highestMaValue := emaValue

// 若未发生穿越,则更新EMA最高值,
// 并将标签移动到该价格
else
    highestMaValue := math.max(highestMaValue, emaValue)

    label.set_y(maHighLabel, highestMaValue)
    label.set_text(maHighLabel, str.tostring(highestMaValue, "0.00"))

我们从indicator()函数开始,配置脚本的各项设置。title为脚本命名;overlay=true使脚本叠加显示在主图表上。

接着,ta.ema()函数计算基于收盘价(close)的20周期EMA。plot()函数则把这条平均线绘制在图表上。由于未指定绘图类型,Pine Script默认绘制常规的线图。这条线以橙色(color.orange)显示,且线宽(linewidth=2)比默认值更粗。

然后,我们创建两个持久化变量。标签变量maHighLabel将用于跟踪标签的标识符。highestMaValue变量则用来记录EMA的最高值。

之后,我们判断价格是否向上穿越了移动平均线:

// 当价格向上穿越EMA时,创建一个新的文本标签
if ta.crossover(close, emaValue)
    maHighLabel := label.new(bar_index, high, style=label.style_label_right,
         color=color.new(color.blue, 80))

    // 同时,重置EMA最高值
    highestMaValue := emaValue

这个if语句使用ta.crossover()函数来判断收盘价是否上穿了EMA。如果上穿,ta.crossover()返回trueif语句内的代码便会执行。这段代码主要做两件事。

首先,Pine Script的label.new()函数创建一个新标签。这个动作在每次价格上穿EMA时都会发生。该标签显示在当前K线的最高价处(由bar_indexhigh确定),其样式为指向右侧的箭头(label.style_label_right)。至于颜色,我们使用color.new()函数把蓝色(color.blue)设置为80%的透明度。

我们把label.new()返回的标识符赋值给maHighLabel变量,以便后续可以继续引用和操作这个标签。

然后,我们把highestMaValue变量的值重置为当前指数移动平均线的值(emaValue)。这确保了每当新的穿越发生时,我们都从当前EMA值开始重新追踪最高点。

指标的最后一部分代码是:

else
    highestMaValue := math.max(highestMaValue, emaValue)

    label.set_y(maHighLabel, highestMaValue)
    label.set_text(maHighLabel, str.tostring(highestMaValue, "0.00"))

这个else代码块是前面if语句的一部分,它会在价格没有向上穿越移动平均线时执行。在这些K线上,我们执行三个操作。

首先,我们使用math.max()函数来追踪EMA的最高值。我们把highestMaValue变量更新为其自身当前值与当前EMA值(emaValue)中的较大者。由于此操作在穿越后的每根K线上都进行,我们便能持续地追踪EMA的最高纪录。

接着,我们调用label.set_y()函数。此举会把最新的标签(其标识符存储在maHighLabel变量中)的位置更新到记录的EMA最高值(highestMaValue)。由于这个位置更新在每根K线上都执行,标签便会随着EMA值的不断升高而向上移动。

最后,label.set_text()函数更新标签的文本。文本内容为EMA的最高值。因为这是一个数值,而标签内容需要是文本格式,所以我们用Pine Script的str.tostring()函数把数字转换为字符串。

在图表上,该指标会在每次价格K线上穿指数移动平均线时绘制一个标签。该标签中的数值以及其在价格轴上的位置,直观地告诉了我们自穿越信号出现后,移动平均线上涨的最高点位:

label.set_y()的特性

Pine Script的标签可以通过label.new()label.set_yloc()函数锚定到价格K线上。锚定后,标签会始终显示在K线上方(使用yloc.abovebar值)或下方(使用yloc.belowbar值)。一旦标签被锚定,即使我们使用label.set_y()更新其价格坐标,它的位置也不会改变。为了能再次改变标签在图表上的位置,我们必须首先调用label.set_yloc()函数并传入yloc.price值。此操作会移除锚定效果,使标签可以再次自由移动。

总结

  • label.set_y()函数用于更新一个标签在价格轴上的坐标。
  • 我们需要告诉该函数两个信息:目标标签的标识符(从label.new()函数获取)和新的Y轴价格值。
  • 由于标签的时间坐标保持不变,label.set_y()的效果是垂直地向上或向下移动标签。
  • 要更改标签的水平位置,应使用label.set_x()label.set_xy()函数。

用label.set_xy()同时更新标签的时间和价格坐标

在我们的Pine Script代码创建标签之后,可以使用label.set_xy()函数来同时更新该标签的价格和时间坐标。

label.set_xy()会根据我们提供给它的坐标,把标签移动到一个新的图表位置。

要完成重新定位,label.set_xy()需要知道三项信息:要修改的是哪个标签、新的时间坐标,以及新的价格坐标。我们来深入探讨。

函数语法格式

该函数的标准语法格式如下:

label.set_xy(id, x, y)
  • id参数用于指定我们想要更改其位置的标签的标识符。Pine Script正是通过这个标识符来识别要修改的具体标签,如果没有它,Pine Script将无从知晓我们想修改哪个标签。这个标识符由label.new()函数在创建标签时返回。如果为该参数传入na值,label.set_xy()将无法更改标签的位置(但好在这种情况下程序并不会抛出错误)。
  • x参数是一个数值,代表标签新的时间坐标。这个坐标可以是K线编号或时间值,具体使用哪种值取决于该标签先前是如何定义的:每个标签在创建时默认使用K线编号,如果我们没有更改过这个设置,或者曾使用xloc.bar_index把标签的坐标类型切换回K线编号,那么该标签就使用K线编号,因此新的时间坐标也必须是K线编号;如果label.new()label.set_xloc()函数早前已把标签的坐标类型设置为xloc.bar_time,那么该标签就使用时间值,此时新的时间坐标也必须是一个时间值。
  • y参数是一个数值,代表标签新的价格坐标。Pine Script会把标签移动到这个新坐标,但有一个例外:如果我们之前已经通过yloc.abovebaryloc.belowbar值把该标签锚定到了价格K线上,那么它将无法被移动到指定的价格坐标。

快速示例

根据标签使用的是K线编号还是时间值,我们使用label.set_xy()的方式会稍有不同。我们分别来看。

先看K线编号。要把标签移动到基于K线编号的图表位置,我们首先需要创建一个标签。这可以通过label.new()函数完成:

// 在当前K线的最高价处放置一个橙色标签
myLabel = label.new(x=bar_index, y=high, color=color.orange,
	 size=size.large)

这段代码在当前K线的最高价(由bar_indexhigh确定)处放置了一个标签。它的颜色是橙色(color.orange),并且尺寸设置为大号(size.large)。

我们没有告知label.new()应该使用K线编号还是时间值,因此标签会采用默认的K线编号作为其时间坐标。

label.new()返回的标识符被我们存入myLabel变量,以便后续通过该变量来访问此标签。

接着,我们使用label.set_xy()来更改标签的位置:

// 将标签的价格更改为当前K线的收盘价,
// 并将其时间坐标向右移动5根K线。
label.set_xy(id=myLabel, x=bar_index + 5, y=close)

在这次label.set_xy()函数调用中,我们指定了三个参数。第一个是myLabel变量,它告诉函数要修改哪个标签。

接下来,我们设置时间坐标。我们用当前K线编号(bar_index)加上5,这会把标签向当前K线右侧移动5根K线。

然后,我们更新价格坐标。这里我们使用当前K线的收盘价(close)。

再看时间值。label.set_xy()也可以把标签移动到一个基于时间值的坐标,这要求该标签当前使用的是时间值(而非K线编号)。

因此,我们先创建一个使用时间值的标签:

// 在当前K线的最高价处绘制一个橙色标签
myLabel = label.new(x=time, y=high, xloc=xloc.bar_time,
	 color=color.orange, size=size.large)

此处的label.new()在当前K线的时间戳和最高价(由timehigh确定)处绘制了一个标签。

xloc=xloc.bar_time参数告知label.new()创建一个基于时间的标签。(若无此参数,标签会默认使用K线编号。)

标签的颜色为橙色(color.orange),尺寸为大号(size.large)。我们把标签标识符存储在myLabel变量中,以备后用。

由于标签现在使用的是时间值,label.set_xy()便可以把其位置更新到一个新的时间点:

// 将标签的价格更新到当前收盘价,并将其
// 时间坐标更改为未来5天后的同一时间。
label.set_xy(id=myLabel, x=time + 5 * 86400000, y=close)

label.set_xy()的第一个参数是myLabel,这样函数就能知道要重新定位哪个标签。

接着,对于标签的新时间坐标,我们取当前K线的时间戳(time),并在此基础上加上5天对应的毫秒数。这会得到一个位于当前K线右侧5天后的时间坐标。

对于标签的价格坐标,我们使用当前K线的收盘价(close)。

图表示例

以上两个示例(无论是基于K线编号还是时间值)所创建的标签,其外观是相同的。

上面的第二个快速示例使用时间值来更改标签位置。我们可以把它的两个代码片段整合为一个完整的Pine Script指标,如下:

//@version=5
indicator(title="label.set_xy() 快速示例", overlay=true)

// 判断脚本是否正在图表的最后一根K线上执行计算
if barstate.islast
    // 在K线的最高价处绘制一个橙色标签
    myLabel = label.new(x=time, y=high, xloc=xloc.bar_time,
         color=color.orange, size=size.large)

    // 将标签的价格更新到当前收盘价,并将其
    // 时间坐标更改为未来5天后的同一时间。
    label.set_xy(id=myLabel, x=time + 5 * 86400000, y=close)

我们从indicator()函数开始配置脚本。title参数为脚本命名,而overlay=true使脚本叠加显示在主图表上。

接着,一个if语句检查脚本是否正在最后一根价格K线上进行计算(barstate.islast)。如果条件为真,Pine Script便会执行我们前面讨论过的代码:label.new()创建一个新标签,随后label.set_xy()更改该标签的价格和时间坐标。

关键字参数

label.set_xy()的关键字参数是可选的。前面的示例中使用它们是为了让代码的意图更加清晰。但一旦我们熟悉了label.set_xy()的工作方式,就可以省略这些关键字以减少一些键盘输入量。

省略idxy关键字后,label.set_xy()的调用方式如下:

// 将标签的价格更改为当前K线的收盘价,
// 并将其时间坐标向右移动5根K线。
label.set_xy(myLabel, bar_index + 5, close)

// 将标签的位置更新到当前收盘价,并将其
// 时间坐标更改为未来5天后的同一时间。
label.set_xy(myLabel, time + 5 * 86400000, close)

label.set_xy()的使用方式

通过label.set_xy(),我们可以把标签向任何方向移动:上、下、左或右。

这个位置不一定需要是全新的。label.set_xy()也可以使用标签已有的价格或时间坐标,这样函数就只会单独更新标签的价格或时间。

我们通常会把label.set_xy()if条件语句结合使用。这样,函数只会在满足特定条件时才被执行,从而移动标签。

有时我们也会在没有任何条件的情况下执行label.set_xy()。其结果是,Pine Script会在每一根K线上都更新标签的位置。这会使得标签随着脚本处理图表时的新K线而持续移动。

如果我们的脚本只需要在创建标签后设置一次其位置,那么直接在label.new()函数中完成会更加方便,所需的代码也比后续再单独调用label.set_xy()要少。

label.set_xy()有两个可替代的函数。label.set_y()仅更改标签的价格坐标,而label.set_x()则仅更新标签的时间坐标。

示例脚本

我们通过一个完整的脚本来实践label.set_xy()的用法。下面的指标会跟踪图表上的历史最高价和历史最低价。

我们把这些极值绘制成一条绿线和一条红线,并用两个标签来显示它们的精确数值。这两个标签我们只创建一次,之后在每根K线上都使用label.set_xy()来更新它们的位置,从而使标签能够从一根K线移动到下一根。

该指标的完整代码如下:

//@version=5
indicator(title="更改标签的价格和时间坐标", overlay=true)

// 创建持久化变量,用于记录图表的历史最高价和最低价
var chartHighPrice = high
var chartLowPrice = low

// 在每根K线上,当出现新的高点或低点时更新变量
chartHighPrice := math.max(chartHighPrice, high)
chartLowPrice  := math.min(chartLowPrice, low)

// 绘制图表的最高价和最低价
plot(chartHighPrice, color=color.green, title="Chart High")
plot(chartLowPrice, color=color.red, title="Chart Low")

// 仅创建一次最高价和最低价标签...
var highPriceLabel = label.new(x=na, y=na, color=color.green,
     textcolor=color.white, style=label.style_label_left)
var lowPriceLabel = label.new(x=na, y=na, color=color.red, 
     textcolor=color.white, style=label.style_label_left)

// ...然后,在每根K线上,将它们更新至当时的图表最高价和最低价。
label.set_xy(highPriceLabel, bar_index, chartHighPrice)
label.set_xy(lowPriceLabel, bar_index, chartLowPrice)

// 使用图表最高价和最低价更新标签的文本
label.set_text(highPriceLabel, "Chart High: " + 
     str.tostring(chartHighPrice))
label.set_text(lowPriceLabel, "Chart Low: " + 
     str.tostring(chartLowPrice))

首先,我们调用indicator()函数,通过title为脚本命名,并通过overlay=true使脚本叠加显示在主图表上。

接着,我们创建两个持久化变量chartHighPricechartLowPrice,分别用于跟踪图表的历史最高价和最低价。它们的初始值被设为第一根K线的高点和低点。

然后,我们在每根K线上更新这两个变量。对于历史最高价变量(chartHighPrice),math.max()函数会比较变量的当前值与当前K线的高点(high),并把较大者作为变量的新值。这样,随着脚本逐根处理图表上的K线,该变量便能持续追踪历史最高价。

我们用类似的方式更新历史最低价变量。math.min()函数会比较变量(chartLowPrice)的当前值与K线的低点(low),并把较小者作为chartLowPrice的新值。由于此操作在第一根K线之后的所有K线上都会执行,该变量便能追踪到图表的历史最低价。

接下来,plot()函数在图表上绘制历史最高价和最低价。由于未设置绘图类型,Pine Script默认绘制常规的线图。这两条线分别以绿色(color.green)和红色(color.red)显示。

然后是处理标签的代码。首先,我们创建两个标签:

// 仅创建一次最高价和最低价标签...
var highPriceLabel = label.new(x=na, y=na, color=color.green,
     textcolor=color.white, style=label.style_label_left)
var lowPriceLabel = label.new(x=na, y=na, color=color.red, 
     textcolor=color.white, style=label.style_label_left)

为了创建最高价标签,我们调用label.new()并传入多个参数。标签的时间和价格坐标暂时设为na。这并非真实的图表坐标,仅作为占位符。这没有问题,因为我们稍后会立即为标签设定一个实际位置。

标签颜色为绿色(color.green),文本颜色为白色(color.white),样式为指向左侧的箭头(label.style_label_left)。我们把label.new()返回的标识符存储在highPriceLabel变量中,以便后续访问。

接着,我们再次调用label.new()创建最低价标签。这个标签以红色(color.red)显示,文字为白色(color.white),同样指向左侧(label.style_label_left)。我们把其标识符存储在lowPriceLabel变量中。

我们使用var关键字来声明这两个标签变量。这能确保Pine Script只创建这些变量一次。并且由于创建变量的同时也调用了label.new(),因此每个标签也只被创建一次。这样做非常高效,因为我们只需要一个最高价和一个最低价标签,而不需要在每根K线上都创建新标签。

接下来,我们更新标签的位置:

// ...然后,在每根K线上,将它们更新至当时的图表最高价和最低价。
label.set_xy(highPriceLabel, bar_index, chartHighPrice)
label.set_xy(lowPriceLabel, bar_index, chartLowPrice)

这里我们调用了两次label.set_xy()。首先更新最高价标签(highPriceLabel),把其新位置设为当前K线编号(bar_index)和截至目前的图表最高价(chartHighPrice)。

我们更新标签位置的方式会产生两个效果。第一,每当脚本处理一根新K线时,标签就会移动到该K线上,从而实现标签从第一根K线到最后一根K线的跟随移动。第二,当我们把标签的价格更新为chartHighPrice变量时,一旦出现新的图表最高价,标签会立即移动到该位置。

第二次label.set_xy()调用则更新最低价标签(lowPriceLabel)。我们把此标签的时间坐标更改为当前K线(bar_index),并把其新价格坐标设为最新的图表最低价(chartLowPrice)。

请注意,指标在每根K线上都会执行这两个label.set_xy()函数,它们并未被置于检查特定条件的if语句中。这是有意为之的,因为标签需要始终更新到最新的数值。

最后要做的是更新标签的文本内容:

// 使用图表最高价和最低价更新标签的文本
label.set_text(highPriceLabel, "Chart High: " + 
     str.tostring(chartHighPrice))
label.set_text(lowPriceLabel, "Chart Low: " + 
     str.tostring(chartLowPrice))

第一个label.set_text()函数调用更改了最高价标签(highPriceLabel)的文本。其新文本由一个字符串字面量与当前图表最高价(通过+连接)组成。由于后者是数值,而标签需要文本,我们使用str.tostring()函数把最高价转换为字符串,使其能用于标签文本。

我们以同样的方式更新最低价标签。调用label.set_text()来修改lowPriceLabel标签的文本,新文本包含当前的图表最低价,同样通过str.tostring()格式化为文本。

在图表上,该指标会显示自图表第一根K线以来的最高价和最低价。请注意,这个输出结果取决于图表上加载的K线数量以及特定交易品种拥有的历史数据量。

label.set_xy()的特性

当一个标签使用K线编号作为其时间坐标时,label.set_xy()无法把标签移动到未来超过500根K线的位置。如果我们尝试把标签移动到当前K线右侧超过500根K线处,TradingView会生成错误:objects positioned using xloc.bar_index cannot be drawn further than 500 bars into the future(使用xloc.bar_index定位的对象不能被绘制到未来超过500根K线的位置)。

如果标签使用K线编号,但我们意外地为label.set_xy()提供了一个时间值,也会发生同样的错误。要解决这个问题,我们应该向label.set_xy()传入一个K线编号。或者,如果确实需要使用时间值,就必须先用label.set_xloc()函数把标签的坐标类型从K线编号切换为时间值模式。

顺便一提,对于历史K线的时间坐标则没有这种限制。label.set_xy()可以使用K线编号或时间值,把标签放置在历史上任何一根K线上。

总结

  • label.set_xy()函数用于同时更新一个标签的价格和时间坐标。
  • 为此,该函数需要三个核心参数:标签的标识符(由label.new()函数返回)、新的时间轴坐标和新的价格轴坐标。
  • 时间坐标可以是K线编号或时间值,具体取决于标签当前的坐标类型。默认是K线编号。如果我们之前对标签使用了xloc.bar_time值,那么它就需要时间值。
  • label.set_xy()在每根K线上执行时,它会使标签跟随新K线移动。如果我们把函数放入if语句中,那么标签的位置就只会在满足特定条件时才更新。
赞(0)
未经允许不得转载:图道交易 » Pine Script(175):更改标签位置,set_x、set_y与set_xy
分享到

评论 抢沙发

登录

找回密码

注册