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

Pine Script(217):strategy.close()与strategy.close_all()

#Pine Script入门教学

用strategy.close()通过市价单退出交易

PineScript策略通过模拟交易来评估交易思路的表现,之后我们需要平掉这些仓位来检验其效果。strategy.close() 函数的作用就是通过一个市价单来平掉(退出)一个特定的开仓订单。

每当我们希望通过市价单退出一个订单时,strategy.close() 都是最佳选择。当策略的仓位仅由一笔交易构成时,它会平掉这笔交易(从而退出整个仓位)。如果策略有多次入场建仓,该函数也可以用来实现分批平仓。

标准语法格式

strategy.close() 函数的标准语法格式如下:

strategy.close(id, when, comment, qty, qty_percent, alert_message)
  • id:指定要平仓的那个开仓订单的ID。这是一个必需的字符串参数,它告诉PineScript要用市价单退出哪个持有的订单。这个ID必须与开仓时 strategy.entry()strategy.order() 函数使用的ID完全一致。例如,如果开仓订单的ID是 "Enter Long",那么 "enter long""Enter long""EnterLong" 都无法让 strategy.close() 找到并平掉该订单——ID是区分大小写且完全匹配的。如果当前持有多个具有相同ID的订单,strategy.close() 会将它们全部平掉。请注意,与其它订单函数用 id 参数来命名新订单不同,strategy.close()id 参数是用来识别平仓目标的。
  • when:一个布尔值,用于条件性地决定是否执行平仓操作。此参数的默认值为 true,意味着如果不设置它,strategy.close() 会在任何时候都尝试执行。因此,我们通常会将它放在一个 if 语句中来精确控制其执行时机。
  • qty:一个数字,指定要从目标订单中平掉多少合约、股票或单位的数量。如果不设置此参数,会平掉指定订单的全部持仓。如果平仓数量大于订单的剩余持仓量,策略只会平掉该订单的全部剩余部分,不会因此意外地开立反向仓位。
  • qty_percent:一个介于0到100之间的数字,指定要平掉目标订单当前持仓数量的百分比。如果同时设置了 qty_percentqtyqty_percent 会覆盖 qty 的设置。如果两者都不设置,则默认平掉整个订单。这个百分比是基于指定订单的当前剩余数量,而不是其初始数量。例如,一个10手的订单,第一次用 qty_percent=50 会平掉5手,剩下5手;第二次再用 qty_percent=50,则会平掉剩余5手的50%,即2手(向下取整),还剩3手。
  • comment:一个字符串,用于为这个平仓订单添加注释。这个文本会显示在图表上以及策略测试器的交易列表中。
  • alert_message:一个字符串,用于设置订单的警报消息文本。当 strategy.close() 订单成交触发警报时,{{strategy.order.alert_message}} 这个占位符会被替换为这里设置的文本。

这么多参数,看起来是不是有点复杂?但别担心,strategy.close() 在实际应用中比看起来要简单得多。让我们通过一些例子来深入了解。

strategy.close()示例

使用 strategy.close() 主要有三种场景:平掉整个订单、部分平仓,以及同时平掉多个订单。我们来逐一探讨。

要完全平掉一个已有的订单,我们只需在 strategy.close() 的第一个参数中,指定那个要平仓的订单的ID。仅此而已,strategy.close() 会自动为其生成一个市价平仓单。我们也可以通过可选参数来自定义这个平仓订单:comment 为平仓订单设置一个自定义的描述,alert_message 定义订单成交时触发的警报消息。

多头平仓的例子:

// 当价格下穿20周期SMA时,通过市价单平掉名为 "Enter Long" 的仓位
if ta.crossunder(close, ta.sma(close, 20))
	strategy.close("Enter Long")

默认情况下,这个平仓订单在图表上会显示为 “Close entry(s) order Enter Long”,既冗长又不易辨认。我们可以用 comment 参数为其指定一个更清晰的名称:

// ...
if ta.crossunder(close, ta.sma(close, 20))
	strategy.close("Enter Long", comment="多头止损")

要自定义成交时的警报消息,可以这样做:

// ...
if ta.crossunder(close, ta.sma(close, 20))
	strategy.close("Enter Long", comment="多头止损", 
		 alert_message="平掉 'Enter Long' 订单")

strategy.close() 函数并不关心交易方向,平多仓和平空仓的方式完全一样,关键在于提供正确的订单ID。空头平仓的例子:

// 当价格上穿20周期SMA时,通过市价单平掉名为 "Enter Short" 的仓位
if ta.crossover(close, ta.sma(close, 20))
	strategy.close("Enter Short", comment="空头止损")

要通过 strategy.close() 生成的市价单来部分平掉一个仓位,我们需要指定目标订单的ID,然后选择一种方式来指定平仓数量:使用 qty 参数来平掉一个固定数量,或使用 qty_percent 参数来平掉当前持仓的一个百分比。

多头部分平仓:

// 当价格下穿20周期SMA时,从名为 "Enter Long" 的仓位中平掉3手
if ta.crossunder(close, ta.sma(close, 20))
	strategy.close("Enter Long", qty=3)

空头部分平仓:

// 当价格上穿20周期EMA时,平掉名为 "Enter Short" 仓位的一半
if ta.crossover(close, ta.ema(close, 20))
	strategy.close("Enter Short", qty_percent=50)

strategy.close() 也可以同时平掉多个已有的订单,主要有两种方式:如果要平掉的订单具有相同的ID,那么一次调用就会将它们全部平掉;如果具有不同的ID,那么我们需要为每一个订单都调用一次 strategy.close()

注意:如果你想用一个市价单平掉所有持仓,无论它们的ID是什么,更方便的方法是使用 strategy.close_all() 函数。

平掉多个不同ID订单的示例,先看多头:

// 当价格下穿12周期EMA时,平掉 "Enter Long #1" 和 "Enter Long #2"
if ta.crossunder(close, ta.ema(close, 12))
	strategy.close("Enter Long #1")
	strategy.close("Enter Long #2")

再看空头:

// 当价格上穿45周期WMA时,平掉多个空头订单
if ta.crossover(close, ta.wma(close, 45))
	strategy.close("Enter Short #1")                     // 平掉全部
	strategy.close("Enter Short #2", qty_percent=50)    // 平掉50%
	strategy.close("Enter Short #3", qty=1)             // 平掉1手

strategy.close()的行为特性

现在我们知道了如何使用 strategy.close(),再来看看它的一些重要特性。

与其它订单函数类似,我们可以通过 when 参数或 if 语句来条件性地执行 strategy.close()。两者在功能上没有区别,但我个人更推荐使用 if 语句,因为它能让代码结构更清晰易读。调用时,也强烈建议除了第一个 id 参数外,都使用关键字参数(如 comment=qty_percent=),而不是依赖参数的位置,这会让代码更清晰,也更不容易出错。

还有几个重要特性值得记住:

  • 不会意外开仓:strategy.close() 函数只能平掉已有的仓位,一个重要的安全特性是,它绝不会意外地开立反向仓位。
  • 可重复执行:一个 strategy.close() 函数可以重复作用于同一个开仓订单,实现多次部分平仓。例如,你可以用同一个 strategy.close("ID", qty=1) 指令,分5次平掉一个5手的仓位。这与 strategy.exit() 不同,后者的同一个平仓指令在部分成交后便不会再次执行。
  • 平仓规则:默认情况下,TradingView策略遵循先进先出(FIFO)的原则平仓。但如果我们设置 strategy()close_entries_rule 参数为 "ANY",那么 strategy.close() 就可以按任意顺序平掉持仓。
  • 模拟订单:strategy.close() 生成的所有订单都是模拟的,无法发送给真实的经纪商。
  • 目标不存在时的行为:如果策略当前没有持有指定ID的订单,strategy.close() 函数不会执行任何操作,也不会产生一个待处理的挂单,订单请求会被立即取消。这使得该函数在不确定某个订单是否仍然持仓时可以安全使用,不会有潜在的挂单风险。

简单总结一下:strategy.close() 函数通过一个市价单来平掉一个特定的订单,我们通过订单ID来告诉函数要平掉哪个已有的订单。如果存在多个同名订单,它会将它们全部平掉;如果不存在指定名称的订单,它不会执行任何操作。要平掉多个不同ID的订单,我们需要为每一个ID都调用一次 strategy.close()

用strategy.close_all()关闭所有策略订单

在PineScript中,有几个函数可以用来开仓交易。但在某个时刻,我们必须平掉策略的模拟仓位。strategy.close_all() 函数就是这样一个工具,它能通过一笔市价单,平掉策略的全部仓位,其结果是让策略回到空仓状态。

我们使用 strategy.close_all() 来平掉所有开仓的订单,无论当前是持有一个订单还是25个。而且,由于这个函数是通过市价单来执行平仓,它追求的是快速成交,而非最优的成交价格。

默认语法结构

strategy.close_all() 函数的标准语法结构如下:

strategy.close_all(when, comment, alert_message)
  • when:一个布尔值,用于决定是否应该生成平仓订单。这个参数的默认值是 true,如果我们不设置它,PineScript会在每根K线上都尝试执行此函数。因此,在实际使用中,我们通常会将 strategy.close_all() 放入一个 if 语句中,通过 if 的条件来控制其执行时机。
  • comment:一个文本字符串,用于为订单添加注释。这个描述性的文本会显示在图表上,也会出现在策略测试器的交易列表中。
  • alert_message:一个字符串,用于设定订单的警报消息。当策略警报被启用,并且警报模板中包含 {{strategy.order.alert_message}} 占位符时,这个文本就会在订单成交时替换该占位符,从而实现代码级别的自定义警报。

strategy.close_all()示例

通常,一个函数的实际应用比其完整的语法结构要简单得多,strategy.close_all() 也不例外。要使用它来平仓,我们只需编写一个 if 语句来检查我们的平仓条件,然后在 if 语句内部调用 strategy.close_all()。这样就足以通过市价单平掉我们的仓位了。

如果需要,我们还可以通过可选参数来自定义订单:使用 comment 参数为订单添加一个清晰的注释,使用 alert_message 参数为成交警报提供自定义的文本内容。

要让 strategy.close_all() 平掉一个多头仓位,我们可以这样做:

// 当K线收盘价下穿40周期EMA时,平掉所有仓位
if ta.crossunder(close, ta.ema(close, 40))
	strategy.close_all()

这段代码判断收盘价是否下穿了EMA。如果条件成立,strategy.close_all() 就会被执行,以市价单平掉策略的当前仓位。

默认情况下,这个平仓订单在图表上会显示为 “Close position order”。为了方便识别,我们可以用 comment 参数来自定义它的名称:

// 为平仓订单添加自定义注释
if ta.crossunder(close, ta.ema(close, 40))
	strategy.close_all(comment="EMA死叉平仓")

这样,图表上显示的订单名称就会是”EMA死叉平仓”,一目了然。

同样,我们也可以添加 alert_message 来自定义警报:

// 平仓并设置自定义警报消息
if ta.crossunder(close, ta.ema(close, 40))
	strategy.close_all(comment="清仓", alert_message="平仓离场:收盘价下穿EMA")

strategy.close_all() 函数是不区分持仓方向的,它对空头的处理方式与对多头完全一样。要用它来平掉整个空头仓位,代码如下:

// 当K线收盘价上穿40周期EMA时,平掉所有仓位
if ta.crossover(close, ta.ema(close, 40))
	strategy.close_all()

你会发现,这段代码与平多仓的例子几乎完全相同。这是因为 strategy.close_all() 的作用就是简单地清空所有仓位,无论这个仓位是多是空。我们同样可以用 commentalert_message 来自定义这个平仓指令。

上面的例子也揭示了一个潜在的问题:由于 strategy.close_all() 不区分方向,一个本意用来平多仓的条件(如下穿均线),如果恰好在持有空仓时被触发,它同样会平掉这个空仓。这可能不是我们想要的结果。

为了解决这个问题,我们应该在平仓条件中明确加入对持仓方向的判断,可以通过内置变量 strategy.position_size 来实现:当策略持有多仓时,它的值大于0;持有空仓时,它的值小于0。

所以,要确保只在持有多仓时才执行平仓,我们可以这样做:

// 仅当策略持有多仓时,才在价格下穿EMA时平仓
if strategy.position_size > 0 and ta.crossunder(close, ta.ema(close, 40))
	strategy.close_all()

这个 if 语句现在有两个条件:第一,策略必须持有多仓;第二,价格必须下穿EMA。只有当两者都满足时,才会执行清仓。这样就避免了误平空仓的风险。

同理,要只在持有空仓时平仓,代码如下:

// 仅当策略持有空仓时,才在价格上穿EMA时平仓
if strategy.position_size < 0 and ta.crossover(close, ta.ema(close, 40))
	strategy.close_all()

strategy.close_all()的特性

现在我们知道了如何使用 strategy.close_all(),再来了解一下它的一些其他特性。

与其它订单函数一样,我们可以通过 when 参数或 if 语句来控制它的执行时机:

// 使用 when 参数
strategy.close_all(when = close > ta.highest(close, 20)[1])

// 使用 if 语句
if close > ta.highest(close, 20)[1]
	strategy.close_all()

两种写法的效果完全相同。我个人更推荐使用 if 语句,因为它能让条件逻辑更突出,代码结构也更清晰易读。

调用函数时,我也强烈建议使用关键字参数,而不是依赖参数的固定顺序:

// 不推荐:依赖参数顺序,可读性差且容易出错
strategy.close_all(true, "SMA交叉", "SMA(20) 发生交叉")

// ✅ 推荐:使用关键字参数,清晰、简洁且不易出错
strategy.close_all(comment="SMA交叉", alert_message="SMA(20) 发生交叉")

使用关键字参数,我们只需设置我们关心的参数,代码更易读,且无需记忆参数的顺序。

还有几点值得知道:如果调用 strategy.close_all() 时策略本就是空仓状态,那么什么也不会发生,这个函数不会等待一个仓位出现再去平掉它,所以即使不确定是否有持仓,调用它也是安全的。它只负责平仓,永远不会反向开立一个新的仓位。它生成的所有订单都是模拟的,用于策略回测,不能用于真实交易或纸上交易账户,也不能管理你手动开立的仓位。

简单总结一下:strategy.close_all() 函数通过一笔市价单来平掉策略的全部仓位。该函数不区分持仓方向,对多仓和空仓都有效。为了避免误平仓,最佳实践是在平仓条件中加入对 strategy.position_size 的检查,以明确目标方向。当策略没有持仓时,调用它不会产生任何效果。

赞(0)
未经允许不得转载:图道交易 » Pine Script(217):strategy.close()与strategy.close_all()
分享到

评论 抢沙发

登录

找回密码

注册