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

Pine Script(124):时间差单位转换,从毫秒到秒分钟小时天周月

#Pine Script入门教学

将时间差转换为秒、分钟、小时等单位

TradingView的Pine脚本语言以毫秒为单位来测量时间。虽然这种方式非常精确,但它也使得我们要处理的数值非常巨大。下面我们来看看如何将这些值转换为像秒、分钟和小时这样的单位。

将TradingView的时间跨度转换为不同单位

TradingView测量时间的方式源自所谓的Unix time值。在TradingView中,这些值代表的是自1970年1月1日以来所经过的毫秒数。虽然这很精确,但也导致数值非常巨大,而且这些巨大的数值本身难以阅读和理解。

幸运的是,将毫秒转换为分钟、小时或天数并不需要很多代码。让我们看看在TradingView中该如何操作。

注意事项

在本文中,我们将一个TradingView的时间差转换为总秒数、总分钟数或总小时数。通过这种方式,我们可以将180000毫秒转换为3分钟或180秒。

如果你希望计算诸如2分20秒或1小时15分45秒这样的复合格式,可以参考下一篇里的做法。

获取TradingView时间差的总秒数

一秒钟有1,000毫秒。所以,如果我们有一个TradingView的时间跨度并想知道它等于多少秒,我们只需将其除以1000即可。

这里是一个快速范例:

// 计算最近5根K线的时间差
timeDiff = time - time[5]

// 将该时间段转换为秒
diffSeconds = timeDiff / 1000

// 输出计算出的时间差
plot(diffSeconds)

这里,我们首先创建 timeDiff 变量,它保存了当前K线的开盘时间(time)与5根K线前的开盘时间(time[5])之间的差值。然后,我们将该变量除以1000,并将结果存储在 diffSeconds 中。这样,我们就得到了这两根K线之间相隔的秒数。最后一行代码则将这个值绘制在图表上。

我们也可以将上面的代码封装成一个函数。如果我们需要重复地将毫秒转换为秒,这样做会更方便。代码如下所示:

// ToSeconds() 函数返回给定毫秒时间跨度的总秒数
ToSeconds(ts) => ts / 1000

// SecondsBetween() 函数返回两个给定时间值之间的总秒数
SecondsBetween(t1, t2) => (t1 - t2) / 1000

以下是如何在我们的代码中使用这些函数:

// 获取自K线开盘以来经过的秒数
secsOpen = ToSeconds(timenow - time)

// 获取前一根K线的持续秒数
prvSeconds = SecondsBetween(time[1], time_close[1])

从TradingView时间跨度计算分钟数

一分钟有60,000毫秒。因此,要将一个TradingView的时间差转换为分钟数,我们将其除以60000。

下面是一个代码片段:

// 获取最近30根K线的时间差
timeDiff = time - time[30]

// 将该时间跨度转换为分钟
diffMinutes = timeDiff / 60000

// 输出计算出的时间差
plot(diffMinutes)

这段代码首先计算当前K线(time)和30根K线之前(time[30])的时间差,我们将该值存储在 timeDiff 变量中。接下来,我们将该变量除以60000,从而将毫秒转换为分钟。然后,我们用这些值在图表上创建一个绘图。

当我们需要重复这项工作时,一个自定义函数可以节省代码编写量。以下是上述代码的函数形式:

// ToMinutes() 函数返回给定毫秒时间跨度的总分钟数
ToMinutes(ts) => ts / 60000

// MinutesBetween() 函数返回两个给定时间值之间的总分钟数
MinutesBetween(t1, t2) => (t1 - t2) / 60000

要使用这些函数,我们可以这样做:

// 获取自这根K线开盘以来经过的分钟数
sinceOpen = ToMinutes(timenow -  time)

// 获取K线的持续分钟数
barDuration = MinutesBetween(time_close, time)

获取TradingView时间差的总小时数

一小时包含3,600,000毫秒。所以,要从TradingView的时间跨度得到小时数,我们将其除以3600000。

这里是一个快速范例:

// 获取当前K线与50根K线前的时间差
timeDiff = time - time[50]

// 将该差异转换为小时数
diffHours = timeDiff / 3600000

// 输出计算出的时间差
plot(diffHours)

首先,我们计算一个时间差。这里我们关注的是当前K线的开盘时间(time)与50根K线之前的那个时间(time[50])之间的差距。为了知道这等于多少小时,我们将其除以3600000。我们将结果存储在一个变量中,然后使用 plot() 将其绘制在图表上。

在同一个脚本中多次编写上述代码会很快变得乏味。幸运的是,我们可以轻松地将上面的代码封装成自定义函数:

// ToHours() 函数返回给定毫秒时间跨度的总小时数
ToHours(ts) => ts / 3600000

// HoursBetween() 函数返回两个给定时间值之间的总小时数
HoursBetween(t1, t2) => (t1 - t2) / 3600000

现在,要使用这些函数,我们只需键入:

// 获取当前K线与100根K线前之间的总小时数
hoursCount = HoursBetween(time, time[100])

// 获取自上一根K线收盘以来经过的小时数
hoursPassed = ToHours(timenow - time_close[1])

从TradingView时间差获取天数

一天(即一个24小时的时间段)包含86,400,000毫秒。因此,要将一个TradingView的时间差转换为天数,我们将其除以86400000。

下面是一个代码片段:

// 将第一根K线的时间存储在变量中
var firstBarTime = time

// 获取当前K线与第一根K线
// 之间的时间差
timeDiff = time - firstBarTime

// 将该时间差转换为天数
diffDays = timeDiff / 86400000

// 显示计算出的时间差
plot(diffDays)

我们首先获取图表第一根K线的时间。我们为此使用了 var 关键字,这样做是有效的,因为该声明只会在脚本首次加载时执行一次。然后,我们用当前K线的时间(time)减去第一根K线的时间。下一步,我们将这个时间跨度除以86400000来得到天数。最后 plot() 函数在图表上绘制该值。

我们也可以将这些计算步骤封装到一个自定义的TradingView函数中。这样我们就不必一遍又一遍地重复相同的代码了。以下是两个示例函数:

// ToDays() 函数返回给定毫秒时间跨度的总天数(24小时时段)
ToDays(ts) => ts / 86400000

// DaysBetween() 函数返回两个给定时间值之间的总天数(24小时时段)
DaysBetween(t1, t2) => (t1 - t2) / 86400000

要使用这些函数,我们可以这样做:

// 获取最近100根K线之间的总天数
daysCount = DaysBetween(time, time[100])

// 查看自300根K线前以来经过的天数
daysPassed = ToDays(timenow - time[300])

从TradingView时间差计算周数

一周(即七个24小时的时间段)有604,800,000毫秒。所以,要将一个TradingView的时间跨度转换为周数,我们将其除以604800000。

实现该功能的代码如下:

// 将第一根K线的时间放入变量
var firstBarTime = time

// 获取当前K线与第一根K线
// 之间的时间差
timeDiff = time - firstBarTime

// 将该时间差转换为周数
diffWeeks = timeDiff / 604800000

// 显示计算出的时间差
plot(diffWeeks)

这里我们再次使用 var 关键字获取第一根K线的时间。下一步,我们用当前K线的时间(time)减去那根更早的K线的时间,结果是一个TradingView时间差,然后我们将其除以604800000来得到周数。我们用 plot() 在图表上显示该值。

为了方便和高效,我们可以将上述代码封装到一个自定义函数中。代码如下所示:

// ToWeeks() 函数返回给定毫秒时间跨度的总周数(7x24小时时段)
ToWeeks(ts) => ts / 604800000

// WeeksBetween() 函数返回两个给定时间值之间的总周数(7x24小时时段)
WeeksBetween(t1, t2) => (t1 - t2) / 604800000

要使用这些函数,我们可以这样做:

// 获取最近250根K线之间的总周数
weeksCount = WeeksBetween(time, time[250])

// 获取自第一根K线以来的周数
var timeFirstBar = time
weeksPassed = ToWeeks(timenow - timeFirstBar)

从TradingView时间差确定月数

如果我们假定一个月有30.42天(365天除以12个月),那么一个月会经过2,628,000,000毫秒。所以,要将一个TradingView的时间跨度转换为月数,我们将其除以2628000000。

这里是一个例子:

// 将第一根K线的时间放入变量
var firstBarTime = time

// 获取第一根与当前K线
// 之间的时间差
timeDiff = time - firstBarTime

// 将该时间差转换为月数
diffMonths = timeDiff / 2628000000

// 显示计算出的时间差
plot(diffMonths)

这段代码再次使用 var 存储了第一根K线的时间。然后我们取当前K线的时间(time)减去第一根K线的时间,结果是一个TradingView时间差,我们将其除以2628000000,这会告诉我们自第一根K线以来经过了多少个月。我们用 plot() 函数在图表上显示该数据。

注意事项

如果你想将一个月定义为4周的时间段,那么应除以2419200000。这是一个28天时间段内所包含的毫秒数。

我们也可以将上述代码包装在函数中,这样可以更方便地重复执行这些计算。代码如下所示:

// ToMonths() 函数返回给定毫秒时间跨度的总月数(假设每月30.42天)
ToMonths(ts) => ts / 2628000000

// MonthsBetween() 函数返回两个给定时间值之间的总月数(假设每月30.42天)
MonthsBetween(t1, t2) => (t1 - t2) / 2628000000

我们像这样使用这些函数:

// 查看最近500根K线经过了多少月
monthsPassed = MonthsBetween(time, time[500])

// 获取自第一根K线以来的月数
var timeFirstBar = time
monthCount = ToMonths(time - timeFirstBar)

总结

通过两个步骤,我们可以计算出两个TradingView时间点之间经过了多长时间。首先,我们用一个时间减去另一个,这会得到一个TradingView时间格式的时间跨度。然后,我们将该值除以我们期望的时间单位所包含的毫秒数。

所以,要得到秒数,我们除以1000;要得到分钟数,我们用60000;小时数需要3600000;天数则需要86400000。

将时间差转换为分钟和秒的组合格式

TradingView的时间值以毫秒为单位来测量时间。不幸的是,这会导致数值非常巨大且难以阅读。下面我们来看看如何将这些值转换为分钟和秒(以及更多单位)。

将TradingView时间转换为多个时间单位

我们的TradingView脚本所处理的时间,是以自1970年1月1日以来的毫秒数来报告的。这种基于Unix的时间格式有几个优点:比较时间很方便,用时间进行计算也很容易。

但这些时间值可能变得非常巨大,难以处理。例如,即便是22分40秒这样一个很小的时间段,也已经是1,360,000毫秒。这使得它们不易于使用,也难以从图表上快速读取。

幸运的是,有一个很好的替代方案:将毫秒转换为其他时间单位的组合,例如分钟和秒。通过这种方式,我们摆脱了巨大而抽象的数值,得到了更具可操作性的数据。本文中的代码范例将展示如何在TradingView中实现这一点。

这些范例中的每一个都遵循相同的通用模式:

  1. 首先处理最大的时间单位(例如天)。然后计算出这个TradingView时间值中可以容纳多少个完整的天数。
  2. 接着处理下一个较大的时间单位(例如小时)。计算在减去之前已经算过的天数后,剩余的时间可以容纳多少个完整的小时数。
  3. 对其他时间单位重复第2步。最小的时间单位(例如秒)就是无法容纳进其他更大时间单位的剩余时间。

现在,让我们看看如何将这些步骤转换为TradingView代码。

注意事项

本文将一个TradingView时间转换为多个时间单位的组合,例如分钟和秒。如果你只想得到一个时间单位(例如总分钟数),参考上一节的做法即可。

从TradingView时间中获取分钟和秒

比方说,我们想得到两根价格K线之间相隔的分钟和秒数。为此,我们首先将两个TradingView时间值相减,这会告诉我们这两个时间点之间相差的毫秒数。然后,我们将其转换为完整的分钟数。下一步,我们再计算还剩余多少秒。

实现该功能的TradingView代码如下:

// 获取当前K线与20根K线前
// 之间的时间差
timeDiff = time - time[20]

// 将该时间差转换为
// 分钟和秒数
timeSeconds = math.round(timeDiff / 1000)
minsLeft = math.floor(timeSeconds / 60)
secsLeft = timeSeconds % 60

// 在图表上显示数值
plot(minsLeft, title="Minutes left")
plot(secsLeft, title="Seconds left")

首先,我们用 time 变量获取当前K线和20根K线前的时间,并将时间差存入 timeDiff 变量。

然后,我们通过除以1000将毫秒转换为秒。在使用 math.round() 进行四舍五入后,我们将该值存储在 timeSeconds 变量中。

要查看这等于多少分钟,我们将该变量除以60。由于我们会单独报告秒数,这里我们使用 math.floor() 函数进行向下取整(这样,33.75分钟就会变为33分钟)。我们将这个结果存入 minsLeft 变量。

接下来我们获取秒数。但由于我们已经计算了分钟数,我们现在需要知道的是剩余的秒数。为了得到这个答案,我们使用取模运算符(%)。该运算符可以找到一个数被另一个数整除后的余数。

在这种情况下,当我们将总时间(timeSeconds)除以60(一分钟的秒数)时,得到的余数就是剩余的秒数。比方说,总时间是2245秒。用它除以60,我们得到37(分钟),余数为25(秒)。由于我们之前已经计算了完整的分钟数,所以在这一步中我们感兴趣的就是这个余数。

注意事项

上述代码中的 math.round() 函数可能看起来有点奇怪。理论上,应该不需要进行四舍五入,因为TradingView目前只报告整秒的时间(即完整的1000毫秒间隔)。

但当我在为本文测试代码时,我偶尔会遇到TradingView时间差中存在1毫秒的差异。这个微小的差异会导致代码报告出像剩余60秒这样不准确的结果。因此,math.round() 确保了我们的脚本处理的是(例如)235秒,而不是234.99999999999这样的浮点数。

重构为自定义TradingView函数

为了能方便地重复使用上述代码,我们也可以将其重写为一个函数。代码如下所示:

// ToMinsSecs() 函数将一个时间跨度转换为
// 分钟 *和* 秒的总数
ToMinsSecs(ts) =>
    secsLeft = math.round(ts / 1000) // 为可能的1ms差异进行舍入
    [math.floor(secsLeft / 60), secsLeft % 60]

要使用这个自定义函数,我们可以这样做:

// 获取自20根K线前以来的分钟和秒数
[minsLeft, secsLeft] = ToMinsSecs(time - time[20])

// 在图表上显示数值
plot(minsLeft, title="Minutes left")
plot(secsLeft, title="Seconds left")

从TradingView时间中获取秒、分和小时

当然,我们也可以从一个TradingView时间值中获取秒、分和小时。这需要与前一个范例相同的处理流程:首先计算有多少个完整的小时;然后,在考虑了小时数的基础上计算分钟数;最后,再计算还剩下多少秒。

实现该功能的TradingView代码如下:

// 获取当前K线与10根K线前
// 之间的时间差
timeDiff = time - time[10]

// 将该时间差转换为
// 小时、分钟和秒
timeSeconds = math.round(timeDiff / 1000)

totalHours   = math.floor(timeSeconds / 3600)
totalMinutes = math.floor((timeSeconds % 3600) / 60)
totalSeconds = timeSeconds % 60

// 在图表上显示数值
plot(totalHours, title="Hours")
plot(totalMinutes, title="Minutes")
plot(totalSeconds, title="Seconds")

这里,我们首先获取当前K线和10根K线前的时间差。然后我们通过除以1000将该值转换为秒数,并将其存储在 timeSeconds 变量中供后续使用。

要查看有多少小时,我们将该变量除以3600(一小时的秒数)。math.floor() 函数将结果向下取整为完整的小时。毕竟,在这一步我们只关心完整的小时数。

然后我们计算分钟数。由于已经得出了小时数,我们现在需要看有多少秒没能凑成一个完整的小时。因此,我们使用取模运算符(%)返回总秒数(timeSeconds)除以3600后的余数。然后我们将这个余数除以60来得到分钟数。我们使用 math.floor() 将该值向下取整为完整的分钟。

最后一部分是秒数。由于我们已经得到了分钟数,在这一步我们计算有多少秒没能凑成一个完整的分钟。为此,我们取 timeSeconds 除以60的余数(%)。

重写为自定义TradingView函数

如果你需要重复地获取秒、分和小时,上面的代码会有点麻烦。幸运的是,我们可以轻松地将其转换为一个自定义函数。方法如下:

// ToHrsMinsSecs() 函数将一个时间跨度转换为
// 小时、分钟 *和* 秒数
ToHrsMinsSecs(ts) =>
    timeSeconds = math.round(ts / 1000) // 为可能的1ms差异进行舍入
    [math.floor(timeSeconds / 3600),
         math.floor((timeSeconds % 3600) / 60),
         timeSeconds % 60]

要使用这个函数,我们可以这样做:

// 获取自10根K线前以来的时、分和秒
[totalHours, totalMinutes, totalSeconds] = ToHrsMinsSecs(time - time[10])

// 在图表上显示数值
plot(totalHours, title="Hours")
plot(totalMinutes, title="Minutes")
plot(totalSeconds, title="Seconds")

从TradingView时间中获取分钟和小时

另一种选择是从一个TradingView时间值中获取分钟和小时。要实现这一点,我们首先计算有多少个完整的小时,然后再看有多少个完整的分钟。

我们编写以下代码来实现该行为:

// 获取当前K线与
// 50根K线前的时间差
timeDiff = time - time[50]

// 将该时间差转换为
// 分钟和小时数
timeSeconds = math.round(timeDiff / 1000)
hrsTime  = math.floor(timeSeconds / 3600)
minsTime = math.floor((timeSeconds % 3600) / 60)

// 在图表上显示数值
plot(hrsTime, title="Hours")
plot(minsTime, title="Minutes")

这里,我们获取两根K线的时间差,然后将其除以1000得到总秒数,并存入 timeSeconds 变量。

要从这个时间间隔中得到小时数,我们将总秒数除以3600,并使用 math.floor() 向下取整。毕竟,我们接下来会用分钟来表示不足一小时的部分。

对于分钟数,我们首先用 timeSeconds 对3600取模(%),这会告诉我们有多少秒没能凑成一个完整的小时。然后我们将其除以60,就知道这等于多少分钟了。

我们将后一个计算也封装在 math.floor() 函数内部,这使得代码只报告完整的分钟数。这样做虽然会损失一些精度(我们舍弃了秒),但图表上的格式看起来会更美观:例如,显示为1小时32分钟,而不是1小时32.42分钟。

重构为自定义TradingView函数

每次需要时都输入上面的代码有点多余。所以,让我们把它封装成一个拿来即用的自定义函数:

// ToHrsMins() 函数将一个时间跨度转换为
// 小时和整分钟数
ToHrsMins(ts) =>
    timeSeconds = math.round(ts / 1000) // 为可能的1ms差异进行舍入
    [math.floor(timeSeconds / 3600), math.floor((timeSeconds % 3600) / 60)]

以下是如何使用该函数:

// 获取自50根K线前以来的小时和分钟
[totalHours, totalMinutes] = ToHrsMins(time - time[50])

// 在图表上显示数值
plot(totalHours, title="Hours")
plot(totalMinutes, title="Minutes")

从TradingView时间中获取分、时和天

还有一个选择是将一个TradingView时间转换为分、时和天。为此,我们取一个时间差,看它包含多少天(即,86,400秒的24小时时间段)。从剩余的时间中,我们首先提取小时数。然后,我们再报告无法计入天和小时的剩余时间的分钟数。

以下是如何在TradingView中编写该代码:

// 获取当前K线与150根K线前
// 之间的时间差
timeDiff = time - time[150]

// 将该时间跨度转换为
// 天、时、分
timeSeconds  = math.round(timeDiff / 1000)
totalDays    = math.floor(timeSeconds / 86400)
totalHours   = math.floor((timeSeconds % 86400) / 3600)
totalMinutes = math.floor((timeSeconds % 3600) / 60)

// 在图表上显示时间
plot(totalDays, title="Total days")
plot(totalHours, title="Total hours")
plot(totalMinutes, title="Total minutes")

这段代码首先计算当前K线时间(time)与150根K线前的时间间隔。然后我们通过除以1000将时间差转换为秒数,并将其存储在 timeSeconds 变量中。

接着,我们实现与之前相同的处理流程。我们从最大的时间单位(天)开始,用总秒数除以86400,并使用 math.floor() 函数向下取整结果,这样我们只报告完整的天数。

要计算小时数,我们关注那些没能凑成一整天的秒数(timeSeconds % 86400),然后将其除以3600得到小时数,并用 math.floor() 向下取整。

然后我们必须计算时间跨度有多少分钟。因此,我们使用取模(%)来看当所有秒数除以3600(一小时的秒数)后还剩下多少。然后我们将这些尚未计算的秒数除以60来得到分钟数。

通过 math.floor(),TradingView将该值向下取整为完整的分钟。这会故意损失一些精度(例如3.92分钟被报告为3分钟),但图表上的结果会因此看起来更美观。(或者,你也可以精确地报告秒数;具体方法请参考前面的范例。)

重构为自定义TradingView函数

虽然上面的代码能正常工作,但当我们需要计算多个时间差时,它就不是很高效了。在这种情况下,自定义函数是更好的选择。以下是重构为函数后的代码:

// ToDaysHoursMins() 函数将一个时间跨度转换为
// 天、小时 *和* 分钟数
ToDaysHoursMins(ts) =>
    timeSeconds = math.round(ts / 1000) // 为可能的1ms差异进行舍入
    [math.floor(timeSeconds / 86400),
         math.floor((timeSeconds % 86400) / 3600),
         math.floor((timeSeconds % 3600) / 60)]

要在TradingView指标或策略中使用这个函数,我们可以这样做:

// 获取自300根K线前的天、时和分
[totalDays, totalHours, totalMinutes] = ToDaysHoursMins(time - time[300])

// 在图表上显示时间
plot(totalDays, title="Total days")
plot(totalHours, title="Total hours")
plot(totalMinutes, title="Total minutes")

总结

TradingView的时间差是以毫秒为单位的。通过一些代码,我们可以将它们表示为其他时间单位,例如小时、分钟和秒数的组合。

为此,我们从最大的时间单位(如小时)开始,计算时间跨度包含多少个小时。然后我们处理下一个时间单位(分钟),在考虑了上一步的整小时数后,计算有多少分钟。接下来我们移到更小的时间单位(秒),在考虑了完整的分钟数后计算秒数。经过所有这些步骤,我们就将一个TradingView的时间差转换为了小时、分钟和秒数的组合。

赞(0)
未经允许不得转载:图道交易 » Pine Script(124):时间差单位转换,从毫秒到秒分钟小时天周月
分享到

评论 抢沙发

登录

找回密码

注册