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

Pine Script(130):找出交易时段的第一根与最后一根K线

#Pine Script入门教学

判断K线是否是时段的第一根

我们时常需要让脚本知道,当前的K线是否标志着该时段的开始。利用这些信息,我们可以实现例如仅在特定时间段内进行交易,或将警报限制在某个交易时段内等功能。

但要实现这些,Pine Script需要知道哪一根K线是时段的第一根。让我们看看如何用代码实现这一点。

自定义函数

要判断一根K线是否是某个时段的第一根,我们首先要弄清楚该时段在哪些K线上是活跃的。然后我们检查当前K线是否处于该时段内,而前一根K线则不在。只有在时段的第一根K线上,这种比较才会成立。

以下是如何在一个自定义的Pine Script函数中实现这个想法:

// 当当前K线是指定时段内的第一根时,IsSessionStart() 返回 'true',
// 并为给定的时区进行校正(可选)。
// 对于时段内的其他K线、时段外的K线,以及当时间周期为1天或更高时,
// 返回 'false'。
IsSessionStart(sessionTime, sessionTimeZone=syminfo.timezone) =>
    inSess = not na(time(timeframe.period, sessionTime, sessionTimeZone))
    inSess and not inSess[1]

这个 IsSessionStart() 函数有两个参数。sessionTime 是一个用于指定自定义交易时段的时段字符串sessionTimeZone 是一个用于设定该时段时区的时区字符串。如果我们不设置后者,该函数会默认使用交易品种的时区(syminfo.timezone)。

我们在函数内部做了两件事。首先,我们判断当前K线是否发生在指定时段和给定时区内。这个方法与上一节中的方法相同。我们将这个真/假结果存入 inSess 变量中,当K线在时段内时,该变量为 true,在时段外则为 false

另一项任务是判断当前K线是否是时段的第一根。为此,我们评估当前K线是否在时段内,同时前一根K线是否不在时段内。这意味着 inSess 应该为 true,同时,该变量在前一根K线上的值应为 false。实现该逻辑的代码是 inSess and not inSess[1]。这会在时段的第一根K线上返回 true(而在任何其他K线上返回 false)。

函数特性

该函数有几个值得了解的特性:

  • 当自定义时段覆盖了图表上的所有K线时,代码无法分辨哪根K线是第一根(因为每根K线都在时段内)。
  • 我们必须在每一根K线上都调用该函数。因为它比较当前和前一根K线,如果跳过K线,它将无法正确计算。
  • 该函数可能找不到时段的第一根K线。当设置的时段发生在交易品种的隔夜时间段时(例如由于时区差异),这种情况就会出现。
  • 该函数在日线和更高的时间周期上总是返回 false,因为这些时间周期的K线没有具体的时段信息。

函数范例

把上述函数加入脚本后,我们可以通过多种方式来使用它。

首先,我们可以调用该函数并将结果存储在一个变量中供后续使用。比方说,我们想知道当前K线是否是9:30到16:00时段的第一根。在这种情况下,我们可以这样做:

// 检查当前K线是否是9:30-16:00时段内的第一根
isFirstBarOfSession = IsSessionStart("0930-1600")

当然,我们也可以在任何允许使用布尔值(真/假)的地方直接使用这个自定义函数。让我们假设我们想为纽约(GMT-5)时区9:30到16:00时段的第一根K线背景上色。要实现这种情况,我们可以这样做:

// 为9:30-16:00时段的第一根K线的背景涂上蓝色
bgcolor(IsSessionStart("0930-1600", "GMT-5") ? color.new(color.blue, 80) : na)

而要使用 barcolor() 函数将隔夜17:00到4:00时段的第一根价格K线标记为黑色,我们可以这样做:

// 使17:00到4:00时段的第一根K线变为黑色
priceBarColour = if IsSessionStart("1700-0400")
	color.black
barcolor(priceBarColour)

脚本范例

让我们让一个完整的脚本来使用这个自定义的 IsSessionStart() 函数。下面的指标会创建两个输入项:一个用于设置时段,另一个用于定义时区。

然后,脚本会寻找该时段的第一根K线。当找到时,它会在图表上放置一个时钟表情符号来高亮显示这第一根K线。

该指标的完整代码如下:

//@version=5
indicator(title="Start of session example", overlay=true)

// 当当前K线是指定时段内的第一根时,IsSessionStart() 返回 'true',
// 并为给定的时区进行校正(可选)。
// 对于时段内的其他K线、时段外的K线,以及当时间周期为1天或更高时,
// 返回 'false'。
IsSessionStart(sessionTime, sessionTimeZone=syminfo.timezone) =>
    inSess = not na(time(timeframe.period, sessionTime, sessionTimeZone))
    inSess and not inSess[1]

// 创建输入项
session  = input.session("0800-2200", title="Session")
timeZone = input.string("GMT-8", title="Time Zone")

// 验证K线是否为指定时段内的第一根
isFirstOfSession = IsSessionStart(session, timeZone)

// 用一个字符高亮时段的第一根K线
plotchar(isFirstOfSession, char='⏰', size=size.small)

我们以 indicator() 函数开始,它用于命名该脚本并将其放置在主图的交易品种之上。

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

接下来,我们创建了两个输入项。一个是由 input.session() 函数创建的时段输入,它用于设置我们希望从中找到第一根K线的交易时段。另一个输入是使用 input.string() 函数创建的字符串输入,它用于定义该时段的时区。我们分别使用 sessiontimeZone 变量来追踪这两个输入的值。

之后,我们便可以找出当前K线是否是该时段的第一根:

// 验证K线是否为指定时段内的第一根
isFirstOfSession = IsSessionStart(session, timeZone)

这段代码用两个参数来调用 IsSessionStart() 函数。第一个参数 session 是‘Session’输入项的变量。另一个参数 timeZone 则持有着‘Time Zone’输入项的当前值。我们将 IsSessionStart() 返回的布尔值(真/假)存入 isFirstOfSession 变量中。

我们接下来在绘图时使用这个变量:

// 用一个字符高亮时段的第一根K线
plotchar(isFirstOfSession, char='⏰', size=size.small)

这里的 plotchar() 函数在图表上创建一个绘制的字符。绘图的条件是 isFirstOfSession 变量。至于绘制的字符,我们使用了一个经典的(模拟)闹钟表情符号。

在图表上,该范例指标的效果如下:

这里,脚本高亮了8:00的K线,在小时图上,这确实是8:00到22:00时段的第一根K线。

被高亮的K线的时间戳并不总是与时段的开始时间相匹配。当图表和时段使用不同的时区时,就会发生这种情况。

举个例子,假设时段使用的是GMT-3,而图表使用的是UTC-5。这会导致绘制的字符比K线的时间戳早出现2个小时。因此,对于8:00-22:00的时段,这个时区差异会使得时段从6:00的K线开始,而不是8:00的K线:

判断K线是否是时段的最后一根

当我们在Pine Script中编写一个自定义时段时,有时我们希望知道当前的K线是否是该时段的最后一根。这些信息在多种情况下都很有用。

例如,我们可以在时段结束前平掉持仓、收集时段的收盘价,或者仅仅是在图表上高亮显示时段的结束。

但要实现这些,Pine Script需要知道哪一根K线是时段的最后一根。让我们看看如何用代码实现这一点。

自定义函数

在寻找一个时段的最后一根K线时,有一个小小的障碍。在Pine Script中,我们无法从下一根K线获取数据。所以我们无法制定一个规则说,“如果时段在下一根K线上结束,那么当前K线就是时段的最后一根”。

但我们可以实现一个变通方案。那就是,等到图表上出现一个完整的交易时段。然后在图表上第一个交易时段结束后的那一根K线上,我们收集其前一根K线的时间戳。这会告诉我们该时段的最后一根K线所具有的时间。

然后,我们就可以在第二个及后续的时段中寻找最后一根K线了。当这些时段中的某一根K线与我们之前记录的时间戳相匹配时,它就是该时段的最后一根K线。

以下是如何在Pine Script中编写这种方法的代码:

// IsLastBarSession() 当当前K线是指定时段的最后一根时返回 'true',
// 并为给定的时区进行校正(可选)。
// 对于时段内的其他K线、时段后的K线,以及当时间周期为
// 天或更高时,返回 'false'。
IsLastBarSession(sessionTime, sessionTimeZone=syminfo.timezone) =>
    var int lastBarHour   = na
    var int lastBarMinute = na
    var int lastBarSecond = na
    inSess = not na(time(timeframe.period, sessionTime, sessionTimeZone))

    if not inSess and inSess[1]
        lastBarHour   := hour[1]
        lastBarMinute := minute[1]
        lastBarSecond := second[1]

    hour == lastBarHour and minute == lastBarMinute and second == lastBarSecond

这个自定义的 IsLastBarSession() 函数有两个参数。第一个 sessionTime 是一个用于定义交易时段的时段字符串。另一个 sessionTimeZone 是一个用于指定该时段时区的时区字符串。如果我们不提供后者,该函数会默认使用交易品种的时区(syminfo.timezone)。

在函数内部,我们做了几件事。首先,我们创建了三个持久性变量(var)。它们将用于保存在历史上作为时段最后一根K线的时间戳。它们以空值 (na) 开始。(如果我们使用默认的0,我们可能会在图表开始时意外地捕获到0:00:00的K线。)

然后,我们判断当前K线是否发生在指定的时段和时区内。这使用了前面判断K线是否落在时段内的相同方法。我们将测试结果存储在 inSess 变量中,当K线在时段内时,该变量为 true,在时段外则为 false

然而,我们并非对任何K线都感兴趣,我们想找到的是时段的最后一根K线。所以,一个 if 语句会判断当前K线是否不在时段内(not inSess),而前一根K线时段内(inSess[1])。当这种情况发生时,我们就知道自定义时段刚刚结束了。

如果时段刚刚结束,我们需要获取前一根K线的时间,因为那根K线就是时段的最后一根。所以我们更新 lastBarHourlastBarMinutelastBarSecond 变量为那根前一根K线的时间。收集了这些时间后,在下一个时段中,脚本就可以寻找最后一根时段K线了。

这项任务由函数的最后一条语句完成。该代码会判断当前K线的小时、分钟和秒是否都与我们之前从早期时段的最后一根K线收集到的时间相匹配。当当前K线具有相同的时间时,我们就知道它是时段的最后一根,因此函数返回 true。对于时段内的其他K线,以及时段外的K线,IsLastBarSession() 函数都会返回 false

函数特性

上面的自定义函数有以下这些值得注意的特性:

  • 该函数依赖于前一个时段的K线时间来寻找当前时段的最后一根K线。这在基于时间的图表上有效,但在基于价格的图表(如Renko图和range图)上无效。(在这些图表类型上,目前没有可靠的方案来识别时段的最后一根K线。)
  • 当自定义时段覆盖了图表上的所有K线时,代码无法分辨哪根K线是时段的最后一根。该识别需要至少一根在时段外的K线。
  • 该函数假设交易品种的交易时间保持不变,因为它使用今天的时段结束时间来看第二天的时段何时结束。当交易时间改变时(例如,当有假日或由于数据问题或交易所中断而导致K线缺失时),这个假设便不再成立。
  • 我们必须在每一根K线上都执行该函数。因为它比较当前和前一根K线,如果跳过K线,其结果将不可靠。
  • 该函数可能在图表上的任何地方都找不到时段的最后一根K线。当设置的时段发生在交易品种的隔夜时间段时(例如由于时区差异),这种情况就会出现。
  • 该函数在日线和更高的时间周期上总是返回 false,因为这些时间周期的K线没有具体的时段信息。

函数范例

把上述函数加入脚本后,我们可以通过多种方式来使用它。

  • 首先,我们可以调用该函数并将其布尔值(真/假)结果存储在一个变量中供后续使用。比方说,我们想找出当前K线是否是9:00到17:30时段的最后一根。因此我们编码:
    // 检查当前K线是否是9:00到17:30时段的最后一根
    isSessionLast = IsLastBarSession("0900-1730")
    
  • 我们也可以在任何Pine Script能处理布尔值的地方直接使用该函数。让我们假设我们想为洛杉矶(GMT-8)时区9:00-17:30时段的最后一根K线背景上色。要实现这一点,我们可以这样做:
    // 为9:00 - 17:30 GMT-8时段的最后一根K线设置红色背景
    bgcolor(IsLastBarSession("0900-1730", "GMT-8") ? 
         color.new(color.red, 80) : na)
    
  • 以同样的方式,我们也可以找到一个隔夜时段的最后一根K线。例如,要将18:00到8:00时段的最后一根K线标记为黄色,我们可以将 barcolor() 函数与 IsLastBarSession() 结合使用,像这样:
    // 将18:00 - 8:00时段的最后一根K线涂成黄色
    barcolor(IsLastBarSession("1800-0800", "GMT+2") ? color.yellow : na)
    
  • 我们可能还想在时段的最后一根K线上生成一个平仓订单。这样,当时段结束后的第一根K线开盘时,TradingView就会平掉策略的持仓。或者,如果我们使用 process_orders_on_close 设置,我们就会在时段最后一根K线的确切收盘时刻平仓。 要在一个8:00到22:00时段的最后一根K线上生成一个平仓订单,我们可以这样做:
    // 如果这是8:00-22:00时段的最后一根K线,平掉所有持仓
    if IsLastBarSession("0800-2200")
        strategy.close_all()
    

脚本范例

让我们看看一个完整的脚本如何使用 IsLastBarSession() 函数。下方的指标使用11:00到16:00的时段。我们通过这个自定义函数来寻找该时段的最后一根K线。当找到时,我们将其背景涂成紫红色。

该指标的完整代码如下:

//@version=5
indicator(title="Last bar in session", overlay=true)

// IsLastBarSession() 当当前K线是指定时段的最后一根时返回 'true',
// 并为给定的时区进行校正(可选)。
// 对于时段内的其他K线、时段后的K线,以及当时间周期为
// 天或更高时,返回 'false'。
IsLastBarSession(sessionTime, sessionTimeZone=syminfo.timezone) =>
    var int lastBarHour   = na
    var int lastBarMinute = na
    var int lastBarSecond = na
    inSess = not na(time(timeframe.period, sessionTime, sessionTimeZone))

    if not inSess and inSess[1]
        lastBarHour   := hour[1]
        lastBarMinute := minute[1]
        lastBarSecond := second[1]

    hour == lastBarHour and minute == lastBarMinute and second == lastBarSecond

// 通过输入项来配置时段
session  = input.session("1100-1600", title="Trading Session")
timeZone = input.string("GMT", title="Time Zone")

// 查看当前K线是否是时段的最后一根
lastSessionBar = IsLastBarSession(session, timeZone)

// 用紫红色背景高亮时段的最后一根K线
bgcolor(lastSessionBar ? color.new(color.fuchsia, 80) : na)

首先,我们调用 indicator() 函数,通过 title 命名脚本,并使用 overlay 使其显示在主图的交易品种之上。

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

接下来,我们创建了两个输入项。第一个是使用 input.session() 函数创建的时段输入,其默认值为11:00到16:00的时段。另一个是使用 input.string() 函数创建的字符串输入,它指定了时段的时区,并以 "GMT" 作为其初始值。sessiontimeZone 变量分别追踪这两个输入的当前值。

之后,我们寻找时段内的最后一根K线:

// 查看当前K线是否是时段的最后一根
lastSessionBar = IsLastBarSession(session, timeZone)

// 用紫红色背景高亮时段的最后一根K线
bgcolor(lastSessionBar ? color.new(color.fuchsia, 80) : na)

这段代码首先用两个参数调用 IsLastBarSession() 函数:第一个是时段输入项的变量 session,另一个是包含时区信息的字符串输入 timeZone

当脚本在时段的最后一根K线上进行计算时,IsLastBarSession() 返回 true(而在任何其他K线上返回 false)。我们将这个结果存入 lastSessionBar 变量。

接下来,bgcolor() 函数为图表背景上色,但并非一直如此。它通过一个条件运算符(?:)来评估 lastSessionBar 变量是否为 true。如果是,运算符会返回一个透明的紫红色(color.fuchsia)作为背景色。否则,它会返回 na 值来禁用背景色。最终结果是,时段的最后一根K线会有一个紫红色的背景,而所有其他K线则没有背景。

在下方的图表上,该指标将15:45的K线高亮为时段的最后一根。这是因为,在一个15分钟的图表上,15:45开盘的K线正是11:00到16:00交易时段的最后一根。

被高亮的K线的时间戳并不总是与我们配置的时段相匹配。当图表和时段使用不同的时区时,就会发生这种情况。

比方说,时段使用的是GMT时区,而图表则使用UTC-5时区。这会导致高亮的背景比时段结束时间早5个小时出现。对于一个11:00-16:00的时段,(在15分钟图上)10:45的K线会被标记为时段的最后一根K线:

总结

  • IsLastBarSession() 函数可以判断一根价格K线是否是特定时区内某个自定义时段的最后一根。
  • 当脚本在该最后一根K线上进行计算时,函数返回 true。对于时段内的其他K线以及时段外的K线,它都返回 false
  • IsLastBarSession() 函数在基于价格的图表(如Renko和Line Break)上无效。
  • 当图表和时段使用不同的时区时,看起来函数可能识别了错误的K线,但这其实是由时区偏移引起的。
赞(0)
未经允许不得转载:图道交易 » Pine Script(130):找出交易时段的第一根与最后一根K线
分享到

评论 抢沙发

登录

找回密码

注册