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

Pine Script(131):时段结束后与开始前的K线定位

#Pine Script入门教学

判断交易时段是否刚刚结束

当我们在Pine Script中编写一个自定义时段时,有时我们不仅想知道K线是否在时段内,还想知道时段刚刚结束的那个确切时刻。

例如,在时段结束的那一刻,我们可以利用该时段的数据来绘制枢轴点(pivots);或者当交易品种的隔夜时段开始时提交一个交易;此外,仅仅是高亮显示时段结束后的第一根K线也是一种选择。

这些功能都要求Pine Script知道哪一根价格K线是时段结束后的第一根。让我们看看如何用代码实现这一点。

自定义函数

要判断一个自定义时段是否已经结束,我们首先要确定哪些K线发生在时段内部。然后,我们寻找这样一根K线:它自身不在时段内,而它的前一根K线则在时段内。当这种情况发生时,我们就找到了时段结束后的第一根K线。

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

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

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

在函数内部我们做了两件事。首先,我们判断当前K线是否发生在指定的时段和时区内。这使用了前面判断K线是否落在时段内的相同代码。我们将这个布尔值(真/假)结果存储在 inSess 变量中,当K线在时段内时,该变量为 true,在时段外则为 false

然而,我们感兴趣的是一根特定的K线。所以,代码的第二行用于判断时段是否刚刚结束。这种情况在两个条件都为真时成立:当前K线不在时段内,而前一根K线在时段内。

通过 not inSess,我们判断当前K线是否不在时段内。这对于任何时段外的K线都会返回 true(而对时段内的K线返回 false)。通过 inSess[1] 表达式,我们判断前一根K线是否在时段内。当它在时段内时,返回 true(不在时则返回 false)。

我们用 and 运算符将这两个值结合起来。这使得当当前K线在时段外(即 not inSesstrue)而前一根K线在时段内时(即 inSess[1]true),表达式返回 true。而对于所有其他的价格K线,则返回 false 值。这正是我们想要的结果!

函数特性

该函数有以下这些值得注意的特性:

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

函数范例

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

  • 首先,我们可以调用该函数并将其结果存储在一个变量中供后续使用。比方说,我们想知道脚本是否正在处理一根紧跟在9:30到16:00股市交易时段之后发生的K线。要找出这一点,我们可以这样做:
    // 查看当前K线是否是9:30 - 16:00时段后的第一根
    isAfterSession = IsSessionOver("0930-1600")
    
  • 我们可以在任何Pine Script接受布尔值(真/假)的地方直接使用该自定义函数。假设我们想为纽约(GMT-5)时区9:30到16:00时段结束后的第一根K线背景上色,我们可以这样做:
    // 为纽约时间9:30-16:00时段后的第一根K线高亮背景
    bgcolor(IsSessionOver("0930-1600", "GMT-5") ? color.new(color.teal, 80) : na)
    
  • 而要使用 barcolor() 函数将16:00到9:30隔夜时段结束后的第一根K线标记为绿色,我们可以像这样使用 IsSessionOver()
    // 将16:00-9:30隔夜时段后的第一根K线设为绿色
    sessionOverColour = if IsSessionOver("1600-0930")
        color.green
    barcolor(sessionOverColour)
    

脚本范例

让我们看看一个完整的脚本如何使用 IsSessionOver() 函数。下方的指标会创建两个输入项:一个用于设置时段,另一个用于定义时区。

我们让 IsSessionOver() 寻找该时段结束后的第一根K线。当找到时,脚本会在这根K线上绘制一条垂直线。

该指标的完整代码如下:

//@version=5
indicator(title="First bar after session ends", overlay=true)

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

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

// 检查当前K线是否是时段结束后的第一根
isFirstAfterSession = IsSessionOver(session, timeZone)

// 在时段结束后的K线上创建一条垂直线
if isFirstAfterSession
    line.new(x1=bar_index, y1=high, x2=bar_index, y2=low, 
         extend=extend.both, color=color.purple, width=2)

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

然后我们引入了上面讨论过的 IsSessionOver() 函数。

接下来,我们创建了两个输入项。input.session() 函数创建了一个时段输入,用于指定我们感兴趣的交易时段。input.string() 函数则创建了一个字符串输入,用以定义该时段的时区。

然后,我们判断当前K线是否恰好在指定的时段和时区结束后出现:

// 检查当前K线是否是时段结束后的第一根
isFirstAfterSession = IsSessionOver(session, timeZone)

我们用两个参数来调用 IsSessionOver():第一个 session 是包含我们自定义交易时段的输入变量,另一个 timeZone 则是包含时区信息的输入变量。

当当前K线确实是时段结束后的第一根时,IsSessionOver() 返回 true(否则返回 false)。我们将这个值存储在一个变量中供下一步使用:

// 在时段结束后的K线上创建一条垂直线
if isFirstAfterSession
    line.new(x1=bar_index, y1=high, x2=bar_index, y2=low, 
         extend=extend.both, color=color.purple, width=2)

这个 if 语句判断K线是否是时段结束后的第一根。如果是,line.new() 函数就会创建一条新的趋势线。

这条线会显示在当前K线(bar_index)上,其价格坐标使用该K线的高点(high)和低点(low)。为了使其成为一条完整的垂直线,我们向两个方向延伸该线(extend.both)。其颜色为紫色(color.purple)。

在图表上,该指标将16:00的K线高亮为时段结束后的第一根。这是正确的,因为在一个15分钟的图表上,当16:00的K线开盘时,11:00到16:00的交易时段确实已经结束了:

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

举个例子,假设我们的时段使用的是GMT+3,而图表则设置为了UTC+1。在这种情况下,由于时区偏移,高亮的K线会提早2个小时出现:

总结

  • IsSessionOver() 函数用于判断当前K线是否是特定时区内某个自定义时段结束后的第一根K线。
  • 在那根特定的K线上,该函数返回 true。对于时段外的其他K线以及时段内的K线,该函数都返回 false
  • IsSessionOver() 函数在基于价格的图表(如Renko和Line Break)上无效。
  • 当时段和图表使用不同的时区时,时段结束后的第一根K线看起来可能会出现在错误的时间,但这其实是由时区差异造成的。

找到时段开始前的那根K线

当我们在Pine Script中编写一个自定义时段时,有时我们不仅想知道K线是否在时段内,还想知道时段即将开始的那个时刻。这些信息在多种情况下都很有用。

例如,我们可以在时段开始前的一根K线上生成警报,这样警报就会在时段开始时触发。或者,如果一个策略在时段前的一根K线上生成订单,那么该订单将在时段开盘时成交。我们还可能希望高亮显示时段前的K线以进行视觉分析。

这些功能都要求Pine Script能够判断哪一根K线恰好在时段之前。让我们看看如何用代码实现这一点。

自定义函数

在寻找时段前的K线时,有一个小小的障碍。在Pine Script中,我们无法从下一根K线获取数据。因此,代码无法询问下一根K线它是否处于时段内。我们必须等到脚本运行到那根K线时才能知道。

幸运的是,我们可以创建一个变通方案。那就是,等到图表上第一个交易时段的开始。然后,在该时段的第一根K线上,我们收集其前一根K线(即时段开始前的那根K线)的时间戳。

一旦我们知道了引导至交易时段的那根K线所具有的时间,那么对于接下来的交易时段,我们就可以通过寻找具有相同时间戳的K线来找到它。

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

// 当当前K线恰好在指定的时段开始前时,IsBarBeforeSession() 返回 'true',
// 并为给定的时区进行校正。
// 对于时段外的其他K线、时段内的K线,以及当时间周期为日线或更高时,
// 返回 'false'。
IsBarBeforeSession(sessionTime, sessionTimeZone=syminfo.timezone) =>
    var int preSessHour   = na
    var int preSessMinute = na
    var int preSessSecond = na
    inSess = not na(time(timeframe.period, sessionTime, sessionTimeZone))

    if inSess and not inSess[1]
        preSessHour   := hour[1]
        preSessMinute := minute[1]
        preSessSecond := second[1]

    hour == preSessHour and minute == preSessMinute and second == preSessSecond

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

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

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

接下来,一个 if 语句判断时段是否刚刚开始。这种情况在 inSesstrue 而其前一根K线的值(inSess[1])为 false 时成立。当这两个条件都满足时,我们就找到了时段的第一根K线。

在该第一根K线上,我们收集引导至该时段的那根K线的时间戳,也就是前一根K线的数据。所以我们更新 preSessHourpreSessMinutepreSessSecond 变量为那根前一根K线的时间。收集了这些值之后,下一次当脚本遇到具有该时间的K线时,我们就知道它就是紧挨着时段开始前的那一根。

这个比较正是该函数的最后一条语句所做的。这里的代码会判断当前K线的小时、分钟和秒时间是否与我们之前收集的值相匹配。如果匹配,脚本正在处理的就是引导至时段的那根K线,因此函数返回 true。对于时间不匹配的所有其他K线,函数返回 false

函数特性

该自定义函数有以下几个值得注意的特性:

  • 该函数要求图表的K线使用一个恒定的时间间隔。但在基于价格的图表(如Point & Figure和Renko)上,每根K线的持续时间都不同,这种情况不成立。在那些图表上,该函数不能可靠地找到时段开始前的K线。
  • 当自定义时段覆盖了图表上的所有K线时,该函数无法判断哪根K线是引导至该时段的(因为没有时段外的K线)。
  • 该函数假设交易品种的交易时间保持不变,因为它使用今天的时段开始时间来推断明天时段开始前的那根K线的时间。当交易品种的交易时间不同时(例如由于假日、数据问题或交易所中断),该函数的结果在第二天就不可靠了。
  • 如果设置的时段没有出现在图表上,该函数也会失败。当设置的时段完全发生在交易品种的隔夜时间段内时,这种情况可能发生。
  • 我们必须在每一根K线上都调用该函数。因为它需要比较当前K线和前一根K线,如果这个比较错过了K线,其结果将不可靠。
  • 该函数在日线和更高的时间周期上总是返回 false,因为这些图表上的K线没有具体的时段信息。

函数范例

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

  • 首先,我们可以调用该函数并将其布尔值(真/假)结果存储在一个变量中供后续使用。比方说,我们想知道当前K线是否发生在9:00到17:30股市时段之前。为此,我们可以这样使用该函数:
    // 查看K线是否恰好在9:00-17:30交易时段开始前发生
    beforeSessionStart = IsBarBeforeSession("0900-1730")
    
  • 创建一个这样的布尔变量很方便,但并非必要。我们可以在任何Pine Script能处理布尔值的地方直接使用该函数。
  • 假设我们想为GMT+4时区9:00-17:30时段之前的K线上色,那么我们可以这样做:
    // 将9:00-17:30 (GMT+4) 时段前的K线设为绿色
    barcolor(IsBarBeforeSession("0900-1730", "GMT+4") ? color.green : na)
    
  • 而要高亮22:00到8:00隔夜时段之前的K线背景,我们可以将 bgcolor() 函数与 IsBarBeforeSession() 函数结合使用,像这样:
    // 在22:00-8:00时段前的K线上创建黄色背景
    bgcolor(IsBarBeforeSession("2200-0800", "GMT-2") ? 
         color.new(color.yellow, 80) : na)
    
  • 另一个选择是在时段前的K线上生成一个市价单。因为策略是在K线收盘时进行计算的,所以该订单会在下一根K线的开盘价成交,而这正是时段的第一根K线。(通过 process_orders_on_close 设置,我们也可以在交易时段前那根K线的收盘时进行交易。) 要在一个8:00-18:00时段前的K线上生成一个入场订单,我们可以这样做:
    // 在时段开始前提交订单(以持仓状态开始时段)
    if close > ta.ema(close, 20) and IsBarBeforeSession("0800-1800")
        strategy.entry("Enter Long", strategy.long)
    

脚本范例

让我们看看一个完整的脚本如何使用 IsBarBeforeSession() 函数。下方的指标会创建两个输入项:一个用于定义交易时段,另一个用于定义该时段的时区。

脚本会寻找紧挨着时段开始前的那根K线。当找到时,它会绘制一条垂直线来高亮显示。

该指标的完整代码如下:

//@version=5
indicator(title="Bar before session starts", overlay=true)

// 当当前K线恰好在指定的时段开始前时,IsBarBeforeSession() 返回 'true',
// 并为给定的时区进行校正。
// 对于时段外的其他K线、时段内的K线,以及当时间周期为日线或更高时,
// 返回 'false'。
IsBarBeforeSession(sessionTime, sessionTimeZone=syminfo.timezone) =>
    var int preSessHour   = na
    var int preSessMinute = na
    var int preSessSecond = na
    inSess = not na(time(timeframe.period, sessionTime, sessionTimeZone))

    if inSess and not inSess[1]
        preSessHour   := hour[1]
        preSessMinute := minute[1]
        preSessSecond := second[1]

    hour == preSessHour and minute == preSessMinute and second == preSessSecond

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

// 检查当前K线是否在时段开始前发生
isBeforeSession = IsBarBeforeSession(session, timeZone)

// 在时段开始前的K线上创建一条垂直趋势线
if isBeforeSession
    line.new(x1=bar_index, y1=high, x2=bar_index, y2=low, 
         extend=extend.both, color=color.black, width=2)

我们通过 indicator() 函数来配置该指标,title 用于命名脚本,overlay 则使其显示在主图的交易品种之上。

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

接下来,我们创建了两个输入项。第一个是时段输入,由 input.session() 函数创建,用于定义自定义时段的交易时间,默认值为8:00到12:00。另一个输入是字符串输入,由 input.string() 函数创建,它指定了时段的时区(初始值为GMT)。我们使用 sessiontimeZone 变量来追踪这两个输入的值。

然后,我们寻找恰好在时段开始前的那根K线:

// 检查当前K线是否在时段开始前发生
isBeforeSession = IsBarBeforeSession(session, timeZone)

这里的 IsBarBeforeSession() 函数用于找到时段前的那根K线。我们向其传递两个参数:第一个 session 是时段输入项的值,另一个 timeZone 则是时区字符串输入的值。

如果K线确实是时段前的那一根,IsBarBeforeSession() 函数返回 true,否则返回 false。我们将这个布尔值存入 isBeforeSession 变量。

然后,我们利用这个变量来高亮显示时段前的K线:

// 在时段开始前的K线上创建一条垂直趋势线
if isBeforeSession
    line.new(x1=bar_index, y1=high, x2=bar_index, y2=low, 
         extend=extend.both, color=color.black, width=2)

这个 if 语句检查 isBeforeSession 变量是否为 true。如果是,line.new() 函数就会创建一条新的趋势线。

我们将这条线绘制在当前K线(bar_index)上,介于该K线的高点(high)和低点(low)之间,这会创建一个小的垂直线段。然而,通过 extend.both 参数,这条线会向两个方向无限延伸。color.black 使这条线显示为黑色。

让我们看看该指标在图表上的效果。使用默认输入,它在7:30的K线上绘制了一条线,因为在一个30分钟的时间周期上,这根K线恰好发生在8:00-12:00时段之前:

被高亮的K线的时间戳并不总是与我们的时段时间相匹配。当图表和时段使用不同的时区时,就会出现差异。

比方说,图表使用的是UTC时区,而时段使用的是GMT+9。对于一个8:00到12:00的时段,在一个30分钟的图表上被高亮的是22:30的K线。这是由图表和时段之间9小时的时差引起的:

总结

  • IsBarBeforeSession() 函数可以判断一根价格K线是否恰好在一个特定时区内的自定义时段开始之前发生。
  • 当脚本处理该K线时,函数返回 true。对于时段外的其他K线以及时段内的K线,该函数都返回 false
  • IsBarBeforeSession() 在基于价格的图表(如Renko和Line Break)上无效。
  • 当图表和时段使用不同的时区时,该函数可能看起来定位了错误的K线,但这实际上是由时区差异造成的。
赞(0)
未经允许不得转载:图道交易 » Pine Script(131):时段结束后与开始前的K线定位
分享到

评论 抢沙发

登录

找回密码

注册