如何更改趋势线的价格坐标
创建一条趋势线后,我们常常还需要更新线条的价格坐标,让它在新的价格K线形成时保持最新。这一节来看看怎么操作。
line.set_y1()与line.set_y2()
TradingView的指标和策略用line.new()函数创建趋势线,执行时会在两点之间画一条线。但线的位置并非一成不变,我们有多种方式修改它,其中一个选项是只更新线的价格坐标——把起点和终点移到不同的Y轴(价格)坐标,X轴(时间)坐标保持原样。Pine Script用以下两个函数完成:
- line.set_y1():更改该趋势线第一个点的价格坐标。
- line.set_y2():调整该线第二个点的价格坐标。
每个函数需要两个参数,默认语法格式如下:
line.set_y1(id, y)
line.set_y2(id, y)
id参数指定要更改哪条线,用的是创建线条时line.new()返回的线条引用;y参数定义新的Y轴(价格)坐标——在主图表的交易品种上画线时,这是一个价格值;如果线画在独立的图表面板里,则是一个脚本计算值。
顺带一提,更改线的位置还有别的方式:调整线的时间坐标、同时更改时间和价格坐标,以及把坐标类型在K线编号和时间值之间切换。
来看看这两个函数的实际用法:
// 创建一条新的趋势线
myLine = line.new(x1=bar_index[10], y1=close[10],
x2=bar_index, y2=close)
// ...
// 更新该线的价格坐标
line.set_y1(id=myLine, y=high[10])
line.set_y2(id=myLine, y=low)
这段代码先用line.new()创建一条趋势线,连接10根K线前的收盘价(bar_index[10]、close[10])和当前K线的收盘价(bar_index、close),返回的线条引用存入myLine变量。
然后更新线的价格。更新第一个点时调用line.set_y1()并传两个参数:第一个指定要改的线(myLine变量),第二个是新的价格坐标(10根K线前的高点)。
更新第二个点则执行line.set_y2():同样先用myLine变量指明哪条线,再给出新的价格坐标,这里用当前K线的低点价格。
顺便一提,TradingView的脚本语言并不总是要求关键字参数,示例里写它们只是为了清晰。省略掉也是完全有效的代码:
// 创建一条新的趋势线
myLine = line.new(bar_index[10], close[10], bar_index, close)
// 更新该线的价格坐标
line.set_y1(myLine, high[10])
line.set_y2(myLine, low)
示例指标:在价格盘整范围放置线条
来看这两个函数在完整脚本中的用法。下面的示例指标寻找价格盘整期,并用趋势线在图表上高亮这些时期。
脚本找到横盘整理的阶段后,会把线条的价格坐标更新到该范围的最高点和最低点,这正是line.set_y1()和line.set_y2()的用武之地。
该指标的完整代码如下:
//@version=5
indicator(title="更新线条价格坐标 - 示例", overlay=true)
// 只创建一次两条趋势线
var highLine = line.new(x1=bar_index[1], y1=high[1],
x2=bar_index, y2=high, color=color.green, width=3)
var lowLine = line.new(x1=bar_index[1], y1=low[1],
x2=bar_index, y2=low, color=color.red, width=3)
// 寻找价格盘整
consolidate = volume < volume[1] and
volume[1] < volume[2] and
ta.tr < ta.tr[1] and
ta.tr[1] < ta.tr[2]
var insideRange = false
// 收集近期的最高高点和最低低点
hiHighs = ta.highest(high, 10)[1]
loLows = ta.lowest(low, 10)[1]
// 当出现价格盘整时,更新
// 线条以捕捉10周期内的价格范围
if consolidate
// 更改高点线的坐标
line.set_y2(highLine, y=hiHighs)
line.set_y1(highLine, y=hiHighs)
line.set_x1(highLine, x=bar_index[10])
line.set_x2(highLine, x=bar_index)
// 更新低点线的坐标
line.set_y1(lowLine, y=loLows)
line.set_y2(lowLine, y=loLows)
line.set_x1(lowLine, x=bar_index[10])
line.set_x2(lowLine, x=bar_index)
insideRange := true
// 获取线条的价格(因为线是水平的,所以可行)
highPrice = line.get_y2(highLine)
lowPrice = line.get_y2(lowLine)
// 当价格保持在盘整范围内时,
// 延伸线条
insideRange := insideRange and
close > lowPrice and
close < highPrice
if insideRange[1]
line.set_x2(highLine, x=bar_index)
line.set_x2(lowLine, x=bar_index)
先从indicator()函数开始,它定义指标的属性。然后创建两条趋势线:
// 只创建一次两条趋势线
var highLine = line.new(x1=bar_index[1], y1=high[1],
x2=bar_index, y2=high, color=color.green, width=3)
var lowLine = line.new(x1=bar_index[1], y1=low[1],
x2=bar_index, y2=low, color=color.red, width=3)
第一条线用line.new()连接前一根K线的高点(bar_index[1]、high[1])和当前K线的高点(bar_index、high),设为绿色(color.green)、3像素粗(width=3),返回的引用存入highLine变量备用。
第二条线连接前一根和当前K线的低点,显示为红色(color.red),粗细相同,引用存入lowLine变量。
这里有两点要注意。第一,两条线的初始坐标只是临时的,找到价格盘整期时会更新它们。第二,两条线都用var语句创建,带var关键字的代码行只执行一次,所以脚本总共只创建两条趋势线,不多不少。这就够了,因为我们总是把这两条线更新到最近的盘整位置。
当然,这要求我们能识别出价格盘整。接下来就写这部分代码:
// 寻找价格盘整
consolidate = volume < volume[1] and
volume[1] < volume[2] and
ta.tr < ta.tr[1] and
ta.tr[1] < ta.tr[2]
var insideRange = false
consolidate变量的值由四个用and连接的条件决定:交易量在当前K线(volume < volume[1])和前一根K线(volume[1] < volume[2])都在下降,同时真实波幅(ta.tr)也连续两根K线下降。四个条件都满足时,consolidate为true。
我们还创建了insideRange变量,默认值为false。这个变量稍后会在if语句里用到,提前在这里创建,是为了在那个if语句结束后仍然能访问它。
然后确定近期的高点和低点:
// 收集近期的最高高点和最低低点
hiHighs = ta.highest(high, 10)[1]
loLows = ta.lowest(low, 10)[1]
用ta.highest()计算近期的最高高点,用ta.lowest()取近期的最低低点,两个函数都基于过去10根K线的数据。结果存入hiHighs和loLows变量,稍后给趋势线用。
接下来判断是否出现了价格盘整:
// 当出现价格盘整时,更新
// 线条以捕捉10周期内的价格范围
if consolidate
// 更改高点线的坐标
line.set_y2(highLine, y=hiHighs)
line.set_y1(highLine, y=hiHighs)
line.set_x1(highLine, x=bar_index[10])
line.set_x2(highLine, x=bar_index)
// 更新低点线的坐标
line.set_y1(lowLine, y=loLows)
line.set_y2(lowLine, y=loLows)
line.set_x1(lowLine, x=bar_index[10])
line.set_x2(lowLine, x=bar_index)
insideRange := true
这个if语句检查consolidate变量。为true时说明一个新的盘整期开始了,趋势线必须更新。
先移动代表盘整高点的线:调用line.set_y1()和line.set_y2()把线移到近期的最高高点,每个函数传两个参数——highLine指明是哪条线,hiHighs设置新的价格坐标。
该线的时间坐标也要更新到近期的盘整周期,所以执行line.set_x1()和line.set_x2():前者把线的起点设到10根K线前(bar_index[10]),后者把终点设为当前K线编号(bar_index)。
低点线以类似方式更改:line.set_y1()和line.set_y2()把价格坐标更新到10周期最低低点,line.set_x1()和line.set_x2()把时间坐标改到10根K线前和当前K线。
我们还把insideRange变量设为true,稍后用它判断价格是否仍在盘整区域内。
到这里,趋势线已经高亮了盘整范围的开始。还差一件事:只要市场保持横盘,就继续延伸趋势线。实现代码如下:
// 获取线条的价格(因为线是水平的,所以可行)
highPrice = line.get_y2(highLine)
lowPrice = line.get_y2(lowLine)
// 当价格保持在盘整范围内时,
// 延伸线条
insideRange := insideRange and
close > lowPrice and
close < highPrice
if insideRange[1]
line.set_x2(highLine, x=bar_index)
line.set_x2(lowLine, x=bar_index)
这段代码做三件事。第一,获取盘整范围的上下边界——因为线是水平的,用line.get_y2()取线条的价格坐标就行,结果存入highPrice和lowPrice变量。
第二,判断价格是否仍在盘整区域内。我们把insideRange变量更新为三个表达式的比较结果:先要求该变量当前值为true,确保只有盘整开始后才继续延伸;再要求K线收盘价高于下趋势线(close > lowPrice),且低于上趋势线(close < highPrice)。三个条件都满足时insideRange为true,否则为false。
第三,实际延伸趋势线。if语句检查insideRange[1]——这里故意用了一根K线的延迟,好让我们能看到价格K线实际突破趋势线的情景。测试为true时,line.set_x2()把高点和低点趋势线的终点更新到当前K线编号(bar_index)。
来看指标在图表上的实际表现。在这个富时100指数CFD图表上,指标在一波显著下跌前片刻捕捉到了一个盘整期:

价格仍在盘整时,指标会持续延伸两条趋势线。这个60分钟的欧元/美元图表就是一个例子:

两个函数的特性
line.set_y1()和line.set_y2()函数有几个值得注意的特性:
- 要知道修改哪条线,两个函数都需要一个线条引用。这个值只有一种获得方式:把line.new()的返回值存入变量。没有引用,就无法更新线的价格。
- 代码创建的线无法手动修改,所以更新线的价格,这两个函数是仅有的选项。
- 用line.get_y1()和line.get_y2()函数获取线的当前价格坐标。
- 给这两个函数传na值而不是有效的线条引用时,脚本不会报错,但价格坐标也不会更新。如果没报错但函数似乎不起作用,先检查用来定位趋势线的值是否有效。
- 这两个都是void函数(无返回值函数),不返回成功或失败的状态。想确认线的价格坐标是否真的改了,用line.get_y1()和line.get_y2()查看。
总结
线出现在图表上之后,我们仍然可以更新它的位置。一个选项是用line.set_y1()和line.set_y2()函数更改线的Y轴(价格)坐标:line.set_y1()改第一个点,line.set_y2()改第二个点。
这两个函数都需要两个参数:第一个是线条引用,告诉函数改哪条线;另一个是新的价格值——它可以来自交易品种的价格图表,如果指标或策略画在独立的图表区域,也可以是自定义的脚本值。
如何把趋势线在K线编号和时间值之间切换
编写一条趋势线时,我们需要指定线的时间坐标,用K线编号或时间值都行。而线创建之后,我们仍然可以更改它使用的坐标类型。这一节来看看怎么操作,以及为什么这样做有用。
line.set_xloc()函数
TradingView的指标和策略用line.new()创建趋势线,创建时要指定价格和时间坐标。时间坐标可以用K线编号或时间值:K线编号用起来简单,时间值则让在未来绘制趋势线成为可能。
有时我们需要更改一条趋势线使用的时间格式,让一条最初用K线编号创建的线改用时间值,或者反过来。line.set_xloc()函数就是干这个的,它需要4个必需参数:
line.set_xloc(id, x1, x2, xloc)
id参数指定要更改哪条线,用的是创建线条时line.new()返回的线条引用。x1参数设置线第一个点的时间轴坐标,x2参数更新第二个点的时间轴坐标,两者用K线编号还是时间值取决于xloc参数。xloc参数定义该线使用哪种X轴坐标,有两个可能的值:xloc.bar_index让趋势线使用K线编号(通过bar_index变量访问);xloc.bar_time让线使用时间值(例如由time和time_close变量返回)。
顺带一提,更改线的位置还有几种其他方式:调整线的价格、更新时间坐标,以及同时更改价格和时间坐标。
那什么时候用line.set_xloc()?执行line.new()创建新线时,我们就能直接指定该线用K线编号(xloc=xloc.bar_index)还是时间值(xloc=xloc.bar_time),90%的情况下这就够了。
但有时一条线需要在两种X轴格式之间切换。比如,先用K线编号在历史K线上定位一条趋势线,进入实时行情后改用时间值,好把趋势线画到未来。想切换一条已存在趋势线的定位方式,就该用line.set_xloc()函数。
快速示例
来看这个函数的用法。假设有一条使用K线编号的线,现在我们想把它移到当前K线的右侧(也就是未来),用line.set_xloc()可以这样实现:
// 创建一条新的趋势线(默认
// 使用 `xloc.bar_index`)
myLine = line.new(x1=bar_index[10], y1=close[10],
x2=bar_index, y2=close)
// ...
// 切换该线以改用时间值
// (使其可以在未来绘制线条)
line.set_xloc(id=myLine, x1=time[25],
x2=time + 86400000, xloc=xloc.bar_time)
这段代码先用line.new()创建一条趋势线,默认使用K线编号作时间坐标,取值用的是bar_index变量,返回的引用存入myLine变量备用。
然后我们想换一种时间坐标类型,于是调用line.set_xloc():用myLine指明目标线条,第一个点的时间坐标设为25根K线前(x1=time[25]),第二个点设为当前K线的开盘时间(time)加86,400,000——这个大数是一天的毫秒数。
所以这段代码把线的第二个点向未来移动了24小时,而xloc=xloc.bar_time把线的坐标类型设成了时间值。
反向操作也可以:把一条线从时间值切换到K线编号。例如:
// 基于K线时间值创建一条新线
myLine = line.new(x1=time[12], y1=high[12],
x2=time, y2=low, xloc=xloc.bar_time)
// ...
// 切换该线以改用K线编号
line.set_xloc(id=myLine, x1=bar_index[30],
x2=bar_index, xloc=xloc.bar_index)
这里先用line.new()创建一条连接12根K线前高点(time[12]、high[12])和当前K线低点(time、low)的趋势线,并设置它使用时间值(xloc=xloc.bar_time)。
然后把它切换成K线编号:执行line.set_xloc(),线的第一个点设为30根K线前(bar_index[30]),第二个时间坐标改成当前K线编号(bar_index)。通过xloc.bar_index,这条线现在用的就是K线编号而不是时间值了。
顺便一提,关键字参数通常是可选的,示例里写它们是为了更清晰。省略后代码更紧凑、输入更快,比如这样也完全有效:
// 创建一条趋势线
myLine = line.new(time[12], high[12], time, low, xloc.bar_time)
// 切换到K线编号
line.set_xloc(myLine, bar_index[30], bar_index, xloc.bar_index)
示例指标:用趋势线高亮月度收盘价
看看line.set_xloc()在完整脚本中如何工作。下面的指标在前一个月的收盘价处画一条水平线,并延伸到当月的每一根K线上,这样就能看到价格与该收盘价的关系。
但在图表的最后一根K线上,我们把这条线向未来延伸5天,方便比较当前价格与上个月的情况。为此,我们用line.set_xloc()把趋势线的坐标类型从K线编号切换为时间值。
该指标的完整代码如下:
//@version=5
indicator(title="月度收盘价趋势线", overlay=true)
// 只创建一次趋势线变量
var line monthClose = na
// 确定自月份开始以来的K线数量
sinceStart = ta.barssince(month != month[1])
// 在每个月开始时创建一条新线
if sinceStart == 0
monthClose := line.new(x1=bar_index[1], y1=close[1],
x2=bar_index, y2=close[1], color=color.orange,
width=2)
// 在每根K线上,将该线延伸一根K线。但在最后一根K线上除外,
// 在那里,将该线向未来延伸5天。
if not barstate.islast
line.set_x2(monthClose, x=bar_index)
else
line.set_xloc(monthClose, x1=time[sinceStart + 1],
x2=time_close + (5 * 86400000), xloc=xloc.bar_time)
先用indicator()函数设置指标属性,然后创建一个趋势线变量:
// 只创建一次趋势线变量
var line monthClose = na
monthClose线变量通过var关键字只创建一次,默认值是na,类似一个缺失值。为什么要费事创建一个空值的变量?因为稍后我们会在if语句里创建趋势线并更新monthClose变量——如果变量在if语句内部才创建,if结束后就无法访问它了,所以选择提前创建。
接着判断新月份是否开始:
// 确定自月份开始以来的K线数量
sinceStart = ta.barssince(month != month[1])
ta.barssince()函数返回自最近一次K线的月份发生变化(month != month[1])以来经过了多少根K线。这个计数存入sinceStart变量,供后续创建和更新线条位置时使用。
接下来创建趋势线:
// 在每个月开始时创建一条新线
if sinceStart == 0
monthClose := line.new(x1=bar_index[1], y1=close[1],
x2=bar_index, y2=close[1], color=color.orange,
width=2)
这个if语句判断sinceStart是否等于(==)零——当前K线是日历月第一根时,该变量就是零。这时我们要在前一个月的收盘价处创建一条新趋势线。
于是执行line.new(),在前一根K线(bar_index[1])和当前K线编号(bar_index)之间画线,价格用前一根K线的收盘价(close[1])。因为这段代码在每月第一根K线上运行,这个前一收盘价正是上个月的收盘价。
线设为橙色(color.orange)、比默认更粗(width=2),line.new()返回的引用存入monthClose变量。
不过这条线相当短,只连接了前后两根K线,所以要延伸它:
// 在每根K线上,将该线延伸一根K线。但在最后一根K线上除外,
// 在那里,将该线向未来延伸5天。
if not barstate.islast
line.set_x2(monthClose, x=bar_index)
else
line.set_xloc(monthClose, x1=time[sinceStart + 1],
x2=time_close + (5 * 86400000), xloc=xloc.bar_time)
这个if/else语句以两种方式延伸线条。当前K线不是图表最后一根时(not barstate.islast),我们更新线第二个点的时间坐标来加长它:调用line.set_x2(),传入要改的线(monthClose)和新的时间坐标(当前K线编号bar_index),让线一根K线一根K线地向右延伸。
else部分则在当前K线是图表最后一根时运行,这时我们要把线延伸到未来。但之前这条线是用K线编号创建的,而用K线编号的线无法把时间坐标设到当前K线之后。
所以需要把坐标类型从K线编号切换为时间值:调用line.set_xloc(),第一个参数是线条引用(monthClose);起始时间坐标用新月份开始那根K线的开盘时间(time[sinceStart + 1],加1是因为barssince()从零开始计数)。
第二个时间坐标则改为当前K线的收盘时间(time_close)加上5倍的一日毫秒数,把线向未来延伸五天。最后通过xloc=xloc.bar_time指定这条线从现在起使用时间值。
这条趋势线在图表上的效果如下:

图上有几条水平线,每一条都放在前一个月的收盘价处,横跨后续整个月的所有K线。当然,最后一条线除外——它向未来延续了数日。
line.set_xloc()的特性
line.set_xloc()函数有几个值得注意的特性:
- 要知道修改哪条线,line.set_xloc()需要一个线条引用。这个值只有一种获得方式:把line.new()的返回值存入变量。没有引用,就无法修改线的时间格式。
- line.set_xloc()可以把趋势线移到未来的位置(当前K线右侧),但这要求使用时间值——K线编号无法实现。
- line.set_xloc()只需执行一次,趋势线在整个生命周期中就会使用指定的时间格式。这也意味着最后一次设置的xloc值才起作用,而不是创建线时设定的那个。
- 目前TradingView没有内置函数判断一条线用的是K线编号还是时间值。不过可以用自定义代码判断,或者用一个自定义变量跟踪该线用的是xloc.bar_index还是xloc.bar_time。
- 给line.set_xloc()传na值而不是有效的线条引用时不会报错,但X轴值也不会更改。如果代码没有任何反应,先检查线条引用是否有效。
- line.new()创建的线无法手动更改,所以line.set_xloc()是把线的坐标类型在K线编号和时间值之间切换的唯一方式。
- line.set_xloc()是void函数(无返回值函数),不返回成功或失败的状态。可以检查线的当前时间坐标来确认位置是否真的改了。
总结
趋势线默认用K线编号作时间坐标,但也可以用时间值——后者能把线放到未来(当前K线的右侧)。
线创建之后,可以用line.set_xloc()函数在K线编号和时间值之间切换。该函数需要四条信息:要更改的趋势线引用;起点和终点的新时间坐标;以及指定用K线编号的xloc.bar_index值,或指定用时间值的xloc.bar_time值。
如果趋势线只需要一种时间格式,创建时通过line.new()的xloc参数配置会更简单。通常只有当同一条线需要先用K线编号、之后转用时间值(或反过来)时,才用line.set_xloc()函数。


