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

Pine Script(228):获取未平仓订单的佣金与入场注释

#Pine Script入门教学

获取未平仓订单的手续费

当一个策略持有仓位时,我们可以使用 strategy.opentrades.commission() 函数来获取某一个特定开仓订单所支付的手续费。通过这个函数,策略就能获知其每一笔开仓交易具体产生了多少交易成本。

我们可以利用这个函数实现多种功能,例如:计算当前所有开仓订单支付的总手续费;报告持仓中平均到每个合约、每股或每个单位的手续费;以图表品种的点数(points)或价格跳动点(ticks)为单位来展示每笔订单的手续费;通过用手续费修正每笔订单的利润来计算仓位的毛利润;计算出手续费在仓位利润中所占的百分比。

默认语法结构

该函数的标准语法如下:

strategy.opentrades.commission(trade_num)

trade_num 是一个整数,用于指定你想查询哪一笔开仓订单的手续费。这个订单编号采用从零开始的索引方式:第一笔开仓订单的编号是0,第二笔是1,第三笔是2,以此类推。strategy.opentrades - 1 这个表达式可以返回最后一笔(即最新一笔)订单的编号。

这个函数的返回值有两种可能:一是返回一个浮点数,代表指定开仓订单所支付的入场手续费;二是返回 na 值,这在传入的订单编号 trade_num 不正确(例如小于0,或大于等于当前开仓订单的总数 strategy.opentrades),或者策略当前没有任何持仓时会发生。

快速示例

要获取第一笔开仓订单(即最早的那一笔)的手续费,我们可以这样做:

// 获取持仓中第一笔入场的手续费成本
firstEntryCosts = strategy.opentrades.commission(0)

要获取最后一笔开仓订单(即最新的一笔)的手续费,可以这样使用:

// 获取最后一笔(最新一笔)入场的手续费成本
lastEntryCosts = strategy.opentrades.commission(strategy.opentrades - 1)

另一个应用场景是遍历所有开仓订单。例如,假设我们想找出所有开仓订单中最高和最低的手续费。我们可以创建一个 for 循环,遍历所有订单,然后在循环内部使用 math.max()math.min() 函数来持续追踪最高和最低值。代码示例如下:

// 从策略的开仓交易中获取最高和最低的手续费
highestCommission = 0.0
lowestCommission = 1e10 // 设一个极大的初始值
for tradeNumber = 0 to strategy.opentrades - 1
    highestCommission := math.max(highestCommission, 
         strategy.opentrades.commission(tradeNumber))
    lowestCommission := math.min(lowestCommission,
         strategy.opentrades.commission(tradeNumber))

// 在图表上绘制最高和最低手续费
plot(highestCommission, title="最高手续费")
plot(lowestCommission, title="最低手续费")

函数的特性

strategy.opentrades.commission() 返回的订单手续费是一个正数。如果策略没有配置手续费,该函数会返回零(0)。

此函数是自PineScript版本5起才可用的新功能,在版本4及更早的版本中不存在。它只能在策略(strategy)脚本中使用,如果在指标(indicator)代码中调用它,PineScript会报错:'You cannot use strategy functions (strategy.opentrades.commission) in indicator script.'

示例策略

让我们通过一个完整的策略来看看如何使用 strategy.opentrades.commission() 函数。下方的脚本基于随机震荡指标(Stochastic oscillator)进行交易。当其%K线在超买或超卖区与%D线发生交叉时,我们开立空仓或多仓。

每当有新的入场交易发生时,我们使用 strategy.opentrades.commission() 来计算并显示当前持仓的平均及总手续费。

策略的完整代码如下:

//@version=5
strategy(title="开仓交易手续费", commission_value=0.25, 
     commission_type=strategy.commission.percent, pyramiding=5,
     overlay=true)

// 计算随机指标 %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)

// 追踪总交易数,判断是否有新交易入场
totalTrades = strategy.closedtrades + strategy.opentrades
newEntry = strategy.opentrades > 0 and totalTrades > totalTrades[1]

// 当有新交易入场时,创建一个带有手续费信息的标签
if newEntry
    // 首先,获取总手续费和平均手续费
    totalCommission = 0.0
    for tradeNumber = 0 to strategy.opentrades - 1
        totalCommission += strategy.opentrades.commission(tradeNumber)

    averageCommission = totalCommission / strategy.opentrades

    // 创建标签文本,然后创建标签本身
    labelText = "手续费\n平均: " + str.tostring(averageCommission, "0.00") + 
                "\n总计: " + str.tostring(totalCommission, "0.00")

    label.new(bar_index, open, color=color.black, textcolor=color.white,
         text=labelText, style=label.style_label_left)

我们首先用 strategy() 函数配置策略,设定了0.25%的交易手续费,并允许最多5次同向加仓。接着,代码计算随机指标并根据其在超买/超卖区的金叉/死叉信号来开仓。

然后,我们通过比较当前K线的总交易数与上一根K线的总交易数,来判断是否有新的交易发生。最后,一个 if 语句在新交易发生时分析手续费:

// 当有新交易入场时,创建一个带有手续费信息的标签
if newEntry
    // ...

newEntry 条件为真时,我们执行三步操作。第一步计算总手续费:初始化一个 totalCommission 变量为0,然后通过 for 循环遍历所有开仓订单,使用 strategy.opentrades.commission() 获取每笔订单的手续费并累加。第二步计算平均手续费:用总手续费除以开仓订单的数量(strategy.opentrades)。第三步创建并显示标签:将计算出的总手续费和平均手续费拼接成一个字符串,并通过 label.new() 函数在图表上创建一个标签来显示这些信息。

在图表上,我们能看到策略在每次入场时都会创建一个文本标签,显示当时持仓的平均和总手续费:

简单总结一下:strategy.opentrades.commission() 函数返回某一个特定开仓订单的手续费金额。这个手续费以一个正数返回,如果策略未设置手续费,则返回0。我们通过一个订单编号来告知函数我们想要查询哪一笔订单的手续费。订单编号从0开始,代表第一笔入场单,并以 strategy.opentrades - 1 结束,代表最后一笔(即最新一笔)入场单。

获取未平仓订单的入场注释

当一个策略持有模拟仓位时,我们可以通过 strategy.opentrades.entry_comment() 函数来获取某个特定持仓交易的注释。通过这个函数,代码可以检索到特定开仓订单的文本备注。

标准语法格式

该函数的标准语法格式如下:

strategy.opentrades.entry_comment(trade_num)

trade_num 是持仓交易的编号。这个整数参数告诉PineScript要返回哪个持仓订单的注释。这个编号是一个从零开始的索引:策略开立的第一个(即最早的)持仓交易编号为0,第二个为1,第三个为2,以此类推。我们可以通过 strategy.opentrades - 1 这个表达式来获取最后一个(即最近的)持仓交易的编号。

这个函数的返回值有两种可能。一是一个字符串,包含了指定持仓交易的开仓订单的注释消息。这里有个细节:如果那个开仓订单没有设置注释,或者注释为空字符串,那么该函数会返回该订单的ID标识符。由于PineScript要求每个订单都必须有一个ID,这意味着 strategy.opentrades.entry_comment() 永远不会返回一个空字符串。二是一个 na 值,这在提供的交易编号不正确(例如,小于0或大于等于当前持仓交易总数),或者策略当前没有任何持仓交易时会发生。

快速示例

要获取第一个(即最早的)持仓交易的注释,我们使用订单编号0:

// 获取策略当前持仓中,第一笔开仓订单的注释
firstEntryOrderComment = strategy.opentrades.entry_comment(0)

要获取最近一笔持仓交易的开仓订单注释,则可以这样使用:

// 获取策略当前持仓中,最后一笔开仓订单的注释
lastEntryComment = strategy.opentrades.entry_comment(strategy.opentrades - 1)

另一个常见的应用是遍历所有持仓交易,并检查它们的注释。这样我们可以寻找特定的注释,或者将所有注释信息汇总起来。例如,假设我们想在一个文本标签中显示所有持仓交易的开仓注释,可以使用一个 for 循环来实现:

// 收集策略所有持仓订单的开仓注释
entryComments = ""
for tradeNumber = 0 to strategy.opentrades - 1
	entryComments += strategy.opentrades.entry_comment(tradeNumber) + "\n"

// 在图表的最后一根K线上,创建一个标签来显示所有注释
if barstate.islast
	label.new(bar_index, high, "当前持仓的开仓注释是:\n" + 
		 entryComments)

应用场景

获取开仓订单的注释可以实现多种功能。比如针对具有特定注释的交易,分别计算它们的盈亏、最大浮盈或回撤,从而评估特定交易设置(子策略)的表现;或者为每个开仓订单的注释赋予不同的交易信号来源(如RSI信号、均线突破),然后通过这个函数来分析当前持仓的构成、交易信号的分布以及各个信号来源的盈亏情况。

我们还可以根据当前持仓订单的注释,来决定下一个交易信号的处理方式,例如在连续两次RSI信号入场后,转而寻找超级趋势信号来作为平仓依据;也可以将开仓订单的类型(如市价、限价、止损)作为注释,通过此函数统计不同订单类型的入场情况,并据此选择合适的平仓策略;甚至可以将开仓时的止损价格作为字符串存入订单注释中,之后取回该价格并与实际入场价进行比较,以衡量滑点。

要让 strategy.opentrades.entry_comment() 能够检索到注释,开仓时就必须为订单添加注释。在PineScript中,我们通过订单函数的 comment 参数来为订单添加注释。可以开仓的两个函数是 strategy.entry()strategy.order(),只需在调用这两个函数时,将其 comment 参数设为一个字符串值即可。

函数的特性

strategy.opentrades.entry_comment() 只对当前持有的交易有效。要获取已平仓交易的入场注释,应改用 strategy.closedtrades.entry_comment() 函数。另外,PineScript无法访问待处理(未成交)订单的注释。

这个函数只返回由策略脚本模拟的交易的注释,无法获取纸上交易或真实经纪商账户的订单信息。它不能在指标(Indicator)脚本中使用,否则会报错,并且是从PineScript版本5开始才可用的函数。

示例策略

让我们通过一个完整的策略来看看如何应用 strategy.opentrades.entry_comment()。下面的脚本在10周期EMA和35周期EMA发生交叉时,同时提交一个多头和一个空头的入场止损单。

我们为这两个订单分别设置了内容为”Enter Long Stop”和”Enter Short Stop”的注释。由于我们无法预知哪个方向会先突破,所以当订单成交后,我们可以检查它的注释来判断交易的方向。我们通过 strategy.opentrades.entry_comment() 来获取这个注释,并利用这些信息来为图表背景上色。

该策略的完整代码如下:

//@version=5
strategy(title="Open entry comment example", overlay=true)

// 计算并绘制指数移动平均线 (EMA)
fastEMA = ta.ema(close, 10)
slowEMA = ta.ema(close, 35)
plot(fastEMA, color=color.orange, title="Fast EMA")
plot(slowEMA, color=color.teal, linewidth=2, title="Slow EMA")

// 如果均线交叉,则生成一个多头和一个空头的入场止损单
if ta.cross(fastEMA, slowEMA)
    strategy.entry("Enter Long", strategy.long, stop=high + ta.tr, 
         comment="Enter Long Stop", oca_name="ema-entry", 
		 oca_type=strategy.oca.cancel)
    strategy.entry("Enter Short", strategy.short, stop=low - ta.tr, 
         comment="Enter Short Stop", oca_name="ema-entry", 
		 oca_type=strategy.oca.cancel)

// 当价格穿越快线时,平掉所有仓位
if ta.cross(close, fastEMA)
    strategy.close_all()

// 获取最近一笔持仓交易的注释
lastEntryComment = strategy.opentrades.entry_comment(
     strategy.opentrades - 1)

// 根据持仓交易的注释来确定背景颜色
backgroundColour = if str.contains(lastEntryComment, "Long")
    color.new(color.green, 85)
else if str.contains(lastEntryComment, "Short")
    color.new(color.red, 90)

bgcolor(backgroundColour)

我们首先用 strategy() 函数配置脚本属性。然后计算并绘制两条EMA均线。当 ta.cross() 检测到均线交叉时,我们通过 strategy.entry() 同时提交两个方向相反的入场止损单。这两个订单被放入同一个OCA订单组中,确保只有一个能最终成交。

接着,我们获取已成交订单的注释:

// 获取最近一笔持仓交易的注释
lastEntryComment = strategy.opentrades.entry_comment(
     strategy.opentrades - 1)

然后,我们利用这个注释来为图表背景上色:

// 根据持仓交易的注释来确定背景颜色
backgroundColour = if str.contains(lastEntryComment, "Long")
    color.new(color.green, 85)
else if str.contains(lastEntryComment, "Short")
    color.new(color.red, 90)

bgcolor(backgroundColour)

我们使用 str.contains() 函数来检查注释中是否包含”Long”或”Short”字符串。如果包含”Long”,背景就设为绿色;如果包含”Short”,则设为红色。bgcolor() 函数将这个颜色应用到图表背景上,从而直观地展示当前持仓的方向。

该策略在图表上的效果如下:

简单总结一下:strategy.opentrades.entry_comment() 函数返回一个特定持仓交易的注释。该函数返回的是一个非空的字符串,这个字符串要么是开仓时设置的 comment 参数值,要么在未设置注释时返回该订单的ID。我们需要为函数提供一个交易编号(索引),以指定要获取哪个交易的注释。这个交易编号从0开始,代表第一个(最早的)持仓交易,最高的交易编号是 strategy.opentrades - 1,代表最后一个(最近的)交易。

赞(0)
未经允许不得转载:图道交易 » Pine Script(228):获取未平仓订单的佣金与入场注释
分享到

评论 抢沙发

登录

找回密码

注册