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

4

我有大约50个数据集,包括5个交易所中10个货币对在30天时间内的所有交易。所有货币对属于同一资产类别,意味着它们具有强相关性,并且预计具有相似的属性,但处于不同的规模上。此类数据的一个例子如下:

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)))

Plot example

大致上,我需要识别每天发生的相关局部极小值和极大值。黄色标记是我感兴趣的点。与此示例不同,通常每天只有一个这样的点,并且我将每天单独考虑。然而,过滤掉我的实际兴趣点中的噪音很难。
我的实际目标是找到成对资产开始跳跃的确切点以及跳跃结束的确切点。这需要尽可能准确,因为我想观察哪种资产先移动,哪种资产在哪个时间点后跟随(如上所述,它们高度相关)。在两个极值之间,我想最小化距离并最大化相对/绝对变化,因为我的兴趣点通常彼此靠近,它们的差异相当大。
我已经查看了其他类似的问题,例如寻找局部最大值和最小值定位局部极大值的算法以及这个有着相同目标的算法。然而,我的数据集非常嘈杂。我已经将数据集减少到5分钟间隔,但这导致省略了识别局部极小值和极大值函数中的相关点。因此,这不是一个对我的目标有益的解决方案。
如何使用相当精确的算法实现我的目标?手动浏览所有时间序列不是一个选项,因为这需要我手动评估50 * 30个时间序列,这太耗时了。我很困惑,正在尝试找到一个合适的解决方案已经一个星期了。
如果需要更多的代码片段,我很乐意分享,但它们并没有给我有意义的结果,这与提供一个最小工作示例的想法相反,因此我决定暂时将它们留出来。

编辑:

首先,我更新了绘图并添加了数据集的时间戳以让您了解(实际分辨率)。理想情况下,算法将检测到左侧的两个跳跃点。内部的两个点因为它们更接近且没有拦截而跳跃,而外部的点因为值更极端。事实上,这也回答了算法是否允许看到未来的问题。是的,如果在范围内有另一个局部极值点,比如说30个观察值(或30分钟)之内,则忽略中间的局部极值点。 在我的数据中,跳跃大小从2%-〜15%不等,因此需要至少为2%才能考虑跳跃。只有在达到相同方向上15(可能是可适应的)个连续步骤的峰和谷之前/之后的阈值时才考虑。
非常幼稚的方法是将数据分成一天的全局最小值和最大值的子集。在大多数情况下,这样会使数据去噪并起到指示作用。然而,当全局极值不在跳跃范围内时,这种方法并不稳健。
希望这澄清了为什么这不是统计问题(有一些测试可以确定是否发生了跳跃,但不知道跳跃到达时间的测试)。
如果有人需要一个真实的例子: this 是相应的图表,this 是相关时期的原始数据,this 是精简数据集。

请查看 https://facebook.github.io/prophet/,而且这个推文线程非常有帮助 https://twitter.com/seanjtaylor/status/1123278380369973248 - infominer
请查看"哪个网站?"以获取一般性问题。这是一个比我们处理的更高级别的问题;我建议使用Stack Exchange统计。 - Prune
也许我的问题描述有误(如果是这样,我很抱歉并会确保修正描述),但这主要是一个算法问题。我不需要像prophet这样的工具来为我做预测,而且对于这个特定的问题,不幸的是没有统计学解决方案可用。您能告诉我这个问题在哪些方面过于高级,我将相应地进行澄清。 - zonfl
1
你的描述并非“有缺陷”,但是不完整。例如,从左边数第二个点标记了一个高点,但是稍微向右移动一点就是更高的高点。为什么不选择那个呢?你需要为局部极值定义规则:算法是否允许看到未来?如果两个局部极值靠得很近(如图表中间所发生的情况),会发生什么?局部极值需要与周围点有多大差异?应该在多大范围内计算极值点?等等... - Enrico Schumann
有效的观点!我会进行编辑。 - zonfl
1个回答

2
也许可以从查看PMwR包中的streaks函数开始(我是该函数的维护者)。一条纹路被定义为一次指定大小的移动,该移动不被同样大小的反向移动所打断。该函数处理回报而非差异,因此我会在你的数据上加入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])

这些垂直线表示连续上涨或下跌的开始和结束。

Streaks

也许您可以通过所需的标准(如长度)来筛选已识别的连续行情。 或者,您可以尝试使用不同的上涨和下跌移动阈值(尽管当前实现不建议这样做,但也许结果足够好)。 例如,连续上涨可能看起来像下面这样。 绿色垂直线表示连续上涨的开始;红线显示其结束。

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")

Up streaks


非常感谢您的努力!看起来非常有前途,我会仔细研究并在测试真实数据集后报告。 - zonfl
这似乎正是我正在寻找的!而且,我很高兴看到它对噪声非常稳健。然而,结果仍然是随机的:https://imgur.com/a/viIHWco(不工作),https://imgur.com/a/I1xm5zX(工作)。我的真实输入数据具有异构比例,因此结果并不总是如预期。以下是一些货币对的当前价格:`0.5; 10; 60; 180; 1400; 5200.` 我想重新调整它们的比例,但这会扭曲收益率(从5200-5400的跳跃不等于从99到101的跳跃)。 - zonfl
1
你调整了上下参数吗?它们应该反映基础系列的波动性。 - Enrico Schumann
我没有将阈值设置得足够低,现在它可以工作了。我还查看了你的其他软件包,文档非常有用且清晰!再次感谢,你的解决方案为我节省了很多时间。 - zonfl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接