获取策略的总交易数
在TradingView中,策略通过在图表上模拟交易来验证各种交易思想。而总交易次数,是评估一个交易思想优劣的若干关键指标之一。
就目前而言,PineScript语言中并没有一个内置变量能直接提供策略的总交易次数。不过幸运的是,我们完全可以自己动手轻松地计算出这个指标。下面就让我们看看如何实现。
自定义函数
要获取策略的总交易笔数,我们只需将已平仓的交易数量与当前持有的未平仓交易数量相加即可。前者可以通过 strategy.closedtrades 变量获得,而后者则由 strategy.opentrades 变量返回。
将这两个变量的值相加,就能准确地告诉我们,策略从历史回测开始到当前的实时信号为止,总共执行了多少笔交易。为了方便在不同策略中重复使用,我们最好将其封装成一个自定义函数,专门用来返回总交易笔数:
// TotalTrades() 函数返回策略执行的总交易笔数
// (包括已平仓和未平仓的),统计范围从第一根历史K线
// 延伸至当前K线。
TotalTrades() =>
strategy.closedtrades + strategy.opentrades
这段代码定义了一个名为 TotalTrades() 的函数。这个小巧的函数只专注做一件事:将 strategy.opentrades(未平仓交易数)与 strategy.closedtrades(已平仓交易数)相加。这个加总的结果,就是函数的返回值。这样,我们每次调用该函数,都能实时获取到策略的总交易笔数。
函数特性
这个自定义的 TotalTrades() 函数有几个值得我们留意的特性。
一是动态变化:函数返回的值会随着策略在图表上的逐步运算而动态更新。在第1,200根K线上得到的总交易数,和在第18,550根K线上得到的,通常是不同的(前提是策略在此期间有新的交易行为)。
二是非线性增长:当我们在代码中逐根K线地监控 TotalTrades() 的值时,需要注意它的值并非总是逐一递增。例如,当策略在同一根K线上同时开仓2笔交易时,TotalTrades() 的值可能会直接从52跳增到54。
三是交易与头寸的区别:此函数统计的是交易(trades)的总次数,这与策略交易的头寸(positions)数量不一定相同。举例来说,当我们通过5次分批入场的方式来建立一个完整的头寸时,我们虽然只交易了1个头寸,但这对应着5笔独立的交易。
快速应用示例
将上述函数代码复制到你的策略脚本中之后,你就可以在多处灵活地调用它了。第一种用法是获取策略的总交易笔数,并据此进行判断。例如,要检查当前的总交易数是否超过了某个设定的门槛,我们可以这样写:
// 判断策略的总交易笔数是否已超过150笔
if TotalTrades() > 150
label.new(bar_index, high, text="总交易已超过150笔!")
这类比较同样可以让策略在决策逻辑中,将总交易数作为一个考量因素。
比方说,我们想设定一个基于亏损额的止损规则。为此,当累计亏损超过2,000货币单位时,我们就不再发出新的做多信号。但为了避免策略仅根据寥寥数笔交易就草率地触发止损,我们规定这个规则必须在交易了至少50笔之后才生效。在这种场景下,TotalTrades() 就派上了用场:
// 设定策略的最大可承受亏损为2000,且该规则在交易超过50笔后激活
maxLossHit = strategy.netprofit < -2000 and TotalTrades() > 50
// 当价格上穿21周期SMA时做多(前提是未触发最大亏损条件)
if ta.cross(close, ta.sma(hl2, 21)) and not maxLossHit
strategy.entry("Enter Long", strategy.long)
第二种用法是结合历史操作符([]),来获取策略在过去某一根K线上的总交易数。例如,我们可以将历史值与当前值进行比较,从而得知策略在近期执行了多少笔交易:
// 检查策略在最近30根K线内是否执行了超过10笔交易
if TotalTrades() - TotalTrades()[30] > 10
label.new(bar_index, high, text="过去30根K线内交易超过10笔!")
有时我们并不需要回溯很长的周期,仅仅了解上一根K线的情况就已足够。比如说,我们想知道策略是否刚刚执行了一笔新的交易。要实现这一点,只需检查 TotalTrades() 的当前值是否大于它在上一根K线的值即可:
// 当策略相较于上一根K线产生了新交易时,
// 将图表背景涂成紫红色
bgcolor(TotalTrades() > TotalTrades()[1] ? color.new(color.fuchsia, 80) : na)
第三种用法,是将 TotalTrades() 与其他函数结合起来使用。这是完全可行的,因为 TotalTrades() 在每根K线上都返回一个数值,构成了所谓的序列值,而PineScript中有大量的函数都可以对这类序列值进行计算。例如,我们可以计算总交易笔数的移动平均值:
// 计算并绘制总交易笔数的移动平均线(SMA)
plot(ta.sma(TotalTrades(), 20), color=color.orange, title="交易计数SMA")
策略范例
让我们通过一个完整的策略来深入了解如何运用 TotalTrades() 自定义函数。下面的脚本基于钱德动量振荡器(Chande Momentum Oscillator, CMO)进行交易。当CMO指标上穿0轴时,我们做多;当它下穿0轴时,我们则建立空头头寸。
在这个策略中,我们会使用 TotalTrades() 函数将总交易笔数绘制在图表上,同时展示其简单移动平均线,并且每当有新交易发生时,都会用背景色进行高亮提示。策略的完整代码如下:
//@version=5
strategy(title="总交易示例")
// TotalTrades() 函数返回策略执行的总交易笔数
// (包括已平仓和未平仓的),统计范围从第一根历史K线
// 延伸至当前K线。
TotalTrades() =>
strategy.closedtrades + strategy.opentrades
// 计算钱德动量振荡器 (CMO)
cmoValue = ta.cmo(hlc3, 9)
// 定义多头和空头开仓逻辑
if ta.crossover(cmoValue, 0)
strategy.entry("Enter Long", strategy.long)
if ta.crossunder(cmoValue, 0)
strategy.entry("Enter Short", strategy.short)
// 以阶梯线形式展示策略的总交易笔数
plot(TotalTrades(), style=plot.style_stepline, color=color.fuchsia)
// 计算并绘制总交易笔数的移动平均线
tradesSma = ta.sma(TotalTrades(), 40)
plot(tradesSma, color=color.orange, title="总交易SMA")
// 当有新交易发生时,将图表背景涂成蓝色
newTrade = TotalTrades() > TotalTrades()[1]
bgcolor(newTrade ? color.new(color.blue, 80) : na)
我们从 strategy() 函数开始,通过 title 参数为脚本命名。接着,我们引入了前面讨论过的 TotalTrades() 自定义函数。
然后,ta.cmo() 函数被用来计算钱德动量振荡器。该函数基于9个周期的K线最高价、最低价和收盘价的平均值(hlc3)进行计算。
随后的两个 if 语句负责产生交易信号。第一个使用 ta.crossover() 函数判断CMO是否上穿了0轴,一旦成立,便通过 strategy.entry() 执行多头开仓。另一个 if 语句则用 ta.crossunder() 函数判断CMO是否跌破了0轴,若条件满足,则执行空头开仓。
接下来,我们展示策略的总交易笔数:
// 以阶梯线形式展示策略的总交易笔数
plot(TotalTrades(), style=plot.style_stepline, color=color.fuchsia)
这里的 plot() 函数将 TotalTrades() 函数的当前返回值显示出来。我们通过 style=plot.style_stepline 将其绘制成阶梯状的线条,颜色为紫红色(color.fuchsia)。
然后,我们计算总交易笔数的移动平均值:
// 计算并绘制总交易笔数的移动平均线
tradesSma = ta.sma(TotalTrades(), 40)
plot(tradesSma, color=color.orange, title="总交易SMA")
首先,ta.sma() 函数计算 TotalTrades() 序列值的40周期简单移动平均线。然后,plot() 函数将这条平均线绘制到图表上。由于没有设置绘图类型,PineScript会默认画出一条常规的折线,颜色为橙色。
最后,我们判断策略在当前K线上是否有新的交易行为:
// 当有新交易发生时,将图表背景涂成蓝色
newTrade = TotalTrades() > TotalTrades()[1]
bgcolor(newTrade ? color.new(color.blue, 80) : na)
我们先比较 TotalTrades() 的当前值是否大于其在上一根K线的值。如果大于,说明有新交易,这个比较表达式返回 true,否则返回 false。我们将这个布尔值存入 newTrade 变量。
接下来,bgcolor() 函数根据 newTrade 的值来为图表背景上色。这里用到了条件运算符(?:):如果 newTrade 为 true,运算符就返回一个带透明度的蓝色,bgcolor() 随即用这个颜色填充背景;反之则返回 na 值,这会取消背景色。
当策略应用于图表时,它会绘制出总交易笔数及其平均值的曲线,并且每当有新交易开仓时,图表背景都会被染上相应的颜色:
简单总结一下:我们自定义的 TotalTrades() 函数能够返回策略的总交易笔数。这个总数是所有已平仓交易(strategy.closedtrades)与所有未平仓交易(strategy.opentrades)的加和。TotalTrades() 统计的是交易的次数,而非头寸的数量。随着策略处理新的K线并执行交易,它的返回值会相应地发生变化。
获取策略的已平仓交易数量
在PineScript策略中,我们可以通过 strategy.closedtrades 变量来获取已完成的交易总数。该变量返回一个整数,代表策略从图表的第一根K线到当前K线为止,累计平仓了多少笔交易。
当策略在图表末尾完成其全部历史回测时,strategy.closedtrades 返回的便是策略在整个回测期间的总交易笔数。我们同样可以在回测过程中的任意一根K线上调用此变量,从而获知策略截至该时间点的累计交易数量。
应用实例
strategy.closedtrades 变量的用途十分广泛,以下是几种常见的应用场景。最直接的用法是获取策略当前的已平仓交易总数。例如,我们可以检查策略的交易笔数是否超过了某个设定的阈值:
// 检查策略的执行交易次数是否已超过一百笔
if strategy.closedtrades > 100
label.new(bar_index, high, text="交易已超过100笔!")
我们也可以将 strategy.closedtrades 与其他策略变量进行比较。假设我们想判断策略的胜率是否达到了50%或更高。一个快速的检验方法是,看盈利的交易笔数(strategy.wintrades)是否大于或等于总交易笔数的一半:
// 判断盈利交易的占比是否超过50%
if strategy.wintrades >= (strategy.closedtrades * 0.5)
label.new(bar_index, high, color=color.lime,
text="过半交易实现盈利!")
这类基于 strategy.closedtrades 的比较,可以被整合到策略的交易决策逻辑中。例如,我们可以设定一个规则,仅在总交易笔数少于200笔时才允许建立新的空头仓位:
// 当价格下穿20周期SMA,且总交易笔数
// 少于200时,才允许做空
if ta.crossunder(close, ta.sma(close, 20)) and strategy.closedtrades < 200
strategy.entry("Enter Short", strategy.short)
第二种常见的用法是结合历史操作符([])。这可以让我们获取到过去某一根K线上的已平仓交易数。通过将历史值与当前值进行比较,我们就能得知在此期间发生了多少笔新交易:
// 检验策略在过去25根K线内,是否执行了超过7笔交易
if strategy.closedtrades - strategy.closedtrades[25] > 7
label.new(bar_index, high, text="近期交易超过7笔!")
如果我们比较变量的当前值与其前一根K线的值,就能准确地判断策略是否刚刚平仓了一笔交易。相应的PineScript代码如下:
// 当策略刚刚完成一笔平仓交易时,将图表背景渲染为蓝绿色
bgcolor(strategy.closedtrades > strategy.closedtrades[1] ?
color.new(color.teal, 80) : na)
strategy.closedtrades 的第三个特性是,它在每一根K线上都有一个确定的值。这一特性使得各类函数可以直接利用这个序列值进行计算。例如,我们可以计算已平仓交易总数的指数移动平均线(EMA),以观察交易频率的变化趋势:
// 计算并绘制策略交易笔数的EMA
plot(ta.ema(strategy.closedtrades, 40), color=color.blue, title="交易笔数EMA")
核心特性
使用 strategy.closedtrades 时,有几点值得留意。
随着策略逐根处理K线,它的值会动态更新。在第50根K线上和第9950根K线上,它的值通常是不同的(假设策略在此期间有交易活动)。
strategy.closedtrades 不等于策略的总交易数,因为它不包含当前尚未平仓的交易(即浮动仓位,strategy.opentrades)。
策略的已平仓交易与已平仓头寸是两个不同的概念,这一点需要特别注意。一个完整的头寸(position)可能由多次交易(trade)构成。例如,如果一个策略通过6次交易来分批加仓建立一个头寸,之后再将此头寸全部平掉,那么这会计为6笔已平仓交易,但只计为1个已平仓头寸。
在逐根K线上观察,strategy.closedtrades 的值并非总是按1递增。如果一个策略已经完成了44笔交易,然后在同一根K线上平掉了两个独立的入场订单,那么它的值会直接从44跳升至46。
strategy.closedtrades 的值是盈利交易(strategy.wintrades)、亏损交易(strategy.losstrades)和盈亏两平交易(strategy.eventrades)三者之和。
此外,strategy.closedtrades 是策略脚本的专属变量,不能在指标脚本中使用。否则,TradingView会报告编译错误,提示无法在指标脚本中使用策略函数。
策略范例
接下来,让我们通过一个完整的策略来演示如何应用 strategy.closedtrades 变量。以下脚本是一个交易20周期价格突破的策略:当价格向上突破近期高点时做多,向下跌破近期低点时做空。
我们将在图表上绘制策略的已平仓交易总数,以及该数值的加权移动平均线(WMA)。同时,每当有新的交易平仓时,我们都将高亮显示图表背景。策略的完整代码如下:
//@version=5
strategy(title="已平仓交易示例")
// 计算近期的最高高点和最低低点
highestHigh = ta.highest(high, 20)[1]
lowestLow = ta.lowest(low, 20)[1]
// 生成突破交易信号
if high > highestHigh
strategy.entry("Enter Long", strategy.long)
if low < lowestLow
strategy.entry("Enter Short", strategy.short)
// 在图表上显示策略的总交易笔数
plot(strategy.closedtrades, color=color.black, linewidth=2)
// 计算并绘制交易笔数的移动平均线
tradeCountWMA = ta.wma(strategy.closedtrades, 15)
plot(tradeCountWMA, color=color.blue, title="交易笔数WMA")
// 当有新的平仓交易发生时,将背景渲染为橙色
newClosedTrade = strategy.closedtrades > strategy.closedtrades[1]
bgcolor(newClosedTrade ? color.new(color.orange, 80) : na)
我们以 strategy() 函数开始,为脚本命名。接着,ta.highest() 和 ta.lowest() 函数分别计算出20周期的最高高点和最低低点。
随后的两个 if 语句负责寻找入场时机。第一个判断当前K线的最高价是否突破了前高,若是,则 strategy.entry() 函数建立一个多头仓位(strategy.long)。第二个 if 语句则判断最低价是否跌破了前低,若是,则建立一个空头仓位(strategy.short)。
然后,我们在图表上绘制交易总数:
// 在图表上显示策略的总交易笔数
plot(strategy.closedtrades, color=color.black, linewidth=2)
此处的 plot() 函数绘制了 strategy.closedtrades 变量的实时值。因为未指定绘图类型,PineScript默认使用常规线图,并以黑色显示。
接下来,我们计算已平仓交易数的移动平均线:
// 计算并绘制交易笔数的移动平均线
tradeCountWMA = ta.wma(strategy.closedtrades, 15)
plot(tradeCountWMA, color=color.blue, title="交易笔数WMA")
这段代码首先调用 ta.wma() 函数,计算 strategy.closedtrades 的15周期加权移动平均值。然后 plot() 函数将这条平均线以蓝色实线的形式绘制在图表上。
最后,我们来处理背景着色逻辑:
// 当有新的平仓交易发生时,将背景渲染为橙色
newClosedTrade = strategy.closedtrades > strategy.closedtrades[1]
bgcolor(newClosedTrade ? color.new(color.orange, 80) : na)
这段代码首先判断 strategy.closedtrades 的当前值是否大于其前一根K线的值。如果大于,说明刚刚有交易平仓,newClosedTrade 变量便为 true,否则为 false。
然后 bgcolor() 函数根据 newClosedTrade 的值来为背景着色。通过条件运算符(?:),当 newClosedTrade 为 true 时,运算符返回一个半透明的橙色,bgcolor() 随即用此颜色渲染背景;否则,运算符返回 na 值,背景色便保持透明。
在图表上,该策略会绘制出交易总数的实时曲线和其平均线。而彩色的背景使得我们可以轻松地识别出每一笔交易完成的时刻:
简单总结一下:strategy.closedtrades 变量返回的是策略已平仓的交易笔数。这个计数包含了盈利、亏损和盈亏两平的所有交易,但不包括尚未平仓的交易。已平仓的交易数可能与已平仓的头寸数不同:例如,1个头寸可能包含了5笔独立的分批加仓交易。strategy.closedtrades 在每一根K线上都有一个对应的值,这使得跨周期的数值比较成为可能,也让各种函数可以利用该变量进行深度计算。




