判断策略是否有未平仓头寸
一个策略通过开仓和平仓来回测交易信号。为了让策略更具适应性,我们通常需要在代码中获取其当前的持仓信息。这样,脚本就可以根据它是否在场内来做出不同的决策。
我们使用 strategy.position_size 这个内置变量来获取策略的当前持仓数量。下面,就让我们来看看如何通过这个变量来判断策略当前是持有仓位还是处于空仓状态。
判断是否持有仓位
我们可以创建一个简洁的自定义函数,来判断策略当前是否持有任何仓位(无论是多头还是空头):
// IsLongShort() 函数在策略持有多头或空头仓位时返回 'true',
// 当脚本空仓时返回 'false'。
IsLongShort() =>
strategy.position_size != 0
在这个 IsLongShort() 函数内部,我们判断了 strategy.position_size 变量的值是否不等于零。当这个变量的值非零时,就意味着策略当前持有多头或空头仓位,此时该函数返回 true。当策略没有任何持仓时,strategy.position_size 的值为零,此时 IsLongShort() 函数返回 false。
IsLongShort() 函数有多种用法。例如,我们可以用 barcolor() 函数,将所有持有仓位期间的K线都标记为橙色:
// 将所有持有仓位的K线都涂成橙色
barcolor(IsLongShort() ? color.orange : na)
策略也可以在知道自己有持仓时做出不同的决策。比如说,我们可能希望在每周五平掉所有持有的仓位:
// 如果当前有持仓,并且是周五,则平掉所有仓位
if IsLongShort() and dayofweek == dayofweek.friday
strategy.close_all()
判断是否处于空仓状态
另一个常见的需求是判断策略当前是否处于空仓状态(即没有任何持仓)。下面是实现这个功能的快捷函数:
// IsFlat() 函数在策略没有任何持仓时返回 'true',
// 当脚本持有多仓或空仓时返回 'false'。
IsFlat() =>
strategy.position_size == 0
在这个 IsFlat() 函数内部,我们判断 strategy.position_size 变量的值是否等于零。如果是,就说明策略当前空仓,函数返回 true。反之,如果策略持有多仓或空仓,IsFlat() 则返回 false。值得注意的是,IsFlat() 函数返回的值与我们前面定义的 IsLongShort() 函数正好相反。
IsFlat() 函数同样有多种用法。例如,我们可以用 barcolor() 函数,将所有策略处于空仓状态的K线都标记为蓝色:
// 将所有空仓状态的K线涂成蓝色
barcolor(IsFlat() ? color.blue : na)
策略也可以基于是否空仓来做出订单决策。例如,我们可以规定只有在策略空仓时才允许开立新的多头仓位:
// 只有在当前空仓时,才允许根据信号开立新的多头仓位
if IsFlat() and close > ta.sma(close, 20)
strategy.entry("Enter Long", strategy.long)
通过这种方式使用 IsFlat() 函数,我们可以防止 strategy.entry() 在已有空头仓位时,意外地将仓位反转为多头。
持仓状态信息的多种应用方式
当一个策略能够知道自己是在场内还是场外时,它可以利用这个信息做很多事情。
例如,当策略知道自己空仓时,它可以挂出买入(做多)和卖出(做空)的止损单,为市场可能发生的突破行情提前布局;只在空仓时绘制潜在的入场止损位,一旦开仓就停止绘制;确保只在空仓时才开立新仓,以避免 strategy.entry() 或 strategy.order() 意外地反转已有仓位;使用不同的入场条件,例如在空仓时使用较保守的开仓条件,一旦建立仓位后则采用更激进的加仓条件;还可以计算或测量策略处于空仓状态的时长,以判断距离上一次交易过了多久。
同样,当策略知道自己有持仓时,它可以寻找加仓机会来扩大已有的仓位;在特定时间点对仓位进行管理,例如在周五收盘前平掉所有仓位,以避免持仓过周末;在持仓期间收集特定的市场数据,例如跟踪平均真实波幅(ATR)来计算持仓期间的平均市场波动性;或者只在持仓时绘制止损和止盈目标线。
示例策略
让我们看一个在完整策略中使用 IsFlat() 函数的例子。下面的脚本在RSI上穿30时做多,在RSI上穿70时平仓。
我们使用 IsFlat() 来为图表背景上色,区分空仓和持仓状态,从而可以轻松地观察到策略的交易区间。脚本的完整代码如下:
//@version=5
strategy(title="Open position or is flat example")
// IsFlat() 函数在策略没有任何持仓时返回 'true',
// 当脚本持有多仓或空仓时返回 'false'。
IsFlat() =>
strategy.position_size == 0
// 计算相对强弱指数 (RSI)
rsiValue = ta.rsi(close, 7)
// 绘制RSI及其超买超卖线
plot(rsiValue, color=color.fuchsia, title="RSI")
hline(30, title="Oversold")
hline(70, title="Overbought")
// 生成买入和卖出多头交易
if ta.crossover(rsiValue, 30)
strategy.entry("Enter Long", strategy.long)
if ta.crossover(rsiValue, 70)
strategy.close("Enter Long", comment="Exit Long")
// 当策略持仓或空仓时为背景上色
bgcolor(IsFlat() ? color.new(color.blue, 90) :
color.new(color.orange, 80))
我们首先用 strategy() 函数配置脚本属性。然后定义了 IsFlat() 函数。接着,代码计算并绘制了7周期的RSI及其30/70的超卖超买线。
之后是两个 if 语句,分别在RSI上穿30时开仓做多,以及在RSI上穿70时平仓。
最后,我们检查策略当前的持仓状态并为背景上色:
// 当策略持仓或空仓时为背景上色
bgcolor(IsFlat() ? color.new(color.blue, 90) :
color.new(color.orange, 80))
这里 bgcolor() 函数根据一个条件来为图表背景上色。这个条件判断 IsFlat() 函数的返回值。如果为 true(策略空仓),背景色就设为半透明的蓝色。如果为 false(策略持仓),背景色则设为半透明的橙色。
通过这种方式,策略在空仓时背景为蓝色,而在持仓时背景为橙色。RSI策略的着色背景在图表上看起来是这样的:
简单总结一下:一个策略通过 strategy.position_size 这个内置变量来检查其当前持仓状态。当这个变量的值不等于零时,策略持有多头或空头仓位;而当这个变量等于零时,策略没有任何仓位(即处于空仓状态)。
判断策略刚刚开仓还是平仓
一个策略会根据我们编写的逻辑来开仓和平仓。但我们的代码如何得知策略刚刚是开仓了还是平仓了呢?我们来一探究竟。
通过持仓规模监控策略的仓位变化
要判断我们的策略是开仓了还是平仓了,我们可以使用内置变量 strategy.position_size。当策略持有多仓时,这个变量返回一个正数。当持有空仓时,它返回一个负数。而当没有任何持仓(即空仓)时,它返回零。
通过 strategy.position_size,我们可以知道策略在当前时刻是处于多头、空头还是空仓状态。但要了解仓位是如何变化的,我们还需要知道它在之前的状态。我们可以通过历史引用运算符([])来获取变量的先前值。
通过比较当前值(strategy.position_size)和前一根K线的值(strategy.position_size[1]),我们就能判断出策略是否刚刚开多仓、是否刚刚开空仓,以及是否刚刚平仓。接下来,让我们通过一些具体的例子来探讨。
要提醒一点:当我们使用历史引用运算符访问前一根K线时,我们获取的是该变量在那根K线收盘时的值。所以 [] 无法窥探K线内部,去了解策略在K线形成过程中的某个时间点是多头还是空头。我们得到的是K线收盘时的持仓状态。
判断策略是否刚刚开多仓
当我们想要捕捉策略开多仓这个动作时,我们需要明确是从哪种状态转变而来的。是从空仓状态开多仓?还是从空头持仓反手做多?根据不同的需求,有几种不同的编码方式。
要简单地判断策略是否刚刚开多仓(不关心之前是空仓还是持有空头),我们可以这样写:
// 检查策略是否刚刚开立了一个多头仓位
longNow = strategy.position_size[1] <= 0 and
strategy.position_size > 0
这里我们检查两个条件:第一,在前一根K线收盘时,策略不持有多仓(即持有空仓或处于空仓状态,strategy.position_size[1] <= 0)。第二,在当前K线上,策略持有多仓(strategy.position_size > 0)。当这两个条件同时满足时,我们创建的 longNow 变量就为 true。
一旦我们捕捉到策略刚刚开多仓这个事件,我们就可以执行其他操作,例如将刚刚开多仓的K线背景高亮显示、提交一个加仓订单来扩大已有的多头仓位,或者在开仓后立刻计算止盈和止损价位。
当然,我们也可以更精确地定义之前的持仓状态。下面的代码用于判断策略是否从空头持仓反手做多:
// 判断策略是否从空头反手做多
longFromShort = strategy.position_size[1] < 0 and
strategy.position_size > 0
要判断策略是否从空仓状态开立了新的多头仓位,我们可以这样写:
// 判断策略是否从空仓状态开多仓
longFromFlat = strategy.position_size[1] == 0 and
strategy.position_size > 0
判断策略是否刚刚开空仓
同样地,我们也有几种方式来判断策略是否刚刚开空仓。要判断策略是否刚刚开空仓(不关心之前是空仓还是持有多头),代码如下:
// 判断策略是否刚刚开立了一个空头仓位
shortNow = strategy.position_size[1] >= 0 and
strategy.position_size < 0
这个 shortNow 变量为真的条件是:前一根K线不持有空仓(>= 0),而当前K线持有空仓(< 0)。
要判断策略是否从多头持仓反手做空,代码如下:
// 判断策略是否从多头反手做空
shortFromLong = strategy.position_size[1] > 0 and
strategy.position_size < 0
要判断策略是否从空仓状态开立了新的空头仓位,代码如下:
// 判断策略是否从空仓状态开空仓
shortFromFlat = strategy.position_size[1] == 0 and
strategy.position_size < 0
判断策略是否刚刚平仓
使用 strategy.position_size 变量的第三种方式是判断策略是否刚刚平仓(回到空仓状态)。要判断策略是否从一个持仓状态(无论多空)回到了空仓状态,代码如下:
// 判断策略是否刚刚平仓(从任何持仓状态回到空仓)
flatNow = strategy.position_size[1] != 0 and
strategy.position_size == 0
这个 flatNow 变量为真的条件是:前一根K线仍有持仓(不等于0),而当前K线变为了空仓(等于0)。
要判断策略是否从多头持仓平仓,代码如下:
// 判断策略是否平掉了多头仓位
flatFromLong = strategy.position_size[1] > 0 and
strategy.position_size == 0
要判断策略是否从空头持仓平仓,代码如下:
// 判断策略是否平掉了空头仓位
flatFromShort = strategy.position_size[1] < 0 and
strategy.position_size == 0
判断策略是否刚刚开仓(不区分多空)
除了判断具体的方向,我们有时也需要知道策略是否刚刚从空仓状态开立了一个新仓位,无论方向如何。代码如下:
// 判断策略是否刚刚从空仓状态开立了一个新仓位(多或空)
longShortNow = strategy.position_size[1] == 0 and
strategy.position_size != 0
这个 longShortNow 变量为真的条件是:前一根K线是空仓,而当前K线不是空仓。
简单总结一下:strategy.position_size 变量返回策略的市场仓位规模和方向,空仓时为0,多仓时为正数,空仓(做空)时为负数。我们可以通过比较当前K线的 strategy.position_size 与前一根K线的 strategy.position_size[1] 来精确地捕捉到仓位的变化:判断开多仓用 strategy.position_size[1] <= 0 and strategy.position_size > 0;判断开空仓用 strategy.position_size[1] >= 0 and strategy.position_size < 0;判断平仓用 strategy.position_size[1] != 0 and strategy.position_size == 0。



