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

Pine Script(236):获取策略的毛利润、总亏损与净利润

#Pine Script入门教学

获取策略的毛利润

在PineScript中,交易策略的总利润是通过 strategy.grossprofit 这个内置变量来获取的。该变量返回的是策略所有已平仓的盈利交易的累计金额。

当策略在图表末端完成了对所有K线的历史回测后,strategy.grossprofit 所返回的就是整个回测期间的最终总利润。不仅如此,策略在处理图表上任意一根K线时,都可以调用这个变量,从而得知策略截至当前时间点的累计盈利表现。

strategy.grossprofit的应用实例

strategy.grossprofit 变量的用法十分灵活,这里列举几种常见用法。最直接的用法是检查策略当前的总利润。例如,我们可以判断总利润是否超过了我们设定的某个目标值:

// 判断总利润是否已超过10,000
if strategy.grossprofit > 10000
	label.new(bar_index, high, text="总利润已突破10,000!")

strategy.grossprofit 变量返回的是一个序列值,这意味着在每一根K线上,它都有一个对应的值。如果我们直接使用而不指定具体的K线,那么获取到的就是当前K线上的值。

当然,我们也可以访问历史K线上的总利润数据。要实现这一点,只需将变量与历史操作符([])结合即可。举个例子,strategy.grossprofit[1] 返回的就是前一根K线的总利润。

假设我们希望在总利润增长时,将图表背景色标示出来。代码可以这样实现:

// 当总利润相较于前一根K线有所增加时(意味着刚刚有一笔盈利交易平仓),
// 就将背景渲染为绿色
bgcolor(strategy.grossprofit > strategy.grossprofit[1] ? 
	 color.new(color.green, 80) : na)

因为 strategy.grossprofit 在每根K线上都有一个数值,所以PineScript中的各种内置函数都可以直接处理这个变量,就像处理 close(收盘价)等其他序列变量一样。

例如,要找出过去100根K线内的最低总利润,我们可以将 strategy.grossprofitta.lowest() 函数结合使用:

// 计算并绘制过去100根K线周期内的最低总利润
grossProfitLow = ta.lowest(strategy.grossprofit, 100)
plot(grossProfitLow, color=color.orange, title="最低总利润")

strategy.grossprofit的核心特性

使用这个变量时,有几个细节值得注意。首先,它返回的总利润是基于策略所设定的货币单位,该货币单位可能与当前图表交易品种的计价货币不同,此时TradingView会自动将交易品种的利润换算成策略设定的货币。在策略产生第一笔盈利平仓交易之前,它的值恒为零。

其次,strategy.grossprofit 只统计已平仓交易的盈利,当前持仓的浮动盈亏并不会计算在内。如需获取浮动盈亏,应使用 strategy.openprofit 变量。

在金融术语中,gross(毛利)有时指扣除成本前,但对于交易策略而言,总利润实际上已经包含了交易成本。因此,strategy.grossprofit 的数值会受到策略设置的滑点和佣金的影响,滑点和佣金越高,总利润就越低。

除了在代码中调用这个变量,我们也可以在策略测试器面板的性能总结标签页中直观地看到总利润的数值。另外要注意,strategy.grossprofit 是策略脚本专用变量,如果在指标脚本中调用它,TradingView会提示错误:无法在指标脚本中使用策略函数。

策略范例

接下来,让我们通过一个完整的策略脚本,来学习如何运用 strategy.grossprofit。下面的脚本基于经典的MACD指标进行交易。当MACD快线与慢线发生交叉,并且得到MACD柱状图的确认时,我们便建立多头或空头仓位。

为了追踪策略的表现,我们不仅会在图表上绘制总利润曲线,还会一并绘制其200周期的移动平均值和最低值,以便更深入地分析。策略的完整代码如下:

//@version=5
strategy(title="总利润示例")

// 计算指数平滑移动平均线 (MACD)
[macdLine, signalLine, macdHist] = ta.macd(close, 12, 26, 9)

// 生成入场信号
if ta.crossover(macdLine, signalLine) and macdHist > 0
    strategy.entry("Enter Long", strategy.long)

if ta.crossunder(macdLine, signalLine) and macdHist < 0
    strategy.entry("Enter Short", strategy.short)

// 捕获策略近期的最低总利润和平均总利润
lowestGrossProfit  = ta.lowest(strategy.grossprofit, 200)
averageGrossProfit = ta.ema(strategy.grossprofit, 200)

// 在图表上绘制总利润及其最低值和平均值
plot(strategy.grossprofit, color=color.green, title="总利润")
plot(lowestGrossProfit, color=color.gray, style=plot.style_cross,
     title="最低总利润")
plot(averageGrossProfit, color=color.orange, style=plot.style_cross,
     title="平均总利润")

首先,我们调用 strategy() 函数,通过 title 参数为该策略命名。

接着,使用内置函数 ta.macd() 计算MACD指标。该函数基于 close(收盘价)进行计算,其中快线周期为12,慢线周期为26,信号线周期为9。计算出的MACD快线、信号线和柱状图的值,分别存入 macdLinesignalLinemacdHist 变量。

随后的两个 if 条件语句用于生成交易信号。第一个 if 语句使用 ta.crossover() 函数判断MACD快线是否上穿信号线,同时要求MACD柱状图的值大于0。若条件满足,则调用 strategy.entry() 函数建立一个多头仓位(strategy.long)。

第二个 if 语句则使用 ta.crossunder() 函数判断MACD快线是否下穿信号线,同时要求MACD柱状图的值为负数。若条件满足,则同样调用 strategy.entry() 函数建立一个空头仓位(strategy.short)。

之后,我们来处理与总利润相关的计算:

// 捕获策略近期的最低总利润和平均总利润
lowestGrossProfit  = ta.lowest(strategy.grossprofit, 200)
averageGrossProfit = ta.ema(strategy.grossprofit, 200)

这段代码先是通过 ta.lowest() 函数获取了过去200根K线内的最低总利润,并将结果存入 lowestGrossProfit 变量,供后续绘图使用。然后,我们用 ta.ema() 函数计算了同一周期内的总利润指数移动平均值,并将结果存入 averageGrossProfit 变量。

最后,我们将这些数据绘制到图表上:

// 在图表上绘制总利润及其最低值和平均值
plot(strategy.grossprofit, color=color.green, title="总利润")
plot(lowestGrossProfit, color=color.gray, style=plot.style_cross,
     title="最低总利润")
plot(averageGrossProfit, color=color.orange, style=plot.style_cross,
     title="平均总利润")

此处的 plot() 函数绘制了三条曲线。第一条是策略的实时总利润(strategy.grossprofit),以绿色实线表示(因为未指定绘图样式,默认使用线图)。

另外两条线则以十字形(style=plot.style_cross)显示。一条是200周期内的最低总利润(lowestGrossProfit),另一条是平均总利润(averageGrossProfit)。它们的颜色分别被设定为灰色和橙色。

应用到图表上后,我们可以看到一条总利润的增长曲线,其下方伴随着代表平均水平和近期低点的两条十字线:

由于总利润是所有盈利交易的累加和,所以它的数值在整个回测过程中只会上升或保持不变,绝不会下降。这与会因亏损交易而减少的净利润形成了鲜明对比。

简单总结一下:strategy.grossprofit 变量返回的是策略所有已平仓盈利交易的累计总和,这个数值已经扣除了佣金和滑点等交易成本的负面影响。该变量返回值的计价单位是策略设置的货币,它可能与你交易的金融产品的计价货币不同。在图表的每一根K线上,strategy.grossprofit 都有一个对应的值,这使得我们不仅可以对相邻K线的总利润进行比较,还可以将其作为参数代入到各类函数中进行更复杂的运算。

获取策略的总亏损

在PineScript中,交易策略的总亏损是通过 strategy.grossloss 这个内置变量来获取的。该变量返回的是策略历史上所有已平仓的亏损交易所产生的亏损金额总和。

当图表上所有K线都回测完毕后,strategy.grossloss 在图表末端返回的值就是策略的最终总亏损。不过,在策略运行于图表中任何一根K线时,我们都可以调用这个变量。这能反映出策略截至当前时间点的累计亏损情况。

strategy.grossloss应用实例

strategy.grossloss 变量的用法有很多种。一种常见的用法是检查策略的总亏损状况。例如,我们可以判断总亏损是否超过了某个预设的阈值:

// 检查策略所有亏损交易的累计亏损是否超过5000
if strategy.grossloss > 5000
	label.new(bar_index, high, text="总亏损已超过5,000货币单位!")

strategy.grossloss 变量返回的是一个序列值,也就是说,它在每一根K线上都有一个对应的数值。如果我们直接使用而不指定具体的K线,那么获取到的就是它在当前K线上的值。

我们也可以获取历史K线上的总亏损。要实现这一点,只需将该变量与历史操作符([])结合使用。例如,strategy.grossloss[2] 返回的就是2根K线之前的总亏损值。

假设我们希望在总亏损增加时,将图表背景标为红色以作警示。我们可以这样实现:

// 当总亏损相较于上一根K线有所增加时,将背景填充为红色
bgcolor(strategy.grossloss > strategy.grossloss[1] ? 
     color.new(color.red, 80) : na)

正因为 strategy.grossloss 在每根K线上都有值,PineScript中的各种函数便可以对其进行计算,就像处理其他任何数值序列一样。

比如说,我们想知道最近40根K线期间的最低总亏损是多少。为了找到这个值,我们将 strategy.grosslossta.lowest() 函数结合起来,代码如下:

// 获取并展示最近40根K线内的最低总亏损
grossLossLow = ta.lowest(strategy.grossloss, 40)

plot(series=grossLossLow, color=color.fuchsia, title="最低总盈利")

strategy.grossloss的核心特性

使用这个变量时,有几点值得注意。首先是货币单位:strategy.grossloss 返回的亏损值,其货币单位遵循策略设置中的货币,这个货币单位可能与当前图表交易品种的计价货币不同,此时TradingView会自动将品种的亏损额换算成策略的本位币。

其次是数值符号:尽管代表的是亏损,但 strategy.grossloss 变量返回的值是一个正数(大于等于0),而不是负数。如果策略还没有产生任何已平仓的亏损交易,它的值将为0。

strategy.grossloss 只统计已平仓的交易。如果想了解当前持仓的浮动盈亏,应当使用 strategy.openprofit 变量。

关于成本计算:在英文中,gross(毛)一词有时指不含成本,例如gross revenue(毛收入)。但对于交易策略而言,strategy.grossloss(总亏损)始终包含交易成本。因此,策略支付的滑点和佣金越高,总亏损额就越大。

除了通过 strategy.grossloss 变量获取,我们也可以在TradingView策略测试器窗口里的表现摘要标签页找到总亏损这项数据。另外,strategy.grossloss 只能在策略脚本中使用,不能用于指标脚本。如果在指标中调用它,TradingView会提示错误:不能在指标脚本中使用策略函数。

策略范例

接下来,我们通过一个完整的策略脚本来看看 strategy.grossloss 的实际应用。下面这个脚本的交易逻辑基于一条平滑处理过的指数移动平均线(EMA)。当价格连续三根K线收于该均线上方时,我们开仓做多。反之,当价格连续三根K线收于该均线下方时,我们开仓做空。

我们会将策略的总亏损及其近期最低值和平均值都绘制在图表上,以便于跟踪和评估策略表现。完整的策略代码如下:

//@version=5
strategy(title="总亏损示例")

// 计算双重平滑EMA
smoothEMA = ta.ema(ta.ema(close, 20), 5)

// 定义开仓条件
if close > smoothEMA and close[1] > smoothEMA[1] and close[2] > smoothEMA[2]
    strategy.entry("Enter Long", strategy.long)

if close < smoothEMA and close[1] < smoothEMA[1] and close[2] < smoothEMA[2]
    strategy.entry("Enter Short", strategy.short)

// 计算策略近期的最低与平均总亏损
lowestGrossLoss  = ta.lowest(strategy.grossloss, 100)
averageGrossLoss = ta.sma(strategy.grossloss, 100)

// 在图表上绘制总亏损及其最低值和平均值
plot(strategy.grossloss, color=color.red, title="总亏损")
plot(lowestGrossLoss, color=color.teal, style=plot.style_circles, 
     title="最低总亏损")
plot(averageGrossLoss, color=color.fuchsia, style=plot.style_circles, 
     title="平均总亏损")

我们从 strategy() 函数开始,通过 title 参数为脚本命名。

接着,我们计算平滑移动平均线。这里我们对 ta.ema() 函数进行了嵌套调用:首先计算收盘价的20周期EMA,然后对得出的EMA结果再计算一个5周期的EMA,从而得到更平滑的曲线。结果保存在 smoothEMA 变量中。

随后的两个 if 结构用于判断入场时机。第一个判断最近三根K线的收盘价(closeclose[1]close[2])是否全部高于平滑均线。若条件成立,则调用 strategy.entry() 函数建立一个多头仓位(strategy.long)。

第二个 if 结构则判断是否连续三根K线的收盘价都低于平滑均线。若条件成立,strategy.entry() 会建立一个空头仓位(strategy.short)。

然后,我们对总亏损进行计算:

// 计算策略近期的最低与平均总亏损
lowestGrossLoss  = ta.lowest(strategy.grossloss, 100)
averageGrossLoss = ta.sma(strategy.grossloss, 100)

这里,我们使用 ta.lowest() 函数来获取过去100根K线期间的最低总亏损,并将结果存入 lowestGrossLoss 变量供后续使用。同时,我们使用 ta.sma() 函数计算同一周期内的平均总亏损,并将这个简单移动平均值存入 averageGrossLoss 变量。

最后,我们将这些数据绘制到图表上:

// 在图表上绘制总亏损及其最低值和平均值
plot(strategy.grossloss, color=color.red, title="总亏损")
plot(lowestGrossLoss, color=color.teal, style=plot.style_circles, 
     title="最低总亏损")
plot(averageGrossLoss, color=color.fuchsia, style=plot.style_circles, 
     title="平均总亏损")

plot() 函数在此处执行了三次绘图操作。第一次是绘制总亏损(strategy.grossloss),颜色为红色。由于没有指定绘图样式,PineScript默认会绘制成一条常规的实线。

另外两个绘图则以圆形(style=plot.style_circles)显示。第一个展示了100周期内的最低总亏损(lowestGrossLoss),另一个则展示了同周期内的平均总亏损(averageGrossLoss)。它们的颜色分别为青色和紫红色。

在图表上,总亏损表现为一条只增不减的曲线。在这条红线下方,可以看到其对应的平均值和最低值:

由于总亏损是所有已平仓亏损交易的累加和,所以在整个回测过程中,它的数值永远不会减少。这一点与净利润、胜率等其他可能出现回撤的绩效指标形成了鲜明对比。

简单总结一下:strategy.grossloss 变量返回的是策略所有已平仓亏损交易的亏损总额。该数值包含了交易成本(如佣金和滑点),并以一个正数(而非负数)的形式呈现。它的值以策略设置的货币为单位,而非交易品种的计价货币,TradingView会在需要时为我们自动完成两者间的货币换算。在每一根K线上,strategy.grossloss 都有一个对应的值,这一特性使得我们不仅可以在不同K线之间对亏损进行比较,还能将其作为输入,用于各种函数计算。

获取策略的净利润

在PineScript中,交易策略的净利润是通过 strategy.netprofit 这个内置变量来获取的。该变量返回的是策略所有已完成(即已平仓)交易的最终盈亏总额。

在图表的第一根K线周期上,strategy.netprofit 的初始值为零。之后,随着策略逐根处理K线并模拟交易,strategy.netprofit 的值会随之波动。当图表走到尽头,该变量返回的就是整个回测周期的最终净利润。

计算净利润有多种方式。其中一种方法是用总利润(所有盈利交易的收益总和)减去总亏损(所有亏损交易的损失总和)。其计算公式如下:

strategy.netprofit的应用实例

PineScript策略可以非常灵活地运用 strategy.netprofit 变量。一个常见的应用是检查策略当前的累计净利润。例如,我们可能想判断净利润是否达到了某个预设的目标:

// 判断当前净利润是否超过1000个货币单位
if strategy.netprofit > 1000
	label.new(bar_index, high, text="当前净利润已超过1,000!")

strategy.netprofit 变量返回的是一个序列值,这意味着它在每一根K线上都有一个对应的数值。如果我们直接使用该变量,默认获取的是当前K线上的净利润值。

我们也可以访问历史K线上的净利润数据。只需将该变量与历史操作符([])结合即可。例如,strategy.netprofit[5] 返回的就是5根K线之前的净利润。

这一特性让我们能方便地将当前的净利润与最近的数值进行比较。例如,要检测净利润是否刚刚发生了回撤,我们可以这样做:

// 检查当前K线的净利润是否相较于前一根K线有所下降
// (这通常意味着刚刚有一笔亏损交易被平仓)
if strategy.netprofit < strategy.netprofit[1]
	label.new(bar_index, high, text="净利润出现回撤!")

如果要计算策略在最近20根K线内的盈利增长情况,可以这样编写代码:

// 查看最近20根K线周期内,净利润的变化情况
netGrowth = strategy.netprofit - strategy.netprofit[20]
if netGrowth > 0
	label.new(bar_index, high, text="最近20根K线周期内,净利润有所增长。")

由于 strategy.netprofit 在每根K线上都有数值,PineScript的各种内置函数都能直接对其进行运算,就像处理其他任何变量一样。

比如说,我们想知道最近30根K线内的最低净利润点。要找到这个值,可以将 strategy.netprofitta.lowest() 函数相结合:

// 获取并绘制30根K线周期内的最低净利润
recentProfitLow = ta.lowest(strategy.netprofit, 30)
plot(series=recentProfitLow, color=color.red, title="近期最低净利润")

strategy.netprofit的核心特性

使用这个变量时有几点需要留意。首先,它返回的净利润是以策略设定的货币为单位的,这个单位可能与图表上交易品种的计价货币不同,此时TradingView会自动处理两者之间的汇率转换。净利润已经扣除了滑点和佣金,这些交易成本越高,strategy.netprofit 的最终值就越低。

策略的净利润等于其总利润与总亏损之差。因此,要想提高净利润,不仅要增加总利润,也要控制好总亏损。在没有任何平仓交易、所有交易都保本离场,或总利润与总亏损恰好相等的情况下,strategy.netprofit 的值将返回零。

strategy.netprofit 只统计已平仓交易的结果。若想了解当前持仓的浮动盈亏情况,需要使用 strategy.openprofit 变量。另外,该变量的净利润值是贯穿整个图表的,即从第一根K线一直累计到最后一根。如果我们想计算特定周期的净利润(例如周度或月度净利润),就需要我们自己编写相应的代码逻辑。

除了通过代码调用 strategy.netprofit,我们也可以在TradingView的策略测试器面板中直观地查看到策略的净利润。要注意它是策略脚本的专属变量,若在指标脚本中调用它,TradingView会报错:无法在指标脚本中使用策略函数。

策略范例

接下来,让我们通过一个完整的策略来深入了解 strategy.netprofit 的用法。下方案例脚本使用随机指标(Stochastics)进行交易。当%K线上穿%D线且%K值处于超卖区,或当%K线下穿%D线且%K值处于超买区时,我们便开立多头或空头仓位。

我们会在图表上绘制出策略的净利润曲线。同时,我们还会追踪并展示整个回测过程中的历史最高和最低净利润。该策略的完整代码如下:

//@version=5
strategy(title="净利润示例", default_qty_value=100)

// 计算随机指标(Stochastics)的%K和%D值
kValue = ta.sma(ta.stoch(close, high, low, 9), 3)
dValue = ta.sma(kValue, 3)

// 提交入场交易
if ta.crossover(kValue, dValue) and kValue < 20
    strategy.entry("Enter Long", strategy.long)

if ta.crossunder(kValue, dValue) and kValue > 80
    strategy.entry("Enter Short", strategy.short)

// 持续追踪策略的最高和最低净利润
var highestNetProfit = 0.0
var lowestNetProfit  = 0.0

highestNetProfit := math.max(highestNetProfit, strategy.netprofit)
lowestNetProfit  := math.min(lowestNetProfit, strategy.netprofit)

// 绘制净利润及其历史最高点和最低点
plot(strategy.netprofit, style=plot.style_area, title="净利润",
     color=strategy.netprofit > 0 ? color.green : color.red)
plot(highestNetProfit, color=color.green, title="历史最高净利润")
plot(lowestNetProfit, color=color.red, title="历史最低净利润")

首先,我们调用 strategy() 函数。title 参数为脚本命名,default_qty_value 将默认的下单数量设置为100手、股或合约单位。

然后,我们来计算随机指标。我们调用 ta.stoch() 函数来计算%K线的基础值,该函数作用于收盘价、最高价和最低价,周期长度为9。我们再将它嵌套于 ta.sma() 函数中,进行一次周期为3的平滑,从而得到常用的%K值。为了得到%D值,我们对%K值再进行一次 ta.sma() 平滑。我们将计算出的Stochastics值分别存入 kValuedValue 变量。

接下来的两个 if 语句负责生成交易信号。第一个 if 语句使用 ta.crossover() 函数判断%K线是否上穿%D线,并且 kValue 小于20(即处于超卖区)。当两个条件同时满足时,strategy.entry() 函数会建立一个多头仓位(strategy.long)。

第二个 if 语句则使用 ta.crossunder() 函数判断%K线是否下穿%D线,并且 kValue 大于80(即处于超买区)。当这些条件发生时,strategy.entry() 建立一个空头仓位(strategy.short)。

接着,我们来追踪净利润的峰值和谷值:

// 持续追踪策略的最高和最低净利润
var highestNetProfit = 0.0
var lowestNetProfit  = 0.0

highestNetProfit := math.max(highestNetProfit, strategy.netprofit)
lowestNetProfit  := math.min(lowestNetProfit, strategy.netprofit)

这里我们声明了两个持久变量(var)。highestNetProfit 用于追踪策略在回测期间所达到的历史最高净利润,而 lowestNetProfit 则用于记录历史最低净利润。

为了追踪最高净利润,我们使用 math.max() 函数来更新 highestNetProfit。该函数会比较变量的当前值和策略的实时净利润(strategy.netprofit),并返回两者中的较大值。这样,highestNetProfit 变量的值便只会在创出新高时才会被更新。

同理,我们使用 math.min() 函数来更新 lowestNetProfit 变量。该函数会返回变量的当前值和策略实时净利润中的较小值,从而确保变量始终记录着净利润的历史最低点。

最后,我们将这些数据输出到图表上:

// 绘制净利润及其历史最高点和最低点
plot(strategy.netprofit, style=plot.style_area, title="净利润",
     color=strategy.netprofit > 0 ? color.green : color.red)
plot(highestNetProfit, color=color.green, title="历史最高净利润")
plot(lowestNetProfit, color=color.red, title="历史最低净利润")

plot() 函数在这里绘制了三项数据。第一项是策略的净利润(strategy.netprofit),我们使用面积图(style=plot.style_area)来展示。通过条件运算符(?:),我们实现了当净利润大于零时图表区域为绿色,小于零时为红色的效果。

另外两个则是常规的线图。它们分别用绿色线条展示了历史最高净利润,用红色线条展示了历史最低净利润。

在图表上,我们可以看到净利润的面积图随着每笔交易的完成而实时变化,而上下的两条线则清晰地标示出了策略表现的峰值与谷底:

简单总结一下:strategy.netprofit 变量返回的是策略所有已平仓交易的净结果,这个结果已经计入了佣金和滑点所带来的负面影响。它的值是以策略的货币为单位,而非交易品种的计价货币,TradingView会自动为我们处理两者间的换算。在图表的每一根K线上,strategy.netprofit 都有一个对应的值,这使得我们能够方便地进行跨周期的数值比较,也让各类函数可以调用此变量进行深度计算。

赞(0)
未经允许不得转载:图道交易 » Pine Script(236):获取策略的毛利润、总亏损与净利润
分享到

评论 抢沙发

登录

找回密码

注册