用市价单平仓
平掉策略的虚拟仓位,一个最常见的方法就是使用市价单。在Pine Script中,有两个函数可以生成这样的平仓指令:
strategy.close()函数:平掉所有具有特定名称的开仓交易。strategy.close_all()函数:简单粗暴地平掉所有开仓交易。
接下来,让我们看看这两种方法的具体用法。
平掉多头交易
要平掉一个特定的多头交易,我们使用 strategy.close() 函数。要做到这一点,我们需要为该函数提供一个必需的参数:我们想要平仓的、已开仓多头订单的订单ID。
例如:
strategy.close("Enter Long")
这行代码会指示 strategy.close() 函数通过一个市价单,来平掉之前开仓时ID为 "Enter Long" 的那笔交易。
但上面的代码片段缺少了一个关键环节:何时发送这个平仓订单。按照现在的写法,它会在每根K线上都尝试平掉名为 "Enter Long" 的订单,这几乎会导致交易在开仓后被立刻平掉。
正确的做法是,将 strategy.close() 放置在一个 if 语句中。这样,该函数就只会在 if 的条件判断为 true 时才被执行,从而实现在特定情况下才进行平仓。
代码如下:
// 当价格下穿加权移动平均线(WMA)时,
// 提交一个市价单来平掉ID为 'Enter Long' 的订单
if ta.crossunder(close, ta.wma(close, 15))
strategy.close("Enter Long")
这个 if 语句使用 ta.crossunder() 函数来检查当前K线的收盘价(close)是否下穿了15周期的加权移动平均线。只有当这个条件成立时,if 语句内部的代码才会被执行。
在 if 语句内部,strategy.close() 函数会平掉所有ID为 "Enter Long" 的开仓订单。这样一来,市价单平仓就只会在满足我们设定的特定条件时发生。
平掉空头交易
我们平掉空头交易的方式与平掉多头交易完全相同。我们调用 strategy.close() 函数,并至少提供一个参数:我们想要平仓的、已开仓空头订单的订单ID。
如果策略的空头入场订单ID是 “Enter Short”,那么 strategy.close() 会像这样通过市价单平掉该笔交易:
strategy.close("Enter Short")
为了避免在每根K线上都尝试平仓,我们需要一个条件来控制平仓的时机。因此,我们同样将 strategy.close() 放入一个 if 语句中:
// 当价格上穿加权移动平均线(WMA)时,
// 提交一个市价单来平掉ID为 'Enter Short' 的订单
if ta.crossover(close, ta.wma(close, 15))
strategy.close("Enter Short")
这个 if 语句使用 ta.crossover() 函数来判断收盘价是否上穿了15周期的WMA。如果条件成立,strategy.close() 函数就会被调用,以市价单平掉所有ID为 “Enter Short” 的空头交易。
平掉所有仓位
另一种市价单平仓的方式是使用 strategy.close_all() 函数。这个函数会通过一笔市价单,平掉所有已开仓的订单,一步到位。
无论策略当前是持有多头还是空头仓位,strategy.close_all() 都会自动选择正确的市价单方向(卖出或买入)来平掉所有交易。
strategy.close_all() 在以下场景中特别有用:
- 当策略可能同时持有多笔不同ID的订单时。与其为每个ID都调用一次
strategy.close(),不如用一次strategy.close_all()来全部清仓。 - 在某些特定时刻需要强制清仓时,无论持的是多单还是空单。(例如,在周末收盘前,或在回测周期结束时清空所有仓位。)
由于 strategy.close_all() 没有任何必需的参数,我们只需直接调用它即可:
strategy.close_all()
当然,我们通常不希望在每根K线上都执行清仓操作。所以,我们应该将 strategy.close_all() 放入一个 if 语句中,以设定特定的触发条件:
// 当价格穿越200周期EMA时,
// 提交一个市价单来平掉策略当前的所有仓位
if ta.cross(close, ta.ema(close, 200))
strategy.close_all()
这个 if 语句使用 ta.cross() 函数来判断收盘价是否与200周期的EMA发生了交叉(无论上穿还是下穿)。当交叉发生时,if 语句块内的 strategy.close_all() 函数就会被执行,以市价单平掉策略的所有仓位。
示例策略
让我们通过一个完整的策略来看看如何使用市价单平仓。下面的脚本基于肯特纳通道(Keltner Channel)进行交易。当价格上穿上轨时做多,跌破下轨时做空。
策略有三种市价单平仓逻辑:当持有多仓时,如果价格再次上穿上轨,则平掉多头仓位。类似地,当持有空仓时,如果价格再次下穿下轨,则平掉空头仓位。此外,如果价格穿越了肯特纳通道的中线,我们也会清空所有仓位。
策略的完整代码如下:
//@version=5
strategy(title="市价单平仓", overlay=true)
// 计算并绘制肯特纳通道
[keltMa, keltUpper, keltLower] = ta.kc(close, 20, 1.75)
plot(keltUpper, color=color.blue, title="上轨")
plot(keltMa, color=color.orange, title="肯特纳中线")
plot(keltLower, color=color.blue, title="下轨")
// --- 入场逻辑 ---
// 当价格上穿肯特纳上轨时做多
if ta.crossover(close, keltUpper)
strategy.entry("Enter Long", strategy.long)
// 当价格下穿肯特纳下轨时做空
if ta.crossunder(close, keltLower)
strategy.entry("Enter Short", strategy.short)
// --- 平仓逻辑 ---
// 当(持有多仓时)价格再次上穿肯特纳上轨,用市价单平掉多头交易
if ta.crossover(close, keltUpper)
strategy.close("Enter Long", comment="多头平仓")
// 如果(持有空仓时)价格再次下穿肯特t纳下轨,用市价单平掉空头交易
if ta.crossunder(close, keltLower)
strategy.close("Enter Short", comment="空头平仓")
// 当价格穿越中线时,用市价单清空策略所有仓位
if ta.cross(close, keltMa)
strategy.close_all(comment="清空所有仓位")
我们首先计算并绘制了肯特纳通道。
入场逻辑很简单:价格上穿上轨时,通过 strategy.entry("Enter Long", strategy.long) 做多;价格下穿下轨时,通过 strategy.entry("Enter Short", strategy.short) 做空。
平仓逻辑包含三个部分:
- 平多单:
if ta.crossover(close, keltUpper)条件在这里被复用。如果策略已持有多仓,当价格再次出现上穿上轨的信号时,我们将其视为一个平仓信号。strategy.close("Enter Long", comment="多头平仓")会平掉ID为"Enter Long"的多头订单。comment参数可以为这笔平仓交易在图表和交易报告中提供一个清晰的注释。 - 平空单:逻辑与平多单类似。如果策略已持有空仓,当价格再次下穿下轨时,
strategy.close("Enter Short", comment="空头平仓")会平掉空头订单。 - 清空所有仓位:
if ta.cross(close, keltMa)判断价格是否与肯特纳通道的中线发生交叉。这是一个中性的信号,我们用它来清空所有持仓。strategy.close_all(comment="清空所有仓位")会不论当前持的是多单还是空单,都将其全部平掉。
在图表上,该策略会根据肯特纳通道的信号,通过市价单进行交易,如下所示:
总结
- TradingView策略主要通过两种方式使用市价单平仓。
strategy.close()函数平掉所有具有特定ID的订单。strategy.close_all()函数则以市价单平掉策略的所有仓位(无论多空或ID)。- 我们必须将这些平仓函数放置在
if语句中,以确保它们只在满足特定条件时才执行。 - 重要提示:这两个函数只负责平仓,它们不能在平仓的同时反向开仓。
用止盈限价单退出交易
TradingView策略使用 strategy.exit() 函数来生成止盈订单(Profit Target)。通过这种方式,策略可以使用一个限价单来平掉其模拟仓位。
strategy.exit() 函数有多种配置方式,但要创建一个止盈订单,至少需要以下三个核心参数:
- 订单ID:为平仓订单设置一个名称,这是第一个必需的参数。例如,我们可以用
"Exit Long"和"Exit Short"来分别命名多头和空头的止盈订单。 from_entry参数:指定这个平仓订单是针对哪一个开仓订单的。通过这个参数,Pine Script就能将平仓与特定的开仓建立关联。- 止盈目标:配置止盈的具体价位。我们有两种方式来实现:
- 使用
profit参数:设置一个基于点数(ticks)的盈利目标,即从开仓价算起盈利多少个点。 - 使用
limit参数:设置一个具体的价格作为止盈目标。
- 使用
下面,我们来运用这三个步骤,编写多头和空头的止盈平仓逻辑。
多头平仓
根据上述步骤,我们有两种设置多头止盈目标的方法:按点数或按价格。
要通过盈利点数来设置多头平仓位,我们可以像这样使用 strategy.exit():
strategy.exit("Exit Long", from_entry="Enter Long", profit=200)
在这里,strategy.exit() 创建了一个名为 “Exit Long” 的平仓订单。它专门用于平掉名为 "Enter Long" 的开仓订单。profit 参数将止盈目标设在距离开仓价格200个点的位置。
要在一个指定的价格平仓,我们可以这样使用 strategy.exit():
strategy.exit("Exit Long", from_entry="Enter Long", limit=close * 1.05)
这个代码片段同样创建了一个名为 “Exit Long” 的平仓订单,用于平掉 “Enter Long” 的仓位。但这一次,limit 参数将止盈目标设为了当前K线收盘价上涨5%后的价位。
然而,以上两个示例都忽略了一个关键问题:应该在何时发送这个平仓订单?按照当前写法,策略会在每一根K线上都生成平仓订单。这虽然不会导致Pine Script报错,但对于基于价格的止盈目标来说,它会导致目标价位在每根K线上都发生变化,这通常不是我们想要的结果。
那么,发送止盈订单的最佳时机是什么时候呢?一个理想的时刻就是在生成开仓订单的同时。这样,一旦开仓成交,止盈订单就能立刻生效。
在代码实现上,这意味着当 strategy.entry() 或 strategy.order() 执行开仓操作时,我们也应该立即执行 strategy.exit()。
因此,我们的策略代码应该这样写:
// 当价格上穿20周期均线时,执行做多,
// 同时生成一个距离开仓价200点的止盈订单
if ta.crossover(close, ta.sma(close, 20))
strategy.entry("Enter Long", strategy.long)
strategy.exit("Exit Long", from_entry="Enter Long", profit=200)
这个 if 语句通过 ta.crossover() 函数判断收盘价是否上穿了20周期简单移动平均线。一旦条件满足,if 语句块内的代码会执行两项操作:
首先,strategy.entry() 函数生成一个市价单来开立一个名为 "Enter Long" 的多头仓位(strategy.long)。
紧接着,在同一时刻,strategy.exit() 函数生成一个名为 "Exit Long" 的平仓订单。from_entry 参数指明了这个平仓订单是为我们刚刚创建的 “Enter Long” 订单服务的。profit 参数则将止盈目标设在开仓价上方200个点。
当然,我们也可以使用具体价格来设置止盈目标,只需将 strategy.exit() 的 profit 参数替换为 limit 参数即可。
注意:我们无需在其他订单平仓后手动取消由
strategy.exit()创建的止盈单。因为strategy.exit()已经通过from_entry参数与开仓订单绑定。一旦那个开仓订单被平掉,TradingView会自动移除与之关联的止盈订单。
空头平仓
与多头止盈类似,空头止盈也有两种选择:基于点数的或基于价格的平仓。
要通过盈利点数来平掉空头仓位,我们可以这样使用 strategy.exit():
strategy.exit("Exit Short", from_entry="Enter Short", profit=175)
在这里,strategy.exit() 创建了一个名为 “Exit Short” 的平仓订单,用于平掉 "Enter Short" 的仓位。profit 参数将止盈目标设在开仓价下方175个点。
要在一个指定价格平掉空头仓位,可以像这样使用 strategy.exit():
strategy.exit("Exit Short", from_entry="Enter Short", limit=close * 0.97)
现在,strategy.exit() 通过 limit 参数将止盈目标设为当前K线收盘价下跌3%后的价位。
同样地,这两个代码片段都会在每根K线上持续发送平仓订单。为了避免这个问题,最佳实践是在创建空头开仓订单的同时就生成止盈订单。
示例如下:
// 当价格下穿20周期均线时,生成一个空头开仓单,
// 并为其设置一个175点的止盈订单
if ta.crossunder(close, ta.sma(close, 20))
strategy.entry("Enter Short", strategy.short)
strategy.exit("Exit Short", from_entry="Enter Short", profit=175)
这个 if 语句检查价格是否下穿了简单移动平均线。如果条件满足,代码块会执行两个函数:
首先,strategy.entry() 生成一个名为 “Enter Short” 的市价单来开立空头仓位(strategy.short)。
同时,strategy.exit() 生成一个名为 "Exit Short" 的平仓订单,通过 from_entry 与刚刚的开仓单绑定,并设置一个175点的盈利目标。
完整策略示例
让我们看一个使用止盈目标进行平仓的完整策略。下面的脚本基于相对强弱指数(RSI)进行交易。
当RSI上穿20时,策略以市价单做多,并提交一个设在当前K线最高价上方3%的止盈目标。同样,当RSI下穿80时,策略以市价单做空,并为其设置一个在当前K线最低价下方3%的止盈目标。
策略的完整代码如下:
//@version=5
strategy(title="Limit order exits")
// 计算相对强弱指数 (RSI)
rsiValue = ta.rsi(hlcc4, 4)
// 绘制RSI及其超买超卖线
plot(rsiValue, color=color.teal, title="RSI")
hline(20, title="Oversold")
hline(80, title="Overbought")
// 当RSI上穿20时做多,并为该仓位
// 生成一个高于最高价3%的止盈订单
if ta.crossover(rsiValue, 20)
strategy.entry("Enter Long", strategy.long)
strategy.exit("Exit Long", from_entry="Enter Long",
limit=high * 1.03)
// 当RSI下穿80时做空(并提交一个3%的止盈目标)
if ta.crossunder(rsiValue, 80)
strategy.entry("Enter Short", strategy.short)
strategy.exit("Exit Short", from_entry="Enter Short",
limit=low * 0.97)
我们首先用 strategy() 函数命名脚本。然后用 ta.rsi() 计算4周期的RSI,并用 plot() 和 hline() 将其及超买(80)超卖(20)水平线绘制出来。
接着是多头入场和止盈的逻辑:
// 当RSI上穿20时做多,并为其生成止盈订单
if ta.crossover(rsiValue, 20)
strategy.entry("Enter Long", strategy.long)
strategy.exit("Exit Long", from_entry="Enter Long",
limit=high * 1.03)
当 ta.crossover() 检测到RSI上穿20时,if 语句内的代码会执行。首先 strategy.entry() 开立一个名为 "Enter Long" 的多头市价单。紧接着,strategy.exit() 为这个刚开的仓位创建一个名为 "Exit Long" 的止盈订单,from_entry 将两者绑定,limit 则将止盈价格设在当时K线最高价的1.03倍。
然后是空头入场和止盈的逻辑:
// 当RSI下穿80时做空(并提交3%的止盈目标)
if ta.crossunder(rsiValue, 80)
strategy.entry("Enter Short", strategy.short)
strategy.exit("Exit Short", from_entry="Enter Short",
limit=low * 0.97)
当 ta.crossunder() 检测到RSI下穿80时,strategy.entry() 开立一个名为 "Enter Short" 的空头市价单。同时,strategy.exit() 为其创建一个名为 "Exit Short" 的止盈单,止盈价格设在当时K线最低价的0.97倍。
在图表上,该策略使用止盈订单平仓的效果如下:
总结
- TradingView策略使用
strategy.exit()函数来创建止盈订单。 - 创建此类订单需要三个核心参数:订单ID、要平仓的开仓订单名称(
from_entry),以及止盈价位。 - 设定止盈价位有两种方式:使用
profit参数指定盈利的点数,或使用limit参数指定一个具体的价格。 - 最佳实践是在提交开仓交易的同时就生成止盈订单。这样,一旦开仓成交,止盈单便能立刻生效,从而实现精准的即时风险管理。
用止损单退出交易
在TradingView策略中,我们使用 strategy.exit() 函数来生成止损单(stop-loss orders)。通过这种方式,策略可以在亏损达到特定数额时,以市价单平掉其虚拟仓位。
我们可以通过多种方式使用 strategy.exit() 函数。要通过止损单平仓,需要提供以下几个关键参数:
- 设置订单ID:通过第一个参数设置平仓订单的唯一名称。例如,我们可以用
"Exit Long"和"Exit Short"来分别命名多头和空头的平仓单。 - 使用
from_entry参数:这个参数用来指定该平仓指令是针对哪一个入场订单的。通过这种方式,Pine Script就能将止损单与特定的入场交易关联起来。 - 指定止损水平。这里有两种设置方式:
loss:设置一个从开仓价格算起的价差(以tick为单位)作为止损距离。stop:直接设置一个具体的价位作为止损价格。
重要提示:我们不需要使用
strategy.cancel()或strategy.cancel_all()来手动取消这个止损单。当我们使用from_entry将一个止损单附加到特定的入场交易上时,TradingView会自动管理。如果该笔交易被其他订单(如止盈单)平仓了,那么这个尚未触发的止损单会被系统自动撤销。
接下来,让我们通过代码来演示如何为多头和空头仓位设置止损。
多头止损平仓
如上所述,设置多头仓位的保护性止损有两种方法:基于价差(ticks)或基于具体价格。
第一种方法,基于价差的止损,使用 strategy.exit() 函数的代码如下:
// 为ID为 "Enter Long" 的入场单,生成一个亏损150个最小变动单位(ticks)的止损单
strategy.exit("Exit Long", from_entry="Enter Long", loss=150)
这里的 strategy.exit() 创建了一个名为 "Exit Long" 的平仓订单。我们通过 from_entry="Enter Long" 告诉它这个止损是专门用于平掉ID为 "Enter Long" 的那笔入场交易的。loss=150 则将止损位设置在开仓价下方150个最小变动单位(ticks)的位置。(TradingView会自动根据这个点数计算出具体的止损价格。)
第二种方法,基于具体价格的止损,代码如下:
// 为ID为 "Enter Long" 的入场单,提交一个止损单,其价格在当前K线最低价的下方2%
strategy.exit("Exit Long", from_entry="Enter Long", stop=low * 0.98)
这段代码同样创建了一个名为 "Exit Long" 的平仓单,并关联到 "Enter Long" 的入场。但这次,我们使用 stop 参数,直接将止损价格设定为当前K线最低价的98%。
上面的两个示例代码都缺少一个关键环节:何时发送这个止损单。按照现在的写法,它们会在每根K线上都执行,这不是最佳实践。
最好的做法是,在生成入场订单的同时生成止损单。这样做有两个核心优势:
- 即时保护:一旦入场单成交,止损单会立刻被激活,从而确保仓位从一开始就受到保护。如果等到持仓后再挂止损,会存在至少一根K线的延迟,这期间仓位是无保护的。
- 避免止损跟着价格跑:如果我们在每根K线上都更新止损价格(例如,始终设在当前K线最低价下方8%),那么随着价格的波动,止损位会一直跟着移动,可能永远不会被触发。因此,我们应该在入场时就确定好止损位,而不是让它一直漂移。
将入场和止损同时生成的代码如下:
// 当价格上穿过去20根K线的最高点时,做多入场,
// 同时设置一个距离开仓价150个最小变动单位的止损
if ta.crossover(high, ta.highest(high, 20)[1])
strategy.entry("Enter Long", strategy.long)
strategy.exit("Exit Long", from_entry="Enter Long", loss=150)
这个 if 语句判断价格是否突破了过去20根K线的最高点。当条件满足时,代码块内的指令被执行。首先,strategy.entry() 提交一个名为 "Enter Long" 的多头市价单。接着,strategy.exit() 提交一个名为 "Exit Long" 的平仓单,通过 from_entry 将它与 "Enter Long" 关联,并通过 loss 设置止损距离。
在后台,TradingView的运行机制很智能:它会先提交入场单,等待其成交后,再立刻激活与之关联的止损单。因此,我们完全可以在代码中将入场和止损指令写在一起,不必担心时序问题。
空头止损平仓
与多头止损类似,为空头仓位设置止损也有两种方式:基于价差(ticks)或基于具体价格。
基于价差的止损:
// 为ID为 "Enter Short" 的入场单,生成一个亏损235个最小变动单位的止损单
strategy.exit("Exit Short", from_entry="Enter Short", loss=235)
基于具体价格的止损:
// 为ID为 "Enter Short" 的入场单,提交一个止损单,其价格在当前K线最高价的上方2%
strategy.exit("Exit Short", from_entry="Enter Short", stop=high * 1.02)
与多头一样,最佳实践是在生成空头入场订单的同时生成其止损单。原因同样是实现即时保护,并防止止损价格随行情漂移。
代码示例如下:
// 当价格下穿过去20根K线的最低点时,做空入场,
// 同时设置一个距离开仓价235个最小变动单位的止损
if ta.crossunder(low, ta.lowest(low, 20)[1])
strategy.entry("Enter Short", strategy.short)
strategy.exit("Exit Short", from_entry="Enter Short", loss=235)
当 if 条件满足时,代码先通过 strategy.entry() 提交一个名为 "Enter Short" 的空头市价单。紧接着,strategy.exit() 提交一个与之关联的止损单。TradingView的后台机制会处理好这一切,确保在入场成交后止损才被激活。
示例策略
让我们通过一个完整的策略来看看如何使用 strategy.exit() 生成止损单。下面的脚本基于两条指数移动平均线(EMA)的交叉进行交易。
当快线上穿慢线时,策略做多;当快线下穿慢线时,策略做空。两种入场都会通过 strategy.exit() 设置一个保护性止损。止损价格设定在慢速均线附近,距离为10个最小变动单位(ticks)。
策略的完整代码如下:
//@version=5
strategy(title="止损单平仓", overlay=true)
// 计算并绘制指数移动平均线 (EMA)
fastEMA = ta.ema(close, 10)
slowEMA = ta.ema(close, 30)
plot(fastEMA, color=color.orange, title="快线EMA")
plot(slowEMA, color=color.teal, linewidth=2, title="慢线EMA")
// 当快线上穿慢线时做多
if ta.crossover(fastEMA, slowEMA)
strategy.entry("Enter Long", strategy.long)
strategy.exit("Exit Long", from_entry="Enter Long",
stop=slowEMA - syminfo.mintick * 10)
// 当快线下穿慢线时做空
if ta.crossunder(fastEMA, slowEMA)
strategy.entry("Enter Short", strategy.short)
strategy.exit("Exit Short", from_entry="Enter Short",
stop=slowEMA + syminfo.mintick * 10)
代码分三个部分:
- 计算指标:我们先计算并绘制了10周期和30周期的EMA。
- 多头逻辑:当
ta.crossover(fastEMA, slowEMA)条件满足时,if语句块被执行。内部代码首先调用strategy.entry()做多,然后立刻调用strategy.exit()设置止损。止损单名为"Exit Long",通过from_entry关联到"Enter Long"入场单,并通过stop将止损价格设在慢速EMA下方10个最小变动单位的位置。 - 空头逻辑:当
ta.crossunder(fastEMA, slowEMA)条件满足时,逻辑与多头类似。先调用strategy.entry()做空,然后立刻调用strategy.exit()设置止损,止损价格设在慢速EMA上方10个最小变动单位的位置。
在图表上,该策略会根据均线交叉进行交易,并为每笔交易设置保护性止损,如下所示:
总结
- TradingView策略使用
strategy.exit()函数来创建止损单。 - 要创建这样一个订单,该函数需要三个关键参数:订单ID、通过
from_entry关联的入场订单ID,以及止损水平。 - 止损水平可以通过
loss(基于价差)或stop(基于具体价格)来设定。 - 最佳实践是在提交入场订单的同时提交止损单。这样,当入场单成交后,TradingView会立即激活止损,为交易提供即时保护。





