获取未平仓订单的ID标识符
当一个策略持有仓位时,我们可以使用 strategy.opentrades.entry_id() 函数来获取某一个特定开仓订单的订单ID。这个ID就是我们在开仓时为该笔交易设定的名称。
获取到这个订单ID后,我们可以实现多种功能,例如:通过标签或表格在图表上显示订单的ID;使用这个ID来生成一个特定的平仓指令,以平掉某一笔开仓订单(可以通过 strategy.exit() 或 strategy.close() 函数实现);遍历所有开仓订单,并只处理那些具有特定名称的订单,比如单独计算所有名为”Enter Long”的订单的总利润或总数量;或者根据订单ID将所有开仓订单分组,分别报告它们各自的浮动盈利和回撤。
默认语法结构
该函数的标准语法如下:
strategy.opentrades.entry_id(trade_num)
trade_num 是一个整数,用于指定你想查询哪一笔开仓订单的ID。这个订单编号采用从零开始的索引方式:第一笔开仓订单的编号是0,第二笔是1,第三笔是2,以此类推。要获取最后一笔(即最新一笔)开仓订单的编号,我们可以使用 strategy.opentrades - 1。
这个函数的返回值有两种可能:一是返回一个字符串,即指定开仓订单的ID;二是返回 na 值,这在传入的订单编号 trade_num 不正确(例如小于0,或大于等于当前开仓订单的总数 strategy.opentrades),或者策略当前没有任何持仓时会发生。
快速示例
要获取第一笔开仓订单(即最早的那一笔)的ID,我们可以这样做:
// 获取第一笔入场订单的ID
firstOrderID = strategy.opentrades.entry_id(0)
要获取最后一笔开仓订单(即最新的一笔)的ID,可以这样使用:
// 获取最新一笔入场订单的ID
lastOrderID = strategy.opentrades.entry_id(strategy.opentrades - 1)
我们也可以处理所有开仓订单的ID,这需要通过 for 循环来遍历它们。例如,假设我们想在图表上显示所有开仓订单的ID。我们可以创建一个循环,将每个订单的ID拼接成一个字符串,然后在图表上用一个标签显示出来。代码示例如下:
// 遍历所有开仓订单,并将它们的ID拼接成一个字符串
orderIds = ""
for tradeNumber = 0 to strategy.opentrades - 1
// 如果不是最后一个ID,则在后面加上逗号和空格
strSuffix = tradeNumber == strategy.opentrades - 1 ? "" : ", "
orderIds += strategy.opentrades.entry_id(tradeNumber) + strSuffix
// 在图表上显示拼接后的结果
label.new(bar_index, high, orderIds)
函数的特性
strategy.opentrades.entry_id() 返回的订单ID,就是我们之前通过 strategy.entry() 或 strategy.order() 函数在开仓时设定的那个名称。此函数只返回已成交、且当前仍持有的订单的ID,我们无法通过它获取尚未成交的挂单的ID。
这个函数是自PineScript版本5起才可用的新功能,在版本4及更早的版本中不存在。此外,它只能在策略(strategy)脚本中使用。如果在指标(indicator)代码中调用它,PineScript会报错:'You cannot use strategy functions (strategy.opentrades.entry_id) in indicator script.'。
示例策略
让我们通过一个完整的策略来看看如何使用 strategy.opentrades.entry_id() 函数。下方的脚本基于一个平滑处理后的EMA进行交易。当价格连续两根K线收于均线之上或之下时,我们开立多仓或空仓。
每当有新的入场交易发生时,我们便使用 strategy.opentrades.entry_id() 来获取该笔交易的ID。然后,我们根据ID的名称(多头或空头),在图表上用不同颜色的标签来显示这个ID。
策略的完整代码如下:
//@version=5
strategy(title="获取开仓交易的入场ID", overlay=true)
// 计算并绘制平滑EMA
smoothEMA = ta.ema(ta.ema(close, 20), 5)
plot(smoothEMA, color=color.lime, linewidth=2, title="平滑EMA")
// 当连续两根K线收于均线之上/下时,开多/空仓
if close > smoothEMA and close[1] > smoothEMA[1]
strategy.entry("Enter Long", strategy.long)
if close < smoothEMA and close[1] < smoothEMA[1]
strategy.entry("Enter Short", strategy.short)
// 通过总交易数的变化来判断是否有新交易入场
totalTrades = strategy.closedtrades + strategy.opentrades
newEntry = totalTrades > totalTrades[1] and strategy.opentrades > 0
// 当有新交易入场时,创建一个文本标签
if newEntry
// 生成标签文本,包含第一笔入场的ID和价格
labelText = strategy.opentrades.entry_id(0) + "\n@ " +
str.tostring(strategy.opentrades.entry_price(0))
// 如果入场订单的ID包含 "Long" 这个词,就创建一个绿色标签
// 否则,创建一个红色的、指向上方的标签
if str.contains(strategy.opentrades.entry_id(0), "Long")
label.new(bar_index, high, color=#D0F0C0, text=labelText)
else
label.new(bar_index, low, color=#FDBCB4, text=labelText,
style=label.style_label_up)
我们首先计算并绘制了一个平滑EMA。入场逻辑是当价格连续两根K线站上或跌破该均线时,分别开立名为”Enter Long”或”Enter Short”的仓位。
接下来,我们通过比较当前K线的总交易数(strategy.closedtrades + strategy.opentrades)与上一根K线的总交易数,来判断是否有新的交易发生。
最后,我们处理订单ID的显示逻辑:
// 当有新交易入场时,创建一个文本标签
if newEntry
// ...
当 newEntry 条件为真时,我们执行两个操作。第一步是生成标签文本:我们将第一笔开仓订单(编号0)的ID和价格拼接成一个字符串,分别使用 strategy.opentrades.entry_id(0) 和 strategy.opentrades.entry_price(0) 来获取这两个信息。第二步是根据ID创建不同颜色的标签:我们使用 str.contains() 函数来检查第一笔订单的ID是否包含”Long”这个词。如果包含,我们就创建一个绿色的标签,显示在K线的最高价处;如果不包含(即为空头订单),我们就创建一个红色的、指向上方的标签,显示在K线的最低价处。
根据策略第一笔开仓订单的ID,脚本会在图表上创建绿色或红色的标签。效果如下:
简单总结一下:strategy.opentrades.entry_id() 函数返回某一个特定开仓订单的订单ID(名称)。我们通过一个订单编号来告知函数我们想要查询哪一笔订单。订单编号从0开始,代表第一笔开仓的交易,并以 strategy.opentrades - 1 结束,代表最后一笔(即最新一笔)入场交易。
获取未平仓订单的入场时间
当一个策略持有仓位时,我们可以通过 strategy.opentrades.entry_time() 函数来获取某个特定持仓订单的入场时间。这个函数能告诉我们一个订单是在哪个具体的日期和时间开仓的。
了解一个订单的入场时间在多种场景下都很有用,例如:查看距离仓位中第一笔订单的入场已经过去了多长时间,或者测量自最近一次加仓以来经过了多久;计算连续开仓订单之间的时间间隔;计算所有在数小时前入场的持仓订单的当前盈亏、最大回撤和最大浮盈。
标准语法格式
该函数的标准语法格式如下:
strategy.opentrades.entry_time(trade_num)
trade_num 是持仓订单的编号。这个整数参数告诉PineScript要返回哪个持仓订单的入场时间。这个编号是一个从零开始的索引:策略开立的第一个订单编号为0,第二个为1,第三个为2,以此类推。我们可以通过 strategy.opentrades - 1 来获取最后一个(即最近的)持仓订单的编号。
这个函数的返回值有两种可能:一是一个时间值,代表订单开仓的日期和时间——PineScript中的时间值是以自1970年1月1日00:00:00 UTC以来的毫秒数来表示的;二是一个 na 值,这在提供的订单编号不正确,或者策略当前没有任何持仓交易时会发生。
快速示例
要获取仓位中第一笔(即最早的)订单的入场时间,我们使用订单编号0:
// 获取持仓中第一笔订单的入场时间
firstEntryTime = strategy.opentrades.entry_time(0)
要获取最近一笔订单的入场时间,则可以这样使用:
// 获取最后一笔(即最近的)订单的入场时间
lastEntryTime = strategy.opentrades.entry_time(strategy.opentrades - 1)
另一个常见的应用是遍历所有持仓订单。例如,我们可以计算所有持仓订单的平均入场时间。为此,我们使用一个 for 循环来遍历所有订单,在循环中将每个订单的入场时间累加起来,最后除以订单总数即可:
// 对当前所有持仓交易的入场时间进行求和
entryTimeSum = 0
for tradeNumber = 0 to strategy.opentrades - 1
entryTimeSum += strategy.opentrades.entry_time(tradeNumber)
// 计算平均入场时间(以自1970年1月1日以来的毫秒数表示)
avgEntryTime = entryTimeSum / strategy.opentrades
返回的是K线时间,而非精确的订单成交时间
关于 strategy.opentrades.entry_time() 的一个重要特性:它返回的并不是订单确切的成交时间,而是订单成交所在那根K线的开盘时间。
这个近似值是否会带来问题,取决于具体情况。如果订单是在K线开盘时成交的,那么该函数给出的入场时间是准确的(因为TradingView的K线时间戳就是基于K线的开盘时间)。而如果订单是在K线内部的某个时间点成交的,那么该函数返回的就不是实际的入场时间,而只是一个估计值。在较长的时间周期上,这种误差会更明显。
总的来说,PineScript通常会高估一个订单的持仓时间。因为即使订单是在K线快收盘时才成交,strategy.opentrades.entry_time() 返回的仍然是这根K线在很久之前开盘的时间。
函数的特性
strategy.opentrades.entry_time() 返回的是毫秒数,这种格式通常不便于我们直接使用。为了使其更实用,我们通常需要将其转换为秒、分钟、小时或天。
另一个容易踩坑的地方是时区:这个函数返回的时间是UTC时区。这一点与PineScript中几乎所有其他处理时间的变量和函数形成对比,后者大多使用交易品种所在交易所的时区。
此外,如果多个订单在同一根K线上成交,它们都会有相同的返回值,即使它们的实际成交时间点不同。这个函数是从PineScript版本5开始才可用的,且不能在指标(Indicator)脚本中使用,否则会报错。
示例策略
让我们看一个使用 strategy.opentrades.entry_time() 函数的完整策略。下面的脚本基于近期高低点的突破进行交易。当策略持仓时,它会每隔10根K线计算一次自第一笔订单入场以来经过了多少分钟,以此来展示仓位的持有时间。
该策略的完整代码如下:
//@version=5
strategy(title="Open trade entry time", overlay=true)
// 计算并绘制近期高低点
highestHigh = ta.highest(high, 20)[1]
lowestLow = ta.lowest(low, 20)[1]
plot(highestHigh, color=color.green, title="Highest High")
plot(lowestLow, color=color.red, title="Lowest Low")
// 生成突破交易
if high > highestHigh
strategy.entry("Enter Long", strategy.long, stop=close)
if low < lowestLow
strategy.entry("Enter Short", strategy.short)
// 当有持仓时,每10根K线显示一次自初始入场以来的分钟数
if strategy.position_size != 0 and bar_index % 10 == 0
minutesSinceEntry = (time - strategy.opentrades.entry_time(0)) / (60 * 1000)
label.new(bar_index, high, color=color.black, textcolor=color.white,
text=str.tostring(minutesSinceEntry) + " 分钟\n持仓时间")
我们首先用 strategy() 函数配置脚本属性。然后计算并绘制20周期的高低点通道。接着,两个 if 语句根据价格是否突破通道来提交开仓订单。
最后,我们报告当前仓位的持有时间:
// 当有持仓时,每10根K线显示一次自初始入场以来的分钟数
if strategy.position_size != 0 and bar_index % 10 == 0
minutesSinceEntry = (time - strategy.opentrades.entry_time(0)) / (60 * 1000)
label.new(bar_index, high, color=color.black, textcolor=color.white,
text=str.tostring(minutesSinceEntry) + " 分钟\n持仓时间")
这个 if 语句检查两个条件:策略是否有持仓(strategy.position_size != 0),以及当前K线的编号是否是10的整数倍(bar_index % 10 == 0)。当两个条件都满足时,代码块执行。
在代码块中,我们首先计算自第一笔订单入场以来经过的分钟数。我们用当前K线的开盘时间(time)减去第一笔订单的入场时间(strategy.opentrades.entry_time(0))。这个结果是毫秒数。为了将其转换为分钟,我们再除以 (60 * 1000)。
然后,label.new() 函数创建一个文本标签,在图表上显示这个持仓分钟数。在图表上,策略会每隔10根K线报告一次自初始入场以来的分钟数。效果如下:
简单总结一下:strategy.opentrades.entry_time() 函数返回一个特定持仓订单的入场时间。一个订单编号参数告诉函数要返回哪个订单的数据,第一个订单使用0,最后一个订单使用 strategy.opentrades - 1。该函数返回的时间是一个以毫秒为单位的UTC时间戳,且返回的并不是订单确切的成交时间,而是其成交所在K线的开盘时间。




