PineScript策略订单函数一览
在TradingView策略能够在图表上进行模拟交易之前,它的代码必须先生成交易指令。我们通过PineScript中一些特殊的函数——即所谓的订单函数来完成这项工作。
PineScript提供了多种订单函数以应对不同的需求。所有可用的函数如下:
| 函数 | 描述 |
|---|---|
strategy.entry() |
专门用于开仓。可以生成市价单、停止单、限价单和停止-限价单。它也可以用于反手开仓。 |
strategy.exit() |
专门用于保护性平仓。可以生成止盈单(限价)、止损单(停止)和追踪止损单。 |
strategy.order() |
通用的订单函数。可以生成买入和卖出指令,用于开仓、平仓、加仓、减仓和反手。支持所有订单类型。 |
strategy.close() |
按名称平仓。生成一个市价单,平掉所有具有特定ID的持仓。 |
strategy.close_all() |
全部平仓。生成一个市价单,平掉策略当前所有的持仓,实现一键清仓。 |
strategy.cancel() |
按名称撤单。取消一个特定ID的、尚未成交的挂单。 |
strategy.cancel_all() |
全部撤单。取消策略当前所有尚未成交的挂单。 |
为了更好地理解这些函数,我们可以将它们分为三类:
- 开仓函数:
strategy.entry()、strategy.order() - 平仓函数:
strategy.exit()、strategy.order()、strategy.close()、strategy.close_all() - 撤销挂单函数:
strategy.cancel()、strategy.cancel_all()
下面,我们来逐一简要介绍每个订单函数。
开仓订单:strategy.entry()
strategy.entry() 函数专用于让策略开立多头或空头仓位。它支持市价单、停止单(stop)、限价单(limit)和停止-限价单(stop-limit)。
使用此函数,我们至少需要提供两个信息:一个订单ID(即订单名称)和交易方向(strategy.long 做多,strategy.short 做空)。
市价单:
// 当价格上穿20周期EMA时,以市价做多
if ta.crossover(close, ta.ema(close, 20))
strategy.entry("Enter Long", strategy.long)
停止单,需额外使用 stop 参数指定触发价格:
// 当价格突破20周期最高点时,提交一个买入停止单
if close > ta.highest(high, 20)[1]
strategy.entry("Enter Long", strategy.long, stop=high * 1.01)
限价单,需额外使用 limit 参数指定挂单价格:
// 当价格突破10周期最高点时,提交一个买入限价单
if high > ta.highest(high, 10)[1]
strategy.entry("Enter Long", strategy.long, limit=high - 0.25)
停止-限价单,需同时使用 stop 和 limit 参数:
// 当价格上穿20周期SMA时,提交一个停止-限价订单
if ta.crossover(close, ta.sma(close, 20))
strategy.entry("Enter Long", strategy.long, stop=high + 0.25, limit=close - 0.50)
保护性平仓订单:strategy.exit()
strategy.exit() 函数专用于为已有仓位设置保护性平仓,即止盈(profit target)、止损(stop-loss)和/或追踪止损(trailing stop)。
最佳实践是在提交入场订单的同时就提交 strategy.exit() 指令。这样,一旦入场单成交,仓位就能立刻受到保护。我们通过 from_entry 参数将这个平仓指令与特定的入场订单ID关联起来。
止盈单,可通过 profit(点数)或 limit(价格)设置:
// 入场做多的同时,设置一个200点的止盈目标
if ta.crossover(close, ta.ema(close, 20))
strategy.entry("Enter Long", strategy.long)
strategy.exit("Exit Long", from_entry="Enter Long", profit=200)
止损单,可通过 loss(点数)或 stop(价格)设置:
// 入场做多的同时,设置一个300点的止损
if high > ta.highest(high, 20)[1]
strategy.entry("Enter Long", strategy.long)
strategy.exit("Exit Long", from_entry="Enter Long", loss=300)
追踪止损单,需设置 trail_offset(追踪距离)和激活条件(trail_points 或 trail_price):
// 入场做多的同时,设置一个追踪止损
if ta.crossover(ta.rsi(close, 7), 30)
strategy.entry("Enter Long", strategy.long)
strategy.exit("Exit Long", from_entry="Enter Long", trail_points=5, trail_offset=20)
通用订单指令:strategy.order()
strategy.order() 是一个非常灵活的万能函数,它只负责生成买入或卖出指令。这些指令具体会产生什么效果(开仓、平仓、加仓、减仓、反手),完全取决于策略当前的持仓状态和订单数量。它同样支持所有订单类型。
市价单:
// 提交一个市价买入指令
strategy.order("Buy (Market)", strategy.long)
限价单:
// 提交一个限价买入指令
strategy.order("Buy (Limit)", strategy.long, limit=low[1])
停止单:
// 提交一个停止买入指令
strategy.order("Buy (Stop)", strategy.long, stop=high[1])
停止-限价单:
// 提交一个停止-限价买入指令
strategy.order("Buy (Stop-Limit)", strategy.long, stop=close * 1.02, limit=high + 5 * syminfo.mintick)
按名称平仓:strategy.close()
strategy.close() 函数通过市价单平掉所有具有特定ID的持仓。它不在乎是多仓还是空仓,只要ID匹配就会被平掉。这个函数只能平仓,永远不会意外地开立反向仓位。
// 当价格下穿20周期SMA时,市价平掉所有ID为 "Enter Long" 的仓位
if ta.crossunder(close, ta.sma(close, 20))
strategy.close("Enter Long")
全部平仓:strategy.close_all()
strategy.close_all() 函数通过一笔市价单平掉策略当前持有的所有仓位,实现一键清仓。该函数无需任何参数。
// 当价格下穿40周期EMA时,清空所有持仓
if ta.crossunder(close, ta.ema(close, 40))
strategy.close_all()
按名称撤单:strategy.cancel()
strategy.cancel() 函数用于取消(删除)一个尚未成交的挂单。它需要一个参数:要取消的挂单的ID。
// 当价格上穿30周期EMA时,取消ID为 "Enter Long" 的挂单
if ta.crossover(close, ta.ema(close, 30))
strategy.cancel("Enter Long")
全部撤单:strategy.cancel_all()
strategy.cancel_all() 函数用于取消策略当前所有尚未成交的挂单,无论其方向或类型。该函数无需任何参数。
// 当RSI下穿20时,取消所有挂单
if ta.crossunder(ta.rsi(close, 7), 20)
strategy.cancel_all()
简单总结一下:TradingView策略通过PineScript的订单函数来开仓和平仓。开仓用 strategy.entry()(推荐)或 strategy.order();平仓用 strategy.exit()(保护性止损/止盈)、strategy.close()(按ID市价平仓)、strategy.close_all()(全部市价平仓)或 strategy.order()(通用);撤销挂单用 strategy.cancel()(按ID)或 strategy.cancel_all()(全部)。
用strategy.entry()开多头和空头交易
PineScript策略通过模拟交易来评估交易思路的表现,而 strategy.entry() 函数正是策略用来建立多头和空头仓位的核心工具。
更具体地说,strategy.entry() 函数能够通过以下四种订单类型来建立多头或空头仓位:市价单、止损单、限价单、止损限价单。
此外,strategy.entry() 还会与策略的当前持仓状态进行交互。基于这种交互,该函数可以实现开立一个新仓位、对现有仓位进行加仓,或是反转当前持仓。
可见 strategy.entry() 的功能十分强大。让我们首先来了解该函数的标准语法格式,然后再通过各种代码示例来深入学习这个重要的订单函数。
标准语法格式
strategy.entry() 函数包含以下参数:
strategy.entry(id, direction, qty, limit, stop, oca_name, oca_type,
comment, when, alert_message)
id:订单的标识符。这是一个必需的字符串参数,用于为订单命名。我们可以通过这个ID在之后修改或取消待处理的订单,或者在订单成交后对其进行平仓。这个ID也会显示在图表上以及策略测试器窗口的交易列表中。direction:订单的市场方向。这个必需的参数只能是strategy.long(多头开仓)或strategy.short(空头开仓)。qty:一个数字,指定要交易的合约、股票或单位的数量。如果不设置此参数或明确设为na,策略将使用默认的订单大小。如果策略也未配置默认订单大小,则strategy.entry()会以数量1进行交易。limit:订单的限价。这需要一个具体的价格,而不是一个点数偏移量。如果设置了该参数,strategy.entry()会发送一个限价单或止损限价单;如果不设置(或设为na),则不使用限价,此时订单将是市价单或止损单。stop:订单的止损触发价。这也需要一个具体的价格,而不是点数数量。如果设置了该参数,strategy.entry()会发送一个止损单或止损限价单;如果不设置(或设为na),则不使用止损触发价,此时订单将是市价单或限价单。oca_name:一个字符串,指定订单所属的订单组名称。TradingView通过这个名称来识别属于同一组的订单。oca_type:设置订单组的类型。可选值有strategy.oca.cancel(创建OCA订单组,其中一个成交,其他全部取消)、strategy.oca.reduce(创建ORO订单组,其中一个成交,其他订单数量相应减少)和strategy.oca.none(默认值,不使用订单组)。comment:一个字符串,用于为订单添加注释。这个注释会显示在图表上以及策略测试器的交易列表中。when:一个布尔值(true或false),用于条件性地决定是否生成该订单。这是使用if语句来控制下单的另一种方式。alert_message:一个字符串,用于设置订单的警报消息文本。当由strategy.entry()订单成交触发的警报中,{{strategy.order.alert_message}}这个占位符会被替换为这里设置的文本。
这么多参数,看起来是不是有点复杂?但幸运的是,我们通常不需要同时使用所有这些参数。实际上,strategy.entry() 比它的参数列表所显示的要简单得多。让我们通过一些例子来深入了解。
四种订单类型
strategy.entry() 究竟会生成哪种订单,完全取决于我们如何组合使用 limit 和 stop 这两个参数。下表展示了这两个参数如何组合成四种订单类型:
| 入场订单类型 | 如何通过 strategy.entry() 创建 |
|---|---|
| 市价单 | 不使用 limit 和 stop 参数。 |
| 限价单 | 设置 limit 参数,但不设置 stop 参数。 |
| 止损单 | 设置 stop 参数,但不设置 limit 参数。 |
| 止损限价单 | 同时设置 limit 和 stop 参数。 |
现在,我们来为每一种订单编写具体的代码示例。
市价单入场
要让 strategy.entry() 发出一个市价单,我们只需通过第一个参数设置订单ID(例如 “Enter Long” 或 “Enter Short”),再通过第二个参数设置订单方向(strategy.long 或 strategy.short)。仅此而已。
如果需要,我们还可以通过以下可选参数来自定义市价单:用 qty 指定一个自定义的订单数量(否则订单将使用策略的默认订单大小)、用 comment 为订单添加一个自定义的描述、用 alert_message 定义一个在订单成交时触发的警报消息。strategy.entry() 的其他参数通常不与市价单一同使用。下面我们来看代码。
要通过市价单开立一个多头仓位,我们可以像这样使用 strategy.entry():
// 当价格上穿20周期EMA时,执行做多
if ta.crossover(close, ta.ema(close, 20))
strategy.entry("Enter Long", strategy.long)
这个 if 语句判断K线的收盘价是否上穿了指数移动平均线。如果条件满足,strategy.entry() 就会执行,生成一个ID为 “Enter Long” 的多头(strategy.long)开仓订单。
如果我们还想指定订单数量,可以这样做:
// 当价格上穿20周期EMA时,执行做多
if ta.crossover(close, ta.ema(close, 20))
strategy.entry("Enter Long", strategy.long, qty=10)
这段代码与上一个例子类似,但 qty 参数告诉 strategy.entry() 开仓10个合约。
如果我们使用了策略警报功能,并且希望在订单成交时发送自定义消息(替换 {{strategy.order.alert_message}} 占位符),则可以设置 alert_message 参数:
// 当价格上穿20周期EMA时,执行做多
if ta.crossover(close, ta.ema(close, 20))
strategy.entry("Enter Long", strategy.long, qty=10,
alert_message="市价做多10手合约")
要通过市价单开立一个空头仓位,我们可以这样执行 strategy.entry():
// 当价格下穿20周期EMA时,执行做空
if ta.crossunder(close, ta.ema(close, 20))
strategy.entry("Enter Short", strategy.short)
当价格下穿EMA时,strategy.entry() 会生成一个ID为 “Enter Short” 的空头(strategy.short)开仓订单。
要指定订单数量,可以添加 qty 参数:
// 当价格下穿20周期EMA时,执行做空
if ta.crossunder(close, ta.ema(close, 20))
strategy.entry("Enter Short", strategy.short, qty=25)
这段代码将以25个合约、股票或单位的数量建立空头仓位。
同样,我们也可以为它设置一个自定义的警报消息:
// 当价格下穿20周期EMA时,执行做空
if ta.crossunder(close, ta.ema(close, 20))
strategy.entry("Enter Short", strategy.short, qty=25,
alert_message="市价做空25手合约")
止损单入场
要让 strategy.entry() 通过止损单入场,我们需要设置订单ID、订单方向(strategy.long 或 strategy.short),再通过 stop 参数指定入场触发价。这需要一个具体的价格,而不是点数偏移。
此外,我们还可以通过以下可选参数来自定义止损单:用 qty 自定义订单数量、用 oca_name 和 oca_type 将订单加入订单组(例如OCA或ORO组)、用 comment 添加订单注释、用 alert_message 定义警报消息。
要生成一个多头入场的止损单,可以这样做:
// 当价格突破20周期最高价时,提交一个多头入场止损单
if close > ta.highest(high, 20)[1]
strategy.entry("Enter Long", strategy.long, stop=high +
10 * syminfo.mintick)
当收盘价高于近期最高价时,strategy.entry() 会执行,生成一个ID为 “Enter Long” 的多头(strategy.long)订单。stop 参数将触发价设在了当前K线最高价上方10个最小变动单位(syminfo.mintick)的位置。
我们也可以指定订单数量和警报消息:
// ...
if close > ta.highest(high, 20)[1]
strategy.entry("Enter Long", strategy.long, qty=50,
stop=high + 10 * syminfo.mintick,
alert_message="止损单做多50手,价格 @ " +
str.tostring(high + 10 * syminfo.mintick))
要将此订单加入一个OCA订单组,以实现一成交全取消的效果,可以这样做:
// ...
if close > ta.highest(high, 20)[1]
strategy.entry("Enter Long", strategy.long, qty=50,
stop=high + 10 * syminfo.mintick,
oca_type=strategy.oca.cancel, oca_name="long-entries")
要生成一个空头入场的止损单,代码如下:
// 当价格跌破20周期最低价时,提交一个空头入场止损单
if close < ta.lowest(low, 20)[1]
strategy.entry("Enter Short", strategy.short, stop=low -
10 * syminfo.mintick)
当收盘价低于近期最低价时,strategy.entry() 会生成一个ID为 “Enter Short” 的空头(strategy.short)订单,触发价设在当前K线最低价下方10个最小变动单位处。同样,我们也可以为其添加数量、警报消息和订单组等设置。
限价单入场
要让 strategy.entry() 通过限价单入场,我们需要设置订单ID、订单方向,再通过 limit 参数定义限价。这需要一个具体的价格,而不是点数偏移。我们也可以为其添加 qty、oca_name、oca_type、comment 和 alert_message 等可选参数。
要通过限价单开立一个多头仓位,代码如下:
// 当价格创下10周期新高时,在突破点下方挂一个多头限价单
if high > ta.highest(high, 10)[1]
strategy.entry("Enter Long", strategy.long, limit=high -
15 * syminfo.mintick)
当价格突破近期高点时,strategy.entry() 会生成一个多头限价单,挂单价格设在当前K线最高价下方15个最小变动单位处,以期在回调时入场。
要通过限价单开立一个空头仓位,代码如下:
// 当价格创下10周期新低时,在突破点上方挂一个空头限价单
if low < ta.lowest(low, 10)[1]
strategy.entry("Enter Short", strategy.short, limit=low +
15 * syminfo.mintick)
当价格跌破近期低点时,strategy.entry() 会生成一个空头限价单,挂单价格设在当前K线最低价上方15个最小变动单位处。
止损限价单入场
要让 strategy.entry() 通过止损限价单入场,我们需要设置订单ID和订单方向,并同时通过 limit 参数指定限价、通过 stop 参数定义止损触发价。limit 和 stop 都需要一个具体的价格。
多头入场:
// 当价格上穿20周期SMA时,提交一个多头止损限价单
// 触发价为高点上方20点,限价为收盘价下方50点
if ta.crossover(close, ta.sma(close, 20))
strategy.entry("Enter Long", strategy.long, stop=high +
20 * syminfo.mintick, limit=close - 50 * syminfo.mintick)
空头入场:
// 当价格下穿20周期SMA时,提交一个空头止损限价单
// 触发价为低点下方20点,限价为收盘价上方50点
if ta.crossunder(close, ta.sma(close, 20))
strategy.entry("Enter Short", strategy.short, stop=low -
20 * syminfo.mintick, limit=close + 50 * syminfo.mintick)
strategy.entry()的行为特性
了解 strategy.entry() 如何生成订单后,我们再来看看它的一些重要行为特性。
除了开立新仓位,strategy.entry() 函数还可以自动反转一个已有的仓位,这无需我们进行任何额外配置。当策略持有多仓时,一个做空的 strategy.entry() 订单会自动将多头仓位反转为空头仓位;当策略持有空仓时,一个做多的 strategy.entry() 订单会自动将空头仓位反转为多头仓位。
这个过程是这样的:当策略有持仓时,如果 strategy.entry() 生成一个反向订单,TradingView会自动将这个新订单的数量加上当前持仓的数量。例如,如果我们持有多仓10手,而 strategy.entry() 生成一个5手的空单,TradingView实际上会发出一个15手的卖出订单。其中10手用于平掉多仓,另外5手用于建立新的空仓。
strategy.entry() 的具体行为取决于策略当前的持仓状态。对于一个做多的 strategy.entry() 订单:如果策略当前空仓,则开立一个新的多头仓位;如果当前持有多仓,则可以进行加仓(但受限于金字塔设置);如果当前持有空仓,则会反转为多头仓位。对于做空的订单,逻辑与此类似。
另外,PineScript的多个风险管理函数会限制 strategy.entry() 的行为。根据被触发的风险规则,strategy.entry() 可能会被限制只能单向交易,或者在某天内禁止交易,甚至完全无法再进行任何交易。
策略的金字塔(pyramiding)设置也会限制 strategy.entry() 在同一方向上可以开立的订单数量。一旦达到最大开仓次数,strategy.entry() 就无法再同向加仓,但仍然可以反转持仓。
我们可以通过两种方式来条件性地执行 strategy.entry()。第一种是使用 when 参数:
strategy.entry("Enter Long", strategy.long, when=ta.crossunder(low, ta.ema(hl2, 30)))
第二种是使用 if 语句(推荐):
if ta.crossunder(low, ta.ema(hl2, 30))
strategy.entry("Enter Long", strategy.long)
两种写法的效果完全相同,但我个人更推荐使用 if 语句,因为它能让条件逻辑更突出,代码结构也更清晰易读。
调用函数时,我强烈建议除了前两个必需参数外,都使用关键字参数。先看不推荐的写法(位置参数):
strategy.entry("Enter Long", strategy.long, na, yesterdayClose, na, "", strategy.oca.none, "Yesterday Limit Entry")
这种写法容易出错且难以阅读。推荐的写法(关键字参数):
strategy.entry("Enter Long", strategy.long, limit=yesterdayClose, comment="Yesterday Limit Entry")
这样代码更简洁,也更清晰。
最后还有几点值得知道:与 strategy.order() 函数相比,strategy.entry() 是开仓交易更方便、更高效的方式,因为它受到了金字塔和风险管理规则的约束,更不容易出错。strategy.entry() 生成的所有订单都是模拟的,无法发送给真实的经纪商。调用 strategy.entry() 也不保证总能成功开仓,因为金字塔设置、风险管理规则和保证金要求都可能阻止订单的生成。
简单总结一下:strategy.entry() 函数用于模拟多头和空头的开仓交易,我们总是需要为其提供订单ID和交易方向(strategy.long 或 strategy.short)。通过组合使用 stop 和 limit 参数,它可以生成市价单、限价单、止损单和止损限价单。该函数的执行受到金字塔、风险管理和保证金等多种因素的制约,因此并不保证总能成功下单。


