通过算法检测时间序列中的跳跃

Algorithmically detecting jumps in a time-series

我有大约 50 个数据集,其中包括 30 天时间范围内 5 个交易所的大约 10 个交易对的所有交易。所有对都属于相同的资产 class,这意味着它们具有很强的相关性并且期望具有相似的属性,但规模不同。此数据的一个示例是

set.seed(1)

n <- 1000
dates <- seq(as.POSIXct("2019-08-05 00:00:00", tz="UTC"), as.POSIXct("2019-08-05 23:59:00", tz="UTC"), by="1 min")
x <- data.frame("t" = sort(sample(dates, 1000)),"p" = cumsum(sample(c(-1, 1), n, TRUE)))

粗略地说,我需要确定每天发生的相关局部最小值和最大值。黄色标记是我的兴趣点。与此示例不同,通常每天只有一个这样的点,我会分别考虑每一天。但是,很难从我的实际兴趣点中滤除噪音。

我的实际目标是找到两人开始跳跃的确切点和跳跃结束的确切点。这需要尽可能准确,因为我想观察哪个资产先移动,哪个资产在哪个时间点跟随(如上所述,它们高度相关)。 在两个极值之间,我想最小化距离并最大化 relative/absolute 变化,因为我的兴趣点通常彼此靠近并且它们的差异很大。

我已经看过其他问题,例如 Finding local maxima and minima and Algorithm to locate local maxima and also this 具有相同目标的算法。但是,我的数据集非常嘈杂。我已经将数据集减少到 5 分钟的间隔,但是,这导致省略了函数中的相关点以识别局部最小值和最大值。因此,考虑到我的目标,这不是一个好的解决方案。

如何使用相当准确的算法实现我的目标?手动浏览所有时间序列不是一种选择,因为这需要我手动评估 50 * 30 时间序列,这太耗时了。真是百思不得其解,想了一个星期才找到合适的解决方案。

如果需要更多代码片段,我很乐意分享,但是它们没有给我有意义的结果,这与提供最小工作示例的想法背道而驰,因此我决定将它们排除在外现在。

编辑: 首先,我更新了绘图并向数据集添加了时间戳,以便让您了解(实际分辨率)。理想情况下,该算法会检测到左侧的两次跳跃。内部的两个点是因为它们靠得更近并且在没有拦截的情况下跳跃,而外部的点是因为它们的值更极端。事实上,这可能回答了是否允许算法展望未来的问题。是的,如果在例如 30 次观察(或 30 分钟)的范围内存在另一个局部极值,则忽略中间的局部极值。 在我的数据中,跳跃从 2% - ~ 15%,因此跳跃至少需要 2% 才能被考虑。并且只有在达到峰值和谷值之前/之后在同一方向上连续执行 15 个阈值(这可能是适应性的)。

一种非常幼稚的方法是围绕一天的全局最小值和最大值对数据进行子集化。在大多数情况下,这已经对数据进行了去噪并用作指标。但是,当全局极值不在跳跃范围内时,这并不稳健。

希望这能澄清为什么这不是一个统计问题(有一些测试可以确定是否发生了跳跃,但不是跳跃到达时间 afaik)。


万一有人想要一个真实的例子: this is a corresponding graph, this is the raw data of the relevant period and this 是缩减后的数据集。


也许作为一个起点,看看函数streaks 在包 PMwR 中(我维护)。连胜是 定义为指定大小的移动,即 不被相同大小的反击打断。这 函数适用于 returns,没有差异,所以我添加 100 到您的数据。

例如:

set.seed(1)
n <- 1000
x <- 100 + cumsum(sample(c(-1, 1), n, TRUE))

plot(x, type = "l")
s <- streaks(x, up = 0.12, down = -0.12)
abline(v = s[, 1])
abline(v = s[, 2])

垂直线表示条纹的起点和终点。

也许您随后可以按要求的标准(例如长度)过滤已识别的条纹。要么 你可以玩不同的阈值 和向下移动(虽然这不是真的推荐 在当前的实施中,但也许是结果 足够好)。例如,向上的条纹可能如下所示。绿色垂直线表示连胜的开始;红线表示结束。

plot(x, type = "l")
s <- streaks(x, up = 0.12, down = -0.05)
s <- s[!is.na(s$state) & s$state == "up", ]
abline(v = s[, 1], col = "green")
abline(v = s[, 2], col = "red")