Pine Script 中的K线状态变量总览
当一个 TradingView 的指标或策略在处理图表时,它会逐一遍历图表上的每一根价格K线。计算从图表的第一根K线开始,然后依次向后,直至最后一根K线。
在这种快速、步进式的分析过程中,脚本会利用价格数据进行计算、绘制图形、生成信号以及在图表上执行交易。
在遍历图表的过程中,脚本会遇到具有不同状态特征的K线。例如,有它开始计算时遇到的第一根K线,也有整个计算过程结束时的最后一根K线。
Pine Script 提供了一些所谓的K线状态变量(bar state variables),这些变量可以告诉我们脚本当前正在处理的这根K线处于何种状态。这些变量及其用途如下 :
| K线状态变量 | 用途 |
|---|---|
barstate.isfirst |
判断是否为图表的第一根K线。 |
barstate.ishistory |
判断是否为历史K线。 |
barstate.isconfirmed |
判断K线是否已经走完(已收盘)。 |
barstate.islast |
判断是否为图表的最后一根K线。 |
barstate.islastconfirmedhistory |
判断是否为图表上最后一根已确认的历史K线。 |
barstate.isnew |
判断是否为一根新生成的K线。 |
barstate.isrealtime |
判断是否为实时K线。 |
下面我们来逐一详细了解这些变量。
barstate.isfirst:判定第一根K线
当我们的 TradingView 指标或策略在图表的第一根K线上进行计算时,barstate.isfirst 变量的值为 true。对于此后的所有K线,该变量的值均为 false。
我们通常会在第一根K线上进行一些初始化操作,为后续K线的计算准备所需数据。例如,我们可以在第一根K线上为一个数组填充初始值。
barstate.ishistory:判定历史K线
当脚本处理的K线是由历史数据构成时,Pine Script 的 barstate.ishistory 变量值为 true。而对于由实时数据构成的K线,该变量的值则为 false。
TradingView 脚本在处理实时数据和历史数据时,其计算方式可以有所不同。因此,如果我们能判断出脚本当前正在使用哪种数据,就能编写出适应性更强的脚本。
barstate.isconfirmed:判定K线已收盘
当一个 TradingView 脚本在已经走完(即已收盘)的价格K线上进行计算时,Pine Script 的 barstate.isconfirmed 变量的值为 true。如果这根K线尚未收盘(仍在接收新的价格更新),那么该变量的值则为 false。
明确一根K线是否收盘,对于处理交易信号至关重要。在一根K线收盘之前,其内部的价格波动可能导致一个已出现的买卖信号最终消失。而一旦K线走完,这个信号就被最终确认下来。
barstate.islast:判定最后一根K线
当脚本处理到图表当前周期中的最后一根K线时,Pine Script 的 barstate.islast 变量的值为 true。对于此前的所有K线,该变量的值均为 false。
如果我们能够判断出脚本已经运行到了最后一根K线,就可以将一些计算量庞大的任务推迟到这根K线上再执行。或者,也可以等到这根K线时,再处理那些只需要执行一次的任务,例如更新一个表格。
barstate.islastconfirmedhistory:判定最后一根历史K线
当一个指标或策略处理到图表上的最后一根历史K线时,Pine Script 的 barstate.islastconfirmedhistory 变量的值为 true。对于其他的历史K线以及所有实时K线,该变量的值均为 false。
最后一根历史K线,是执行那些在脚本计算流程末端只需运行一次的任务的理想位置。这些任务包括计算回测性能指标和处理数组数据等。
barstate.isnew:判定新K线
当脚本处理图表时,它会遍历所有的价格K线。每当它遇到一根尚未处理过的新K线时,Pine Script 的 barstate.isnew 变量的值便为 true。如果脚本已经在这根K线上执行过计算,该变量的值则为 false。
举例来说,通过这个变量我们就能知道,脚本的某次计算是发生在一根已经收盘的K线上,还是发生在一根尚未走完的新K线上。
barstate.isrealtime:判定实时K线
当一个 TradingView 脚本在能够接收实时价格更新的K线上进行计算时,Pine Script 的 barstate.isrealtime 变量的值为 true。如果K线并非由实时数据构成(而是由历史数据构成),那么该变量的值则为 false。
TradingView 脚本在处理实时数据和历史数据时的运行方式可能会有所不同。因此,明确脚本当前使用的是哪种数据,有助于我们为其编写特定的行为逻辑。
barstate.isconfirmed:判断K线是否已收盘
一个 TradingView 的指标或策略会处理图上的所有价格K线。它所遇到的大部分K线都是已经收盘的。但如果市场正在交易中,那么最后一根K线就尚未走完。
通过 barstate.isconfirmed 变量,我们可以判断脚本当前是否正在一根已收盘的价格K线上进行计算 。
该变量会返回以下两个值之一 :
true:当脚本在一根已收盘的价格K线上计算时。这包括所有的历史K线,以及实时K线完成收盘时的那次更新。false:当脚本在一根尚未走完的K线上计算时。这指的是当图表最后一根K线仍在接收实时数据更新的期间。
也就是说,所有的历史K线都是已收盘状态。而实时K线则既可能处于仍在跳动的状态,也可能刚刚收盘。让我们看看 barstate.isconfirmed 在图表上的具体表现。
barstate.isconfirmed 的图表示例
下面的这个迷你指标会为所有已收盘的K线添加一个文本标签:
//@version=5
indicator(title="barstate.isconfirmed example", overlay=true)
// 当K线收盘时,在图表上放置一个标签
if barstate.isconfirmed
label.new(bar_index, low, style=label.style_label_up,
color=color.red, textcolor=color.white,
text="已收盘")
这个指标首先通过 indicator() 函数来配置其属性,例如脚本的名称 (title) 以及是否将脚本叠加到主图上 (overlay=true)。
接着,一个 if 语句用来检查 barstate.isconfirmed 变量。当K线收盘时,该变量会返回 true。
在这种情况下,if 语句块内的代码会调用 label.new() 函数来创建一个文本标签。这会在图上绘制一个红色 (color.red) 背景的标签,上面以白色文字 (color.white) 显示”已收盘”。
这个脚本会用文本标签高亮所有已确认(收盘)的K线:
除了最后一根价格K线外,其他所有K线都已收盘。而最后一根是仍在接收价格更新的实时K线。
当一根实时K线接收到它的最终价格更新时,这根K线也就变为已收盘状态。因此,经过一段时间后,新的实时K线会不断形成(并随后收盘)。这时图表会变为:
如果我们向回滚动图表,会发现并非每根历史K线都有”已收盘”标签。这是因为 TradingView 限制了单个脚本所能创建的标签数量上限。因此不可能为每一根已收盘的K线都附上标签。但它们本质上仍然是已收盘的K线。
barstate.isconfirmed 的实际用途
利用 barstate.isconfirmed,我们可以实现一些实用的功能,包括:
- 在每根K线收盘时,执行一次计算量庞大的任务,例如遍历数组或更新表格。
- 仅当交易信号被一根已收盘的K线最终确认后,才生成视觉信号(例如在图上绘制形状或为背景上色)。
- 仅在K线收盘时触发警报,而不是在K线(及其数据)仍可能发生变化时触发。
- 仅在K线走完后才删除之前的绘图对象,而不是在新绘图有机会保留在图表上之前就删除。
因为 barstate.isconfirmed 在每根K线上只会出现一次 true 的状态,这为我们提供了一个理想的时机,去执行那些我们希望只运行一次的任务。
barstate.isconfirmed 变量的特性
-
与后台数据函数的关系:TradingView 官方建议,不要将
barstate.isconfirmed与后台数据函数(例如request.security()函数)结合使用 。因为barstate.isconfirmed只反映当前图表交易品种的K线状态,而不会考虑通过request.security()请求的其他交易品种的K线状态。这可能导致状态不匹配和不可预知的计算结果。 -
策略中的行为:在策略脚本中,一个订单成交后可能会触发一次额外的脚本计算。尽管这些计算发生在历史K线的内部,但此时的
barstate.isconfirmed值却是true。因此,在历史数据上,我们无法用barstate.isconfirmed来区分K线收盘时的计算和K线内部的计算。 -
与历史操作符的关系:我们可以通过历史操作符(
[])来访问barstate.isconfirmed在前一根K线上的值。但这并非必要,因为前一根K线必然总是一根已收盘的K线。 -
在K线回放中的行为:在使用 TradingView 的K线回放功能时,对于正在被回放的那根K线,
barstate.isconfirmed的值始终为false。当 TradingView 回放完该K线的所有数据后,这根K线才会收盘(此时barstate.isconfirmed变为true),然后回放功能才会切换到下一根K线。
注意事项
barstate.isconfirmed 变量,与其他K线状态变量一样,可能导致脚本在处理实时数据和历史数据时行为不一致。这种情况可能会产生所谓的重绘(repainting)效应。
barstate.isconfirmed 与其他K线状态变量的对比
在其计算过程中,一个 TradingView 脚本还会遇到其他类型的K线,例如第一根K线和最后一根历史K线。那么,barstate.isconfirmed 与其他K线状态变量之间有何关联呢?我们来一探究竟:
-
第一根K线 (
barstate.isfirst) 在第一根K线上,barstate.isconfirmed的值为true。因为第一根K线几乎总是一根已收盘的K线。一个例外是当图表没有历史数据时(例如在 IPO 上市当天),此时第一根K线就是实时K线,那么在该K线上barstate.isconfirmed的值将为false。 -
历史K线 (
barstate.ishistory) 在历史K线上,barstate.isconfirmed的值始终为true。所有历史K线也都是已收盘的K线。 -
最后一根K线 (
barstate.islast) 在最后一根K线上,如果市场已收盘,或者最后一根实时K线刚刚走完,barstate.isconfirmed的值为true。但如果这最后一根K线仍在接收实时价格更新,其值则为false。 -
最后一根历史K线 (
barstate.islastconfirmedhistory) 在最后一根历史K线上,barstate.isconfirmed的值始终为true。因为最后一根历史K线必然是一根已收盘的K线。 -
新K线 (
barstate.isnew) 在一根新K线上,如果这根新K线是历史K线,barstate.isconfirmed的值为true。这是因为在历史数据上,新K线生成和K线收盘的计算是同时发生的。但如果这根新K线是由实时数据构成的,那么barstate.isconfirmed的值为false,因为当这根新K线刚开始时,它尚未收盘。 -
实时K线 (
barstate.isrealtime) 在一根实时K线上,当它接收到收盘(即最后一笔)价格更新时,barstate.isconfirmed的值为true。否则,当这根实时K线尚未收盘时,其值一直为false。
总结
barstate.isconfirmed 变量用于判断脚本当前是否在一根已收盘的价格K线上进行计算。
- 历史K线永远是收盘状态,因此在该类K线上
barstate.isconfirmed的值始终为true。 - 当一根实时K线在收盘前仍在不断接收价格更新时,
barstate.isconfirmed的值为false。 - 当这根实时K线接收到其最后一笔价格更新(即完成收盘)时,
barstate.isconfirmed的值变为true。
barstate.isfirst:判断图表的第一根K线
为了处理图表,一个 TradingView 的指标或策略会计算所有的价格K线。也就是说,它的计算从第一根K线开始,然后依次向后,直至最后一根K线。
通过 barstate.isfirst 变量,我们可以判断脚本当前是否正在图表的第一根K线上进行计算 。
该变量会返回以下两个值之一 :
true:当脚本在图表的第一根K线上计算时。false:当脚本处理其他任何价格K线时。(即第一根K线之后的所有K线。)
让我们看看 barstate.isfirst 在图表上的具体表现。
barstate.isfirst 的图表示例
下面的这个快速指标,会在图表的第一根K线上放置一个文本标签。
//@version=5
indicator(title="barstate.isfirst example", overlay=true)
if barstate.isfirst
label.new(x=bar_index, y=high, color=color.yellow,
size=size.large, text="第一根K线!")
代码首先通过 indicator() 函数来配置指标的属性。这样做可以命名脚本 (title) 并将其叠加到主图的交易品种上 (overlay=true)。
接着,一个 if 语句用来检查 barstate.isfirst 变量。在图表的第一根价格K线上,该变量会返回 true。在任何其他K线上,其值均为 false。
当值为 true 时,if 语句块内的代码便会执行。这段代码会调用 label.new() 函数来创建一个新的文本标签。这个黄色的 (color.yellow) 标签会在图表上显示”第一根K线!”文本。
当我们将此脚本添加到图表时,它会将图表的第一根K线标记出来,就像这样:
任何其他的K线都不会获得这个文本标签。毕竟,第一根K线只有一个。无论市场是开盘还是休市,也无论图表总共有多少根K线,这一点都同样适用。
barstate.isfirst 的实际用途
barstate.isfirst 变量使得一些实用的功能成为可能,包括:
- 在图表的第一根K线上,为数组填充初始值。
- 在图表的第一根K线上,创建表格的单元格。
barstate.isfirst 变量之所以能实现这些任务,得益于它的两个特性:
首先,该变量在脚本的整个计算周期中,只会出现一次 true 的状态。这为我们提供了一个执行一次性任务的绝佳时机。
其次,该变量在脚本计算流程的开端就为 true,因此它能为后续的脚本计算提前准备好所需的数据。
barstate.isfirst 的特性
-
替代方案:
barstate.isfirst的一个替代方案是使用bar_index变量。当该变量的值等于 (==) 0 时,也代表着脚本正在图表的第一根K线上计算。并且这个比较条件也同样只会出现一次true的情况。 -
历史值访问:通过历史操作符(
[]),我们可以访问barstate.isfirst在之前K线上的值。这可以告诉我们之前某根K线是否是图表的第一根K线。 -
与计算周期的关系:
barstate.isfirst在图表的实际的第一根K线上为true。它的值不取决于脚本计算所需的回溯K线数量。因此,如果我们编写一个10周期的移动平均线,barstate.isfirst为true的是图表上编号为1的K线,而不是移动平均线开始绘制的第10根K线。 -
与策略设置的关系:
barstate.isfirst的值不受策略计算设置的影响。无论策略是在K线收盘时计算、在订单成交时计算,还是在每个tick上都计算,barstate.isfirst始终指向图表的第一根K线。
注意事项
barstate.isfirst 变量,与其他K线状态变量一样,可能导致脚本在图表重载后行为发生变化。这种情况可能会产生所谓的重绘(repainting)效应。
barstate.isfirst 与其他K线状态变量的对比
除了图表的第一根K线,Pine Script 还能识别其他类型的K线,例如最后一根K线和实时K线。那么,barstate.isfirst 与其他K线状态变量之间有何关联呢?我们来一探究竟:
-
历史K线 (
barstate.ishistory) 在历史K线上,barstate.isfirst仅在图表的第一根历史K线上为true。对于第一根之后的所有历史K线,barstate.isfirst均为false。 -
已收盘(确认的)K线 (
barstate.isconfirmed) 在一根已收盘的K线上,只有当这根K线同时也是图表的第一根K线时,barstate.isfirst的值才为true。对于所有其他已收盘的K线,其值均为false。 -
最后一根K线 (
barstate.islast) 在最后一根K线上,barstate.isfirst的值几乎总是false。唯一的例外是当某个交易品种只有一个K线数据时(例如 IPO 上市当天),此时第一根和最后一根K线是同一根,两者会同时为true。 -
最后一根历史K线 (
barstate.islastconfirmedhistory) 在最后一根历史K线上,barstate.isfirst的值为false。因为最后一根历史K线几乎永远不可能是第一根。一个理论上的例外是当图表只有一个K线数据且市场已收盘时,在这个罕见的场景下,第一根K线和最后一根历史K线是同一根,两者会同时为true。 -
新K线 (
barstate.isnew) 在一根新K线上,只有当这根新K线是图表的第一根K线时,barstate.isfirst的值才为true。对于图表上所有其他的新K线,其值均为false。 -
实时K线 (
barstate.isrealtime) 在实时K线上,barstate.isfirst的值为false。因为只要一个交易品种存在历史数据,实时K线就永远不可能是第一根K线。只有在图表没有任何历史数据的情况下(例如 IPO 上市时),第一根K线和实时K线才可能是同一根,两者同时为true。
总结
barstate.isfirst 变量用于判断脚本当前是否正在图表的第一根K线上进行计算。
这根K线指的是图表上实际的第一根K线(编号为 #1 的K线),而不是脚本因需要预热数据而开始绘制指标的那根K线。
当脚本处理图表时,在其整个计算过程中,有且仅有一次计算会将 barstate.isfirst 的值视为 true,那就是在图表的第一根K线上进行的那次计算。
barstate.ishistory:判断是否为历史K线
一个在图表上运行的 TradingView 指标或策略,会处理所有的价格K线。它的计算范围从最旧的历史K线,一直覆盖到最新的实时K线。
通过 barstate.ishistory 变量,我们可以判断脚本当前是否正在一根历史K线上进行计算 。
该变量会返回以下两个值之一 :
true:当脚本在一根由历史数据构成的K线上计算时。false:当脚本处理的K线并非由历史数据构成时。(这指的是实时K线,即由传入的实时价格更新所构成的K线。)
注意事项
对于 TradingView 而言,历史K线指的是由历史数据服务器加载而来的K线。当一根实时K线走完并收盘时,它并不会因此转变为一根历史K线。
尽管这根已收盘的K线(相对于图表当前的最后一根K线而言)确实发生在不久的过去,但它是由实时数据而非历史数据构成的。因此,在 barstate.ishistory 变量看来,它并不属于历史K线。
让我们看看 barstate.ishistory 在图表上是如何运作的。
barstate.ishistory 的图表示例
下面的指标会用文本标签高亮显示历史K线:
//@version=5
indicator(title="barstate.ishistory example", overlay=true)
// 当K线为历史K线时,创建一个标签
if barstate.ishistory
label.new(x=bar_index, y=high, color=color.teal,
textcolor=color.white, text="历史K线")
这段代码首先通过 indicator() 函数定义指标的设置。title 用于命名脚本,而 overlay 则将脚本叠加显示在主图的交易品种上。
接着,一个 if 语句检查 barstate.ishistory 变量。该变量在历史价格K线上为 true,在实时K线上则为 false。
当值为 true 时,label.new() 函数便会创建一个文本标签。这个青色 (color.teal) 的标签会在图表上显示历史K线的文本。
当我们将这个指标添加到一个市场已休市的图表上时,它会将所有K线标记为历史K线。(由于 TradingView 限制了单个脚本可创建的标签数量上限,因此并非所有历史K线都会获得标签。但它们本质上仍然都是历史K线。)
如果该交易品种正在交易中,那么在我们刚打开其图表时,所有的K线(除了最后一根)都会被标记为历史K线:
但如果我们保持图表打开一段时间,一些实时K线会收盘,同时新的实时K线会不断出现。然而,那些已经收盘的K线并不会转变为历史K线。
原因在于,这些已收盘的实时K线是由实时数据而非历史数据构成的,因此它们不会被标记为历史K线:
这里还有另一个有趣的现象。如果我们从图表上移除该指标再重新添加回去,那些由实时数据形成的K线依旧不会被视为历史K线。
这是因为这些已收盘的K线是在图表打开期间由实时数据生成的,所以对于脚本而言,它们不具备历史K线的属性。
然而,如果我们关闭浏览器或 TradingView 桌面客户端再重新打开,此时 TradingView 的实时数据缓冲区已被清空,它会从历史数据服务器重新抓取这些K线。这样一来,脚本就会将这些同样的K线识别为历史K线。(并且 barstate.ishistory 在这些K线上的值将为 true。)
barstate.ishistory 的实际用途
barstate.ishistory 变量使得一些实用的功能成为可能,例如:
- 区分信号生成逻辑:只在历史数据上生成信号,而不触发实时信号。或者反过来,当脚本依赖于K线内的计算时(该功能在历史数据上不可用),我们可以在历史数据上屏蔽信号,只在有实时数据时才生成信号。
- 应用不同的参数:为历史K线和实时K线应用不同的信号逻辑与参数。例如,在实时行情中,脚本会随着每一个价格更新而计算,这使得我们可以提交更贴近入场价的止损订单,并且比在历史数据上能做的更早地采取行动。
因为 barstate.ishistory 能够告诉我们脚本当前使用的是哪种数据,所以它的主要目标就是帮助我们区分并分别处理实时行为和历史回测行为。
barstate.ishistory 的特性
-
在实时K线上的首次计算:当一个指标处理完图上所有的历史K线,并首次到达最后一根实时K线时,它会先进行一次历史模式的计算。通过这种方式,它能处理这根实时K线到目前为止已经发生的数据。在这个实时K线上的历史计算期间,
barstate.ishistory的值为true。但这次计算一结束,TradingView 会立刻将该指标切换到实时模式进行计算。因此,当下一次实时更新到来时,barstate.ishistory的值就变为false。(与此同时barstate.isrealtime变量变为true。) -
与策略设置的关系:
barstate.ishistory的值不受策略计算设置的影响。无论策略是在K线收盘时计算、在订单成交后计算,还是在每个tick(价格跳动)上都计算,只要K线是由历史数据构成的,barstate.ishistory的值就始终为true;而当K线是由实时数据构成时,其值则为false。 -
与
barstate.isrealtime的关系:barstate.ishistory与barstate.isrealtime变量的逻辑完全相反。后者用于判断K线是否由实时数据构成。当这两个变量中的一个为true时,另一个必定为false。(它们永远不能同时为true或同时为false。) -
值的更新时机:我们只有在脚本执行计算时,才能观察到
barstate.ishistory值的更新。比方说,我们的策略只在K线收盘时计算(默认行为),而市场正在交易中。在这种情况下,我们必须等到第一根实时K线收盘后,脚本才能知晓它当前处理的是实时数据而非历史数据(也就是说,要等到那时它才知道barstate.ishistory的值变为了false)。 -
历史值访问:通过历史操作符(
[]),我们可以访问barstate.ishistory在之前K线上的值,从而判断之前的某根K线是否由历史数据构成。 -
在K线回放中的行为:在使用 TradingView 的K线回放功能时,
barstate.ishistory变量在整个回放计算期间的值均为false。这表明,在脚本看来,K线回放功能被视为一种实时数据流。
注意事项
barstate.ishistory 变量,与其他K线状态变量一样,可能导致脚本在重载 TradingView 应用后行为发生变化(因为之前由实时数据生成的K线在重载后变成了历史K线)。这种情况可能会产生所谓的重绘(repainting)效应。
barstate.ishistory 与其他K线状态变量的对比
除了历史数据,Pine Script 还能识别K线的其他状态特征,例如我们也可以检查K线是否已收盘或是否为实时K线。那么,barstate.ishistory 与其他K线状态变量之间有何关联呢?让我们逐一来看:
-
第一根K线 (
barstate.isfirst) 在第一根K线上,barstate.ishistory的值为true。因为图表的第一根K线几乎总是历史价格K线。一个例外是当某个交易品种没有历史数据时(例如 IPO 上市首日),此时第一根K线就是实时K线。 -
已收盘(确认的)K线 (
barstate.isconfirmed) 在一根已收盘的K线上,如果这根K线是历史K线,barstate.ishistory的值为true。如果这根已收盘的K线是由传入的实时数据构成的,那么该变量的值为false。 -
最后一根K线 (
barstate.islast) 在最后一根K线上,如果这根K线是图表上最后一根历史K线,barstate.ishistory的值为true。但如果市场正在交易中,那么最后一根K线会接收实时数据,这使得barstate.ishistory在该K线上的值为false。 -
最后一根历史K线 (
barstate.islastconfirmedhistory) 在最后一根历史K线上,barstate.ishistory的值始终为true。这是因为这根K线根据定义就是历史K线(它不可能是实时K线)。 -
新K线 (
barstate.isnew) 在一根新K线上,如果这根新K线是历史K线,barstate.ishistory的值为true。或者,当脚本在最后一根K线上从历史模式切换到实时模式之前进行首次计算时,该值也为true。但如果交易品种正在交易中且一根新的实时K线形成,barstate.ishistory的值则为false。 -
实时K线 (
barstate.isrealtime) 在实时K线上,barstate.ishistory的值始终为false。实时K线和历史K线的定义是互斥的。
总结
barstate.ishistory 变量用于判断脚本当前是否在一根由历史数据创建的K线上进行计算。
- 当我们为一个交易品种打开图表时,所有位于图表上实时K线左侧的K线都是历史K线。在这些K线上,
barstate.ishistory的值为true。 - 在图表打开期间,由传入的实时数据所构成的K线上,
barstate.ishistory的值为false。














