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

Pine Script(220):同时挂出多空停止单与止损限价单

#Pine Script入门教学

同时开设多头和空头的停止入场单

TradingView策略可以使用 strategy.entry() 函数来通过停止单(stop order)开立多头和空头仓位。当我们两次调用这个函数时,就可以同时生成一个多头停止入场单和一个空头停止入场单。

但我们为什么要这么做呢?这种订单组合在交易突破行情时非常有用。假设我们的策略发现了一个价格盘整形态,行情可能向上或向下突破。通过同时设置一个多头和一个空头的停止入场单,一旦价格发生突破,策略就能自动在突破的方向上开仓。并且,如果我们使用一个订单关联组(order group),TradingView会在其中一个订单成交后,自动取消另一个尚未成交的订单。

要实现同时生成多空停止入场单,需要三步。第一步是执行 strategy.entry() 函数两次,分别发送一个多头停止单和一个空头停止单,每次调用都需要提供五个关键信息:

  • 订单ID(id):为停止单指定一个唯一的名称。
  • 交易方向:多头停止单使用 strategy.long,空头停止单使用 strategy.short
  • 停止价格(stop):通过 stop 参数设置具体的触发价位(注意:是绝对价格,不是价差)。
  • 订单组名称(oca_name):为两个订单设置相同的组名称,这样PineScript就知道它们是关联的。
  • 订单组类型(oca_type):设为OCA(One-Cancels-All)组(strategy.oca.cancel),这样当一个订单成交时,TradingView会自动取消同组的另一个订单。

第二步是将两个 strategy.entry() 调用放入一个 if 语句中,用 if 的条件控制这两个订单的生成时机,确保它们只在满足特定条件时才被挂出。第三步是在不再需要时取消这两个停止单——当市场出现某些情况,使得我们最初的交易设定失效时,我们就应该主动撤销这两个挂单,避免它们在不合时宜的时候被触发,可以使用 strategy.cancel()strategy.cancel_all() 函数来完成撤单。

接下来,让我们看看这些要求如何转化为PineScript代码。

多空停止单

要生成一个多头和一个空头的停止单,我们需要调用 strategy.entry() 两次,并为每次调用都提供订单ID、方向、停止价格以及订单组的配置。对于多头入场单,代码如下:

// 在当前K线收盘价上方20个最小变动单位处,提交一个多头停止入场单
strategy.entry("Enter Long", strategy.long, stop=close + 20 * syminfo.mintick,
	 oca_type=strategy.oca.cancel, oca_name="stop-entries")

这里,我们使用了 strategy.entry() 的五个关键参数:订单ID为 "Enter Long",方向为 strategy.long,触发价格 stop 设在收盘价上方20个最小变动单位处。oca_type 设为 strategy.oca.cancel 将其定义为OCA组的一员,oca_name 则为该组命名为 "stop-entries"

对于空头入场停止单,代码类似:

// 在当前K线收盘价下方20个最小变动单位处,提交一个空头停止入场单
strategy.entry("Enter Short", strategy.short, stop=close - 20 * syminfo.mintick,
	 oca_type=strategy.oca.cancel, oca_name="stop-entries")

空头单的ID为 "Enter Short",方向为 strategy.short,触发价格设在收盘价下方。最关键的是,它的 oca_name 与多头单完全相同("stop-entries"),这样它们就被关联在了同一个OCA组中。

上面的代码片段缺少了一个关键环节:何时生成这两个订单。按照现在的写法,它们会在每根K线上都执行。我们应该用一个 if 语句来设定挂单的条件:

// 当9周期RSI穿越50中轴时,同时提交一个买入停止单和一个卖出停止单
// 它们都距离当前收盘价20个最小变动单位
if ta.cross(ta.rsi(close, 9), 50)
	strategy.entry("Enter Long", strategy.long, stop=close + 20 * syminfo.mintick, oca_type=strategy.oca.cancel, oca_name="stop-entries")
	strategy.entry("Enter Short", strategy.short, stop=close - 20 * syminfo.mintick, oca_type=strategy.oca.cancel, oca_name="stop-entries")

这个 if 语句使用 ta.cross() 函数来判断RSI是否穿越了50。只有当条件成立时,内部的两个 strategy.entry() 函数才会被执行,从而同时挂出多头和空头的停止单。

请注意:停止单的触发价格是在 if 条件成立的那一刻确定的,它会记住当时的 close 价。之后,即使新的K线有不同的收盘价,这两个已挂出的停止单价格不会自动更新。

最后一步是决定何时撤销这两个挂单。如果原始的交易设定已经失效,我们就应该撤销它们,以防被意外触发:

// 当RSI进入超买区(>80)或超卖区(<20)时,
// 撤销这两个尚未成交的停止挂单
if ta.crossover(ta.rsi(close, 9), 80) or ta.crossunder(ta.rsi(close, 9), 20)
	strategy.cancel("Enter Long")
	strategy.cancel("Enter Short")

这个 if 语句判断RSI是否进入了极端区域。如果进入,我们认为突破的良机已失,便调用 strategy.cancel() 按名称分别撤销 "Enter Long""Enter Short" 这两个挂单。

如果除了这两个单子外没有其他挂单,我们也可以直接用 strategy.cancel_all() 来清扫所有挂单:

// 当RSI进入超买区(>80)或超卖区(<20)时,撤销所有挂单
if ta.crossover(ta.rsi(close, 9), 80) or ta.crossunder(ta.rsi(close, 9), 20)
	strategy.cancel_all()

回顾一下,生成和撤销这一对多空停止单的完整逻辑块如下:

// 当RSI穿越50时,挂出多空停止单
if ta.cross(ta.rsi(close, 9), 50)
	strategy.entry("Enter Long", long, stop=close + 20 * syminfo.mintick, 
        oca_type=strategy.oca.cancel, oca_name="stop-entries")
	strategy.entry("Enter Short", short, stop=close - 20 * syminfo.mintick, 
        oca_type=strategy.oca.cancel, oca_name="stop-entries")

// 当RSI进入极端区域时,撤销挂单
if ta.crossover(ta.rsi(close, 9), 80) or ta.crossunder(ta.rsi(close, 9), 20)
	strategy.cancel("Enter Long")
	strategy.cancel("Enter Short")

示例策略

让我们通过一个完整的策略来看看如何同时提交多空停止入场单。下面的脚本基于价格与40周期简单移动平均线(SMA)的交叉进行交易。

当交叉发生时,策略在价格上方3%处提交一个多头停止单,在价格下方3%处提交一个空头停止单,形成一个价格通道,试图捕捉交叉后可能出现的动能。如果挂单在交叉发生后的5根K线内仍未成交,我们就将它们全部撤销,等待下一次交叉机会。

策略的完整代码如下:

//@version=5
strategy(title="多空停止单入场", overlay=true)

// 计算并绘制移动平均线
smaValue = ta.sma(close, 40)
plot(smaValue, color=color.orange, linewidth=2, title="SMA")

// 当价格穿越移动平均线时,在收盘价上下3%的位置提交买入和卖出停止单
if ta.cross(close, smaValue)
    strategy.entry("Enter Long", strategy.long, stop=close * 1.03,
         oca_name="sma-entry", oca_type=strategy.oca.cancel)
    strategy.entry("Enter Short", strategy.short, stop=close * 0.97,
         oca_name="sma-entry", oca_type=strategy.oca.cancel)

// 如果自交叉发生以来已过去5根K线,但两个停止单都未成交,则将它们全部撤销
if ta.barssince(ta.cross(close, smaValue)) == 5
    strategy.cancel_all()

代码的挂单逻辑是:当 ta.cross(close, smaValue) 条件满足时,我们同时调用两次 strategy.entry(),一次用于挂出多头停止单,另一次用于挂出空头停止单。两个订单的 oca_name 都设为 "sma-entry"oca_type 都设为 strategy.oca.cancel,将它们绑定在同一个OCA组中。

撤单逻辑则使用 ta.barssince() 函数来计算自上次均线交叉以来经过了多少根K线。如果这个数值等于5,就意味着挂单已经过期,我们便调用 strategy.cancel_all() 将它们全部撤销。

在图表上,该策略会根据SMA交叉信号,挂出多空停止单进行交易,如下所示:

简单总结一下:一个策略可以通过调用两次 strategy.entry() 函数来同时提交一个多头和一个空头的停止入场单。要实现这种二选一的突破交易,该函数需要五个关键参数:订单ID、交易方向、停止价格(stop),以及用于创建OCA组的 oca_typeoca_name。当原始的入场设定失效时,我们应该使用 strategy.cancel()strategy.cancel_all() 函数来撤销这些挂单。

同时开设多头和空头的止损限价单

PineScript策略通过模拟交易来评估交易思路的表现,而 strategy.entry() 函数正是其用来建立多头和空头仓位的核心工具。更进一步,它甚至可以同时生成一个多头和一个空头的止损限价单。

为什么要这样做呢?同时挂出多头和空头的止损限价单,是一种应对突破行情的有效策略。假设我们的代码识别出了一个市场即将大幅波动的盘整形态。如果脚本无法预知价格将向哪个方向突破,它就可以在区间的上下方同时布置两个止损限价单。后续的价格行为将自然地决定哪个订单最终成交。

这种双向挂单的思路与同时挂出多空止损单的逻辑类似,但有一个关键区别:止损限价单包含了一个限价,这可以防止策略在突破发生时以一个非常不利的价格(即滑点过大)成交。所以,我们虽然有兴趣开仓,但不是不计任何代价。

要生成一个同时存在的多空止损限价入场订单,我们需要遵循三个步骤。第一步是调用两次 strategy.entry() 函数,一次用于创建多头止损限价单,另一次用于创建空头止损限价单,每一次调用都需要提供这些关键参数:

  • 订单ID:为每个订单指定一个必需的名称。
  • 交易方向:多头订单使用 strategy.long,空头订单使用 strategy.short
  • 止损触发价(stop):指定订单的触发价格。这是一个具体的价位,而不是点数或百分比。
  • 限价(limit):指定订单的成交价格限制,成交价必须等于或优于此价格。
  • 订单组名称(oca_name):为两个订单设置相同的组名,这样PineScript才能知道它们是关联的。
  • 订单组类型(oca_type):将此参数设为 strategy.oca.cancel,以创建一个OCA(One-Cancels-All,一成交则全取消)订单组。通过这种订单组,当其中一个订单成交时,TradingView会自动取消另一个订单。这确保了即使我们同时提交了两个订单,最终也只有一个会成交。

第二步是设置触发条件,将这两个 strategy.entry() 调用都放在一个 if 语句中,通过 if 语句的条件来控制这两个挂单的生成时机,确保它们只在特定的市场条件下(如盘整形态形成时)被创建。第三步是及时取消订单,当入场的理由不再成立时,应及时取消这两个待处理的订单,我们可以使用 strategy.cancel() 函数来分别取消它们,或者使用 strategy.cancel_all() 函数来一次性取消所有待处理的订单。

下面,让我们将这些要求转化为具体的PineScript代码。

多空双向止损限价入场

要同时挂出多头和空头的止损限价单,我们需要调用两次 strategy.entry() 函数,并为它们配置好订单ID、方向、触发价、限价,以及最重要的订单组参数。对于多头方向的订单,代码如下:

// 提交一个开立多头仓位的止损限价单。触发价为前一根K线的最高价,
// 成交限价为当前K线的收盘价或更低。
strategy.entry("Enter Long", strategy.long, stop=high[1], limit=close,
	 oca_type=strategy.oca.cancel, oca_name="stp-lmt-entries")

这里,strategy.entry() 创建了一个名为 "Enter Long" 的多头订单。stop 参数将触发价设为前一根K线的最高价(high[1]),而 limit 参数则将成交限价设为当前K线的收盘价。

关键在于 oca_typeoca_name 这两个参数。oca_type 设为 strategy.oca.cancel,表明这是一个OCA订单组。oca_name 则为这个组命名为 "stp-lmt-entries"。这个组名可以是任意字符串,只要确保多空两个订单使用同一个名称即可。

相应地,我们像下面这样创建空头方向的止损限价单:

// 提交一个开立空头仓位的止损限价单。触发价为前一根K线的最低价,
// 成交限价为当前K线的收盘价或更高。
strategy.entry("Enter Short", strategy.short, stop=low[1], limit=close,
	 oca_type=strategy.oca.cancel, oca_name="stp-lmt-entries")

这段代码创建了一个名为 "Enter Short" 的空头订单。触发价是前一根K线的最低价(low[1]),限价是当前K线的收盘价。最重要的是,我们为它设置了与多头订单完全相同的 oca_typeoca_name。这样,一旦其中一个订单成交,TradingView就会自动取消另一个,从而实现了二选一的突破交易逻辑。

上面两个代码片段有一个问题:它们会在每一根K线上都尝试挂单,这通常不是我们想要的。我们应该只在特定的盘整或突破前夕才挂出这些订单。为此,我们将它们放入一个 if 语句中,通过条件来控制下单时机。示例如下:

// 当相对强弱指数(RSI)穿越50中线时,同时提交一个多头
// 和一个空头的止损限价单,以捕捉潜在的突破行情。
if ta.cross(ta.rsi(close, 7), 50)
	strategy.entry("Enter Long", strategy.long, stop=high[1], limit=close,
		 oca_type=strategy.oca.cancel, oca_name="stp-lmt-entries")
	strategy.entry("Enter Short", strategy.short, stop=low[1], limit=close,
		 oca_type=strategy.oca.cancel, oca_name="stp-lmt-entries")

这个 if 语句使用 ta.cross() 函数来判断7周期的RSI是否上穿或下穿了50。只有当穿越发生时,if 块内的代码才会被执行,从而创建出多空两个方向的挂单。

请注意,这两个订单的触发价和限价是基于 if 条件最后一次成立时的K线数据。挂单的价格不会自动随着每一根新K线而更新,它们是那个特定时刻的一个快照。

挂单发出后,我们还需要考虑在何种情况下将它们取消,因为它们不应该永远有效。为此,我们再创建一个 if 语句,其条件用于判断何时取消订单。示例如下:

// 当RSI进入超买(>80)或超卖(<20)区域时,取消所有待处理的
// 止损限价单(如果它们尚未成交)。
if ta.rsi(close, 7) > 80 or ta.rsi(close, 7) < 20
	strategy.cancel("Enter Long")
	strategy.cancel("Enter Short")

这个 if 语句判断RSI是否进入了超买或超卖区。如果条件满足,就分别取消名为 "Enter Long""Enter Short" 的挂单。

如果策略中没有其他待处理的订单,使用 strategy.cancel_all() 会更简洁:

// ...
if ta.rsi(close, 7) > 80 or ta.rsi(close, 7) < 20
	strategy.cancel_all()

回顾一下,生成和管理双向止损限价单的两个关键步骤如下:

// 当RSI穿越50时,挂出多空双向的止损限价单
if ta.cross(ta.rsi(close, 7), 50)
	strategy.entry("Enter Long", strategy.long, stop=high[1], limit=close,
		 oca_type=strategy.oca.cancel, oca_name="stp-lmt-entries")
	strategy.entry("Enter Short", strategy.short, stop=low[1], limit=close,
		 oca_type=strategy.oca.cancel, oca_name="stp-lmt-entries")

// 当RSI进入超买或超卖区时,取消所有挂单
if ta.rsi(close, 7) > 80 or ta.rsi(close, 7) < 20
	strategy.cancel("Enter Long")
	strategy.cancel("Enter Short")

完整策略示例

让我们来看一个使用双向止损限价单进行交易的完整策略。下面的脚本基于近期最高价和最低价之间的距离来进行交易。

当这个价格区间连续5根K线收窄时,策略认为市场进入了盘整状态。为了捕捉随之而来的潜在突破,它会生成一个多头和一个空头的止损限价单。这两个订单被放入一个OCA订单组中,因此一旦一个方向的突破发生并导致一个订单成交,另一个订单就会被自动取消。

策略的完整代码如下:

//@version=5
strategy(title="Long & short stop-limit entries", overlay=true)

// 计算并绘制近期高低点
highestHigh = ta.highest(high, 20)[1]
lowestLow   = ta.lowest(low, 20)[1]
plot(highestHigh, color=color.green, title="Highest High")
plot(lowestLow, color=color.red, title="Lowest Low")

// 当高低点之间的距离连续5根K线收窄时,
// 生成多空双向的止损限价入场订单
if ta.falling(highestHigh - lowestLow, 5)
    strategy.entry("Enter Long", strategy.long, stop=highestHigh,
         limit=highestHigh + 10 * syminfo.mintick, oca_name="entries", 
         oca_type=strategy.oca.cancel)

    strategy.entry("Enter Short", strategy.short, stop=lowestLow,
         limit=lowestLow - 10 * syminfo.mintick, oca_name="entries", 
         oca_type=strategy.oca.cancel)

// 当价格穿越了价格通道但未开仓时,
// 取消旧的待处理止损限价入场订单
if ta.crossunder(close, lowestLow) or ta.crossover(close, highestHigh)
    strategy.cancel_all()

// 如果价格触及或跌破最低价通道,平掉多头仓位
if low <= lowestLow
    strategy.close("Enter Long", comment="Exit Long")

// 如果价格触及或突破最高价通道,平掉空头仓位
if high >= highestHigh
    strategy.close("Enter Short", comment="Exit Short")

我们首先用 strategy() 函数命名脚本,然后计算并绘制20周期的最高价和最低价通道。

接着是入场逻辑:当 ta.falling() 函数检测到价格通道连续5根K线收窄时,我们同时挂出ID为 "Enter Long""Enter Short" 的多空止损限价单。这两个订单都被放入名为 "entries" 的OCA订单组中。

然后是订单取消逻辑:如果价格在没有触发任何一个挂单的情况下,直接穿越了高低点通道,我们认为原始的盘整形态可能已经失效,于是通过 strategy.cancel_all() 取消所有待处理的订单。

最后是平仓逻辑:如果已经持有多仓,当价格触及或跌破最低价通道时,通过 strategy.close() 平仓。反之,如果持有空仓,则在价格触及或突破最高价通道时平仓。

简单总结一下:PineScript策略可以使用 strategy.entry() 函数来创建同时存在的多头和空头止损限价入场订单。要实现这一点,该函数需要六个关键信息:订单ID、交易方向、stop 触发价、limit 限价、oca_type(设为 strategy.oca.cancel)以及一个共享的 oca_name。当最初的入场设置失效时,我们应及时取消这些待处理的订单,以避免它们在不希望的时机成交,取消订单可以使用 strategy.cancel()strategy.cancel_all() 函数。

赞(0)
未经允许不得转载:图道交易 » Pine Script(220):同时挂出多空停止单与止损限价单
分享到

评论 抢沙发

登录

找回密码

注册