如何获取趋势线的时间坐标
代码在图表上画出一条趋势线后,我们经常需要处理这条线的坐标。这一节来看看如何获取线条的时间坐标。
line.get_x1()与line.get_x2()
TradingView的指标和策略用line.new()函数创建趋势线。执行该函数时,TradingView会在图表上的两点之间画一条线,每个点都有一个价格坐标和一个时间坐标。
通常,想移动一条线之前,得先知道它当前的位置。Pine Script里有两个函数可以返回线条的时间坐标:
- line.get_x1():返回该线第一个点的时间坐标。
- line.get_x2():返回该线第二个点的时间坐标。
每个函数都需要知道从哪一条趋势线取值,默认语法格式如下:
line.get_x1(id)
line.get_x2(id)
id参数指定要从哪条线获取时间坐标,这里用的值是一个线条引用,也就是创建线条时line.new()返回的值。
line.get_x1()和line.get_x2()都返回整数,但整数的含义取决于线条是怎么定位的:当线条用K线编号放置在图表上时,返回的是绝对的K线编号;当线条用时间值定位时,返回的则是TradingView时间值。
要注意,line.new()创建的趋势线默认使用K线编号。如果你不确定自己的线用的是哪种坐标,那它多半用的是K线编号——只有代码里显式用了xloc.bar_time,线条才会使用时间值。
快速示例
现在实践一下这两个函数。下面的代码片段基于线条当前的时间坐标,把整条线向左移动10根K线:
// 基于K线编号创建一条新线
myLine = line.new(x1=bar_index[20], y1=close[20],
x2=bar_index, y2=close, width=3)
// ...
// 将整条线向左移动10根K线
line.set_x1(id=myLine, x=line.get_x1(id=myLine) - 10)
line.set_x2(id=myLine, x=line.get_x2(id=myLine) - 10)
这里我们先用line.new()画一条趋势线,连接20根K线前的收盘价和当前K线的收盘价,返回的线条引用存入myLine变量。
然后用line.set_x1()和line.set_x2()更新该线的时间坐标,用myLine变量告知函数要改哪条线。新的时间坐标基于当前坐标计算:先用line.get_x1()和line.get_x2()取出当前坐标,再减去10,整条线就向左移了10根K线。
当线条使用的是时间值时,过程也非常相似:
// 创建一条使用时间值作为X轴坐标的线
myLine = line.new(x1=time[20], y1=close[20],
x2=time, y2=close, width=3, xloc=xloc.bar_time)
// ...
// 将该线的时间坐标向左移动4小时
// (14,400,000毫秒)
line.set_x1(id=myLine, x=line.get_x1(id=myLine) - 14400000)
line.set_x2(id=myLine, x=line.get_x2(id=myLine) - 14400000)
这段代码同样先用line.new()创建一条连接20根K线前收盘价和当前K线的趋势线。但这次线条用时间值(xloc=xloc.bar_time)作为X轴坐标,我们把坐标设为K线的开盘时间:time[20]和time。返回的引用存入myLine变量。
然后把整条线向过去移动4小时:执行line.set_x1()和line.set_x2(),用myLine指定要改哪条线。新时间坐标同样基于当前位置计算——先用line.get_x1()和line.get_x2()取出当前坐标,再减去1440万毫秒,线就向左移了4小时。
顺便一提,Pine Script并不总是需要关键字参数,示例里写它们只是为了清晰。下面的代码和前一个示例功能完全相同,但省掉了可选的关键字参数:
// 创建一条趋势线
myLine = line.new(time[20], close[20], time, close,
width=3, xloc=xloc.bar_time)
// 更新该线的时间坐标
line.set_x1(myLine, line.get_x1(myLine) - 14400000)
line.set_x2(myLine, line.get_x2(myLine) - 14400000)
示例指标:把高低点线延伸到未来
接下来看一条线的时间坐标在完整脚本中怎么用。下面的示例指标用趋势线显示最近的最高高点和最低低点,这或许能提示短期支撑和阻力的位置。
当市场处于交易时段时,我们把两条线向右延伸3天,展示这些价格区域在未来的位置。这一步就要用line.get_x2()函数获取线条当前的时间坐标。
该示例指标的完整代码如下:
//@version=5
indicator(title="用线条捕捉近期价格", overlay=true)
// 计算近期的高点/低点
hiHighs = ta.highest(high, 10)[1]
loLows = ta.lowest(low, 10)[1]
// 只创建一次两条趋势线
var highLine = line.new(x1=na, y1=na, x2=na, y2=na,
color=color.green, width=3, xloc=xloc.bar_time)
var lowLine = line.new(x1=na, y1=na, x2=na, y2=na,
color=color.red, width=3, xloc=xloc.bar_time)
// 在每根K线上更新线条的位置
line.set_xy1(highLine, x=time[10], y=hiHighs)
line.set_xy2(highLine, x=time, y=hiHighs)
line.set_xy1(lowLine, x=time[10], y=loLows)
line.set_xy2(lowLine, x=time, y=loLows)
// 但在最后一根K线上,如果有实时数据,
// 将两条线额外向未来延伸3天
if barstate.isrealtime
line.set_x2(highLine, x=line.get_x2(id=highLine) +
(3 * 86400000))
line.set_x2(lowLine, x=line.get_x2(id=lowLine) +
(3 * 86400000))
先用indicator()函数设置指标属性,接着计算近期的极值价格:
// 计算近期的高点/低点
hiHighs = ta.highest(high, 10)[1]
loLows = ta.lowest(low, 10)[1]
我们用ta.highest()和ta.lowest()计算最高高点和最低低点,结果存入hiHighs和loLows变量备用。
因为只需要高亮最近的最高高点和最低低点,所以两条趋势线就够了,而且只创建一次:
// 只创建一次两条趋势线
var highLine = line.new(x1=na, y1=na, x2=na, y2=na,
color=color.green, width=3, xloc=xloc.bar_time)
var lowLine = line.new(x1=na, y1=na, x2=na, y2=na,
color=color.red, width=3, xloc=xloc.bar_time)
第一个line.new()调用创建最高高点线。这条绿色(color.green)的线用TradingView时间值(xloc=xloc.bar_time)作为X轴坐标,这样才能把线画到未来。返回的线条引用存入highLine变量,方便之后访问。
第二条语句创建最低低点线,红色(color.red),同样使用时间值,引用存入lowLine变量。
注意两条线的初始坐标都是na。这个缺失值没法把线正确放到图表上,但暂时没关系,因为接下来马上就会把线更新到实际位置:
// 在每根K线上更新线条的位置
line.set_xy1(highLine, x=time[10], y=hiHighs)
line.set_xy2(highLine, x=time, y=hiHighs)
line.set_xy1(lowLine, x=time[10], y=loLows)
line.set_xy2(lowLine, x=time, y=loLows)
先更新最高高点线:调用line.set_xy1()更改该线(highLine)的起点,新坐标是10根K线前(time[10])的当前最高高点(hiHighs);再用line.set_xy2()把终点改到当前K线的时间(time)和同一个最高高点。
最低低点线的处理类似:line.set_xy1()把起点设到10根K线前、当前最低低点(loLows)处,然后把终点改到当前K线和相同的价格。结果就是一条标出最低低点的水平线。
注意我们在每一根K线上都更新线的位置,这样趋势线才能跟着最新的最高高点和最低低点移动。如果只创建一次而不更新,它们就会一直停留在图表的起始位置。
接下来,把线条向未来延伸,观察未来的支撑和阻力:
// 但在最后一根K线上,如果有实时数据,
// 将两条线额外向未来延伸3天
if barstate.isrealtime
line.set_x2(highLine, x=line.get_x2(id=highLine) +
(3 * 86400000))
line.set_x2(lowLine, x=line.get_x2(id=lowLine) +
(3 * 86400000))
这个if语句检查当前K线是否正在接收实时数据。如果是,barstate.isrealtime变量返回true(否则false)。这就实现了市场交易时延伸趋势线、市场关闭时不延伸的效果。
在if代码块内部,第一个line.set_x2()调用更新最高高点线(highLine)终点的时间坐标。新坐标基于当前坐标计算:先用line.get_x2()取出当前坐标,再加上三倍的一日毫秒数,线就向未来延伸了三天。
最低低点线以同样的方式延伸:line.set_x2()更新该线(lowLine)的终点,新时间坐标是line.get_x2()取出的当前坐标加上3个整天的毫秒数,终点被移到图表最后一根K线右侧72小时的位置。
最后看看该指标在图表上的效果。当市场仍在交易时,脚本会把最高高点线和最低低点线向未来延伸数日:

但如果市场关闭,线条则不延伸,只显示10周期的最高高点和最低低点:

两个函数的特性
line.get_x1()和line.get_x2()函数有以下特性:
- 要知道从哪条线取时间坐标,这两个函数都需要一个线条引用。这个值只有一种获得方式:把line.new()的返回值存进变量。没有引用,就取不到线的时间坐标。
- 虽然一条线可以用K线编号或时间值定位,但line.get_x1()和line.get_x2()不会告诉你某条线用的是哪种格式。目前TradingView也没有提供判断坐标类型的函数,不过用一点代码可以自己解决这个问题(后面的章节会讲)。
- 给这两个函数传na值而不是有效的线条引用时,不会产生错误,但它们也取不到时间坐标。所以如果函数似乎不起作用,先检查线条引用是否正确。
- line.new()创建的趋势线无法手动交互,所以这两个函数是查看线条精确时间坐标的唯一方式。
- 无论线条用K线编号还是时间值作为X轴坐标,line.get_x1()和line.get_x2()都返回整数值序列。
总结
线条创建之后,可以用多种方式获取它的数据,其中之一就是通过line.get_x1()和line.get_x2()函数获取X轴(时间)坐标。
line.get_x1()返回线条起点的时间坐标,line.get_x2()则负责线条的终点。这两个函数都需要一个参数:指定从哪条线取时间坐标的线条引用。
虽然它们总是返回整数,但这个值既可能是K线编号,也可能是时间值,具体取决于我们当初是怎么在图表上定位这条线的。
判断趋势线使用K线编号还是时间值
Pine Script可以用两种方式在图表上定位一条趋势线:K线编号或时间值。目前并没有内置函数能直接告诉我们某条线用的是哪种方式,但有时了解这一点很有用——比如要更改一条线的位置时,就得根据它先前使用的坐标类型来决定用K线编号还是时间值。
幸运的是,我们可以自己写这样一个函数。判断规则和标签一样:当一个绘图的时间坐标在0到100万之间时,它使用的是K线编号;超出这个范围时,用的则是时间值。
自定义函数GetLineXloc()
下面的自定义函数可以判断给定的趋势线用哪种类型作X轴坐标。线条使用K线编号时,函数返回xloc.bar_index;使用时间值时,返回xloc.bar_time。代码如下:
// GetLineXloc() 函数用于获取指定趋势线的X轴坐标类型。
// 返回两个可能的常量之一:
// - xloc.bar_index (表示该线使用K线编号作为其坐标)
// - xloc.bar_time (表示该线使用时间值作为其坐标)
// 注意:对于1970年1月1日0:00:00至0:16:40 UTC之间的K线,
// 函数结果可能不准确。
GetLineXloc(lineId) =>
lineLeftCoordinate = math.min(line.get_x1(lineId), line.get_x2(lineId))
lineRightCoordinate = math.max(line.get_x1(lineId), line.get_x2(lineId))
if lineLeftCoordinate >= 0 and lineRightCoordinate <= 1000000
xloc.bar_index
else
xloc.bar_time
GetLineXloc()函数接受一个参数lineId,指定要查询哪条线的X轴定位方式。
函数的代码先取得该线的左、右坐标。因为我们不知道这条线是从左往右画的还是反过来,所以把较小的时间坐标当作左坐标,较大的当作右坐标。
取左坐标时,我们调用line.get_x1()和line.get_x2()得到线条两个端点的时间坐标,然后用math.min()函数返回两者中的较小值,存入lineLeftCoordinate变量。
取右坐标时同样调用line.get_x1()和line.get_x2(),但这次放在math.max()函数里,得到较大的那个值,存入lineRightCoordinate变量。
有了左(最小)和右(最大)时间坐标,就可以判断它们是否落在K线编号的范围内了。
于是,if/else语句检查lineLeftCoordinate是否大于等于(>=)0,并且(and)lineRightCoordinate是否小于等于(<=)100万。两个比较都为true时,if代码块返回xloc.bar_index,说明该线用的是K线编号。
当左坐标小于零或者右坐标大于100万时,else部分运行,返回xloc.bar_time,说明该线用的是时间值。
xloc.bar_index和xloc.bar_time这两个值看起来可能有点抽象,但用起来并不难,只要测试函数返回的是不是这两个值之一即可。假设我们创建了一条趋势线,标识符存在myLine变量里。要检查它是否使用K线编号,就测试自定义函数的返回值是否等于(==)xloc.bar_index:
// 判断线条是否使用K线编号
usesBars = GetLineXloc(myLine) == xloc.bar_index
要验证该线是否使用时间值,则判断函数返回的是不是xloc.bar_time:
// 判断线条是否使用时间值
if GetLineXloc(myLine) == xloc.bar_time
// ...
示例脚本
通过一个完整脚本看看GetLineXloc()如何工作。下面的指标测试一条趋势线用的是K线编号还是时间值:用K线编号就设为实心灰线,用时间值就变成橙色虚线。
该指标的完整代码如下:
//@version=5
indicator(title="判断线是使用K线编号还是时间值", overlay=true)
// GetLineXloc() 函数用于获取指定趋势线的X轴坐标类型。
// 返回两个可能的常量之一:
// - xloc.bar_index (表示该线使用K线编号作为其坐标)
// - xloc.bar_time (表示该线使用时间值作为其坐标)
// 注意:对于1970年1月1日0:00:00至0:16:40 UTC之间的K线,
// 函数结果可能不准确。
GetLineXloc(lineId) =>
lineLeftCoordinate = math.min(line.get_x1(lineId), line.get_x2(lineId))
lineRightCoordinate = math.max(line.get_x1(lineId), line.get_x2(lineId))
if lineLeftCoordinate >= 0 and lineRightCoordinate <= 1000000
xloc.bar_index
else
xloc.bar_time
// 创建一个输入选项以便在K线编号和时间值之间轻松切换
lineCoordinateStyle = input.string("bar numbers",
title="Line Time Coordinate Style",
options=["bar numbers", "time values"])
// 首先,根据输入选项将值转换为线条可以使用的形式
xAxisValue = lineCoordinateStyle == "bar numbers" ? bar_index : time
xAxisStyle = lineCoordinateStyle == "bar numbers" ?
xloc.bar_index : xloc.bar_time
// 在最后一根已确认的历史K线上,创建一个示例趋势线
if barstate.islastconfirmedhistory
// 创建一条新线
myLine = line.new(x1=xAxisValue[50], y1=low[50],
x2=xAxisValue, y2=high, width=6, xloc=xAxisStyle)
// 如果线条使用时间值,则将颜色设为橙色;否则,使用灰色
lineColor = GetLineXloc(myLine) == xloc.bar_time ?
color.orange :
color.gray
line.set_color(id=myLine, color=lineColor)
// 如果线条使用K线编号,则将其设为实线(否则使用虚线样式)
if GetLineXloc(myLine) == xloc.bar_index
line.set_style(id=myLine, style=line.style_solid)
else
line.set_style(id=myLine, style=line.style_dashed)
首先用indicator()函数配置指标设置,为脚本命名并叠加显示在主图表上。然后我们把上面讨论过的GetLineXloc()函数原样放进来。
指标的其余部分做三件事:创建一个输入,画一条趋势线,最后根据该线用K线编号还是时间值来更改它。我们逐一来看。
先创建输入选项:
// 创建一个输入选项以便在K线编号和时间值之间轻松切换
lineCoordinateStyle = input.string("bar numbers",
title="Line Time Coordinate Style",
options=["bar numbers", "time values"])
input.string()函数创建了一个自定义脚本设置,这个字符串输入的默认值是”bar numbers”。title参数为输入命名,名称Line Time Coordinate Style会显示在脚本设置窗口中该输入的前面。options参数给输入加了一个下拉菜单,包含bar numbers和time values两个选项。输入的值存入lineCoordinateStyle变量,供后续代码查询。
创建了输入后,接下来画趋势线:
// 首先,根据输入选项将值转换为线条可以使用的形式
xAxisValue = lineCoordinateStyle == "bar numbers" ? bar_index : time
xAxisStyle = lineCoordinateStyle == "bar numbers" ?
xloc.bar_index : xloc.bar_time
// 在最后一根已确认的历史K线上,创建一个示例趋势线
if barstate.islastconfirmedhistory
// 创建一条新线
myLine = line.new(x1=xAxisValue[50], y1=low[50],
x2=xAxisValue, y2=high, width=6, xloc=xAxisStyle)
这段代码先根据用户的输入确定线条的设置,为此创建了两个变量。
xAxisValue变量持有趋势线的实际时间坐标。它的值取决于对lineCoordinateStyle输入变量的判断:如果等于(==)”bar numbers”,条件运算符(?:)返回当前K线编号(bar_index);否则返回当前K线的时间(time)。
xAxisStyle变量则说明趋势线该用哪种X轴定位方式。同样评估lineCoordinateStyle:设置为使用K线时用xloc.bar_index,否则用xloc.bar_time通过时间值定位。
然后if语句检查barstate.islastconfirmedhistory变量,它只在图表最后一根已确认的历史K线上为true,这样趋势线只会创建一次。
在这根K线上,我们用line.new()画出趋势线,连接50根K线前的低点和当前K线的高点,时间坐标用xAxisValue变量,X轴定位方式则通过xAxisStyle变量配置。line.new()返回的标识符存入myLine变量,方便后续访问。
指标代码的最后一部分,根据线条用K线编号还是时间值来更新它:
// 如果线条使用时间值,则将颜色设为橙色;否则,使用灰色
lineColor = GetLineXloc(myLine) == xloc.bar_time ?
color.orange :
color.gray
line.set_color(id=myLine, color=lineColor)
// 如果线条使用K线编号,则将其设为实线(否则使用虚线样式)
if GetLineXloc(myLine) == xloc.bar_index
line.set_style(id=myLine, style=line.style_solid)
else
line.set_style(id=myLine, style=line.style_dashed)
第一部分更改线条颜色。条件运算符(?:)判断GetLineXloc()对myLine的返回值是否等于(==)xloc.bar_time:为true返回color.orange,否则返回color.gray,结果存入lineColor变量。然后调用line.set_color(),指定修改myLine这条线,颜色用lineColor变量。
接下来更改线条的视觉样式。if/else语句评估GetLineXloc()的返回值是否等于(==)xloc.bar_index:是则调用line.set_style()把myLine变为实线(line.style_solid);如果该线用的是时间值,else代码块执行,同一个函数把线变为虚线(line.style_dashed)。
代码就说到这里,看看脚本在图表上的运行效果。默认设置下指标使用K线编号,趋势线是一条实心灰线:

如果更改输入选项让线条使用时间值,指标会改变线条的颜色和样式,说明代码识别出这条线现在用的是时间值:

替代方法
上面的自定义函数并不是判断线条坐标类型的唯一方式,但它有几个优点:只需一个函数就能测试K线编号和时间值两种情况;而且函数的返回值还能用于其他目的——比如取得一条线的X轴位置类型后,在该线末端创建文本标签时可以直接复用这个值。
当然,我们可能并不需要GetLineXloc()返回的值,下面看两种替代方案。
如果只想知道一条趋势线是否使用K线编号,可以用这个自定义函数:
// LineUsesBarNumbers() 在给定的趋势线为其时间坐标使用
// K线编号 (xloc.bar_index) 时返回true。当该线
// 用时间值定位时返回false。
// (对于1970年1月1日0:00:00至0:16:40 UTC之间的K线,结果可能不准确。)
LineUsesBarNumbers(lineId) =>
lineLeftCoordinate = math.min(line.get_x1(lineId), line.get_x2(lineId))
lineRightCoordinate = math.max(line.get_x1(lineId), line.get_x2(lineId))
lineLeftCoordinate >= 0 and lineRightCoordinate <= 1000000
指定的线使用K线编号时,LineUsesBarNumbers()返回true(使用时间值则返回false)。在脚本中可以这样用:
// 判断 'myLine' 这条线是否使用K线编号
usesBars = LineUsesBarNumbers(myLine) // true 或 false
// 我们也可以像这样使用该函数:
if LineUsesBarNumbers(myLine)
// ...
类似地,想测试一条趋势线是否使用时间值,可以用下面这个自定义函数:
// LineUsesTimeValues() 在给定的趋势线为其时间坐标使用
// 时间值 (xloc.bar_time) 时返回true。当该线
// 用K线编号定位时返回false。
// (对于1970年1月1日0:00:00至0:16:40 UTC之间的K线,结果可能不准确。)
LineUsesTimeValues(lineId) =>
lineLeftCoordinate = math.min(line.get_x1(lineId), line.get_x2(lineId))
lineRightCoordinate = math.max(line.get_x1(lineId), line.get_x2(lineId))
lineLeftCoordinate < 0 or lineRightCoordinate > 1000000
LineUsesTimeValues()在给定的趋势线用时间值作X轴坐标时返回true(改用K线编号则返回false)。用法如下:
// 判断 'myLine' 是否使用时间值
usesTimes = LineUsesTimeValues(myLine) // true 或 false
// 或者作为替代:
if LineUsesTimeValues(myLine)
// ...
总结
要判断一条线用的是K线编号还是时间值,看它的时间轴坐标:坐标在0到100万之间时,该线使用K线编号;否则,它就是用时间值放置在图表上的。


