【问题标题】:Using zero-length xts objects使用长度为零的 xts 对象
【发布时间】:2017-07-24 21:22:19
【问题描述】:

我对长度为零且宽度不为零的 xts 对象感到困惑,为了方便起见,这里将其称为 empty xts 对象。
我认为它们是对没有观察到的证券进行建模的好方法,例如退市证券。

x=xts(matrix(numeric(0), dimnames=list(NULL, "Delist1")), as.Date(numeric(0)))
x
#      Delist1

但是,当涉及合并空证券时,它们就会消失:

y=xts(1:3,  as.Date(1:3))    
names(y)="List1"
merge(x,y)
#             List1
# 1970-01-02      1
# 1970-01-03      2
# 1970-01-04      3

当您有多个时间序列时,这尤其不方便,其中一些可能是空的:

z=xts(matrix(numeric(0), dimnames=list(NULL, "Delist2")), as.Date(numeric(0)))
L=list(x,y,z) # etc.
Reduce(merge, L)
#             List1
# 1970-01-02      1
# 1970-01-03      2
# 1970-01-04      3

您丢失了有关空时间序列的信息,而您希望每个空序列都有一整列的 NA。

也许简单的经验法则就是不要使用空的 xts 对象并使用 NA:

x=c(Delist1=NA)
z=c(Delist2=NA)
L=list(x,y,z) # etc.
X=Reduce(merge.xts, L)
setNames(X, sapply(L, names))
#            Delist1  List1 Delist2
# 1970-01-02      NA      1      NA
# 1970-01-03      NA      2      NA
# 1970-01-04      NA      3      NA

但是,前两个系列不能是 NA:

L=list(x,z,y) # etc.
Reduce(merge.xts, L)
# Error use:
do.call(merge.xts, L)

无论如何,如果L 的所有元素都是空的,do.call(...) 仍然不起作用,需要额外的修复。

总结:

  1. 应该如何使用空的 xts 对象?
  2. 他们是否打算在没有观察的情况下对时间序列进行建模?

更新

这是对@userR 提出的解决方案的长评论

在我虚构的时间窗口as.Date(1:3) 中,创建/定义一个空的时间序列并为每个日期定义一个 NA 会很简单,这可能适用于理论案例。
在现实世界的场景中,当您在给定的时间窗口内查询数据时,您永远不会填满所有的日子。

为了澄清,假设您查询证券 A 和 B 在 2000-02-01/2000-02-04 期间的数据。
基于 NA 的空系列应该是这样的:

(delist=xts(rep(NA,4), as.Date("2000-02-01")+0:3))
#            [,1]
# 2000-02-01   NA
# 2000-02-02   NA
# 2000-02-03   NA
# 2000-02-04   NA

提供者返回的实际数据可能是这样的:

A
#            [,1]
# 2000-02-01    1
# 2000-02-02    2
# 2000-02-03    3

B
#            [,1]
# 2000-02-01    1
# 2000-02-02   NA
# 2000-02-03    3

假设没有 2000-02-04 日期,因为这不是交易日。
合并给出:

merge(A,B, delist)
#             A  B delist
# 2000-02-01  1  1     NA
# 2000-02-02  2 NA     NA
# 2000-02-03  3  3     NA
# 2000-02-04 NA NA     NA

显然[2,2]中的NA是一个实际的缺失值,最后一行NA是delist的定义人为推导出来的。
相反,单一 NA 方法不涉及这些问题:

delist=NA
merge(A,B, delist)
#            A  B delist
# 2000-02-01 1  1     NA
# 2000-02-02 2 NA     NA
# 2000-02-03 3  3     NA

我们无法提前确切知道返回的交易日期。不同的市场/交易所/证券实施不同的约定,因此如果可能的话,在查询它们之前确定交易日至少是不切实际的。

更新:持久性

还有一个更微妙的问题。
以上,证券AB 具有基于实际观察的持久表示。当上下文需要它时,例​​如在merge() 中,会添加 NA 以填补错位间隙。 如上所述,根据AB 的日期定义第三个证券C 是一个弱定义,因为当您更改投资组合组合时,您也在更改此证券的定义,但@987654341 @ 始终与数据源未返回数据的安全性相同。
因此,恕我直言,C 可以建模为 NANULL、零长度 xts 等,但不能建模为 上下文敏感 值。

【问题讨论】:

  • 我明白你的意思。我是否正确假设您的delist 系列中的 NA 数量 only 取决于从查询返回的最长系列中的行数?如果是这种情况,您是否可以不创建delist 查询您的数据?这样,您就可以在能够将delist 存储为xts 对象的同时,不人为地添加不必要的NA。你可以这样做xts(matrix(rep(NA, length(y)), dimnames=list(NULL, "Delist1")), order.by = index(y))
  • 如果我理解正确,请告诉我,我将编辑我的答案以适应。
  • @user:在合并范围内,您可以从非空系列中取任意日期。但是,我认为根据在其他对象中找到的值对对象(空时间序列)进行 定义 并不是一个好主意。您可能事先不知道将提供哪些日期,更重要的是,如果您添加或删除新证券,定义会中断。最好重新定义 merge() 以便接受空 xts 对象并在输出中生成 NA 列。
  • 我理解你的顾虑,但我不认为有问题,因为delist总是有东西要合并,否则单独分析delist有什么意义呢?您始终可以根据最长的系列以编程方式定义delist。这样您就不必知道最长的系列有多长,程序知道。合并后,delist 列不再依赖于初始定义,因此删除任何现有系列不会破坏任何内容。我虽然同意重新定义 merge() 以接受空 xts 是一个更好的主意,但到目前为止我想不出解决方案。
  • "empty" xts 对象在您定义它们时在代码中没有明确定义,因此目前不受支持。有“零宽度”xts 对象,它们是具有索引但没有数据的 xts 对象。您的“空”对象没有索引,但有没有数据的“列”。我称之为“零长度”。我还打开了an issue 来记录和讨论这种细微的差异。

标签: r time-series xts


【解决方案1】:

1.空xts对象应该如何使用?

2.他们是否打算在没有观察的情况下对时间序列进行建模?

两个都回答:

空 xts 对象通常是在 xts 对象中的值范围之外的时间范围内进行子集化的结果。你希望getSymbols("AAPL"); AAPL["1900"] 会返回什么?

那么空的 xts 对象什么时候有用?好吧,如果我想填充 NA 数据行,我会创建一个带有一组日期的空 xts 对象(没有实际数据),以后可能会将其用于其他目的。例如,如果我们在不均匀的时间戳上有 bid/ask 值,我们可能想要创建 5 秒的 OHLC 柱,并带有整齐的柱时间戳开始(注意实际上,如果您要合并不同频率的柱数据,请始终确保使用柱结束时间戳来避免意外引入前瞻偏差)。一个空的 xts 对象有助于达到目标:

# Create sample tick data:
set.seed(5)
st_time <- as.POSIXct('2007-01-02 09:00:00')
x <- xts(x= matrix(c(1:10, 1:10 +0.01),nc = 2) + rnorm(10, 0, 0.01),
         order.by = st_time + rnorm(10,0, 3) + seq(5, 25, length.out = 10),
         dimnames = list(NULL, c("bid","ask")))
x
#                                   bid       ask
# 2007-01-02 09:00:04.816884  2.0138436  2.023844
# 2007-01-02 09:00:06.203266  2.9874451  2.997445
# 2007-01-02 09:00:08.682891  0.9915914  1.001591
# 2007-01-02 09:00:10.673608  5.0171144  5.027114
# 2007-01-02 09:00:11.194063  4.0007014  4.010701
# 2007-01-02 09:00:14.003655  7.9936463  8.003646
# 2007-01-02 09:00:15.694152  5.9939709  6.003971
# 2007-01-02 09:00:16.541393  6.9952783  7.005278
# 2007-01-02 09:00:23.500229  8.9971423  9.007142
# 2007-01-02 09:00:24.221933 10.0013811 10.011381

to.period(x, period = "secs", k = 5, indexAt='startof')
# x.Open    x.High     x.Low    x.Close
# 2007-01-02 09:00:04.816884 2.013844  2.013844 2.0138436  2.0138436
# 2007-01-02 09:00:06.203266 2.987445  2.987445 0.9915914  0.9915914
# 2007-01-02 09:00:10.673608 5.017114  7.993646 4.0007014  7.9936463
# 2007-01-02 09:00:15.694152 5.993971  6.995278 5.9939709  6.9952783
# 2007-01-02 09:00:23.500229 8.997142 10.001381 8.9971423 10.0013811

# 5 sec bar Timestamps are messy, so let's fix them using an empty xts object
# Use of an empty xts object:
emp_5sec_interval <- xts(order.by = st_time + seq(5, 25, by = 5),)
x2 <- merge(x, emp_5sec_interval, fill = na.locf)
x2
#                                   bid       ask
# 2007-01-02 09:00:04.816884  2.0138436  2.023844
# 2007-01-02 09:00:05.000000  2.0138436  2.023844
# 2007-01-02 09:00:06.203266  2.9874451  2.997445
# 2007-01-02 09:00:08.682891  0.9915914  1.001591
# 2007-01-02 09:00:10.000000  0.9915914  1.001591
# 2007-01-02 09:00:10.673608  5.0171144  5.027114
# 2007-01-02 09:00:11.194063  4.0007014  4.010701
# 2007-01-02 09:00:14.003655  7.9936463  8.003646
# 2007-01-02 09:00:15.000000  7.9936463  8.003646
# 2007-01-02 09:00:15.694152  5.9939709  6.003971
# 2007-01-02 09:00:16.541393  6.9952783  7.005278
# 2007-01-02 09:00:20.000000  6.9952783  7.005278
# 2007-01-02 09:00:23.500229  8.9971423  9.007142
# 2007-01-02 09:00:24.221933 10.0013811 10.011381
# 2007-01-02 09:00:25.000000 10.0013811 10.011381

x_ohlc <- to.period(x2, period = "secs", k = 5, indexAt='startof')
x_ohlc
# x2.Open   x2.High     x2.Low   x2.Close
# 2007-01-02 09:00:04.816884  2.0138436  2.013844  2.0138436  2.0138436
# 2007-01-02 09:00:05.000000  2.0138436  2.987445  0.9915914  0.9915914
# 2007-01-02 09:00:10.000000  0.9915914  7.993646  0.9915914  7.9936463
# 2007-01-02 09:00:15.000000  7.9936463  7.993646  5.9939709  6.9952783
# 2007-01-02 09:00:20.000000  6.9952783 10.001381  6.9952783 10.0013811
# 2007-01-02 09:00:25.000000 10.0013811 10.001381 10.0013811 10.0013811

如果您想对退市证券建模,则创建一个具有有效日期的 xts 对象,并用 NA 填充相应的列(实际上可能不止一列,例如 OHLC、Bid/Ask)。例如使用类似的东西合并退市证券(正如用户已经建议的那样)

y=xts(rep(NA, 3),  as.Date(1:3))

我不会使用您建议的 delist=NA 方法。

最终,xts 作者是这里关于空 xts 对象是什么的设计权威......

【讨论】:

  • 我会小心区分“零宽度”和“零长度”,并避免使用“空”来描述这两种类型的对象。
  • 假设您想获取 S1、S2、S3 的数据...您将它们循环起来,如果被删除,getSymbols("S1") 返回一个错误。您使用try 捕获它,并且需要为 S1 赋值。哪一个?如果它取决于 S2、S3... 的日期,您不会提前知道它们。因此,您只能在循环结束时构建 S1(和其他空时间序列)。同时如何存储 S1 状态?好的系列也可能有不同的日期。不同的投资组合组合日期会有所不同,您需要重建 S1。我们首先需要某种持久值来为 S1 建模。以后的 S1 可以通过 NA 观察合并。
  • @antonio 所以包括一个虚拟的第一行 na 值,日期为 1970-01-01 或任何退市证券。然后正常地跨证券合并(并在合理的开始日期下对值进行子集化)。似乎您对初始化对象的方式过于复杂了。查看 blotter 和 quantstrat 包源以获得其他人如何初始化 xts 对象的灵感。关系松散。
【解决方案2】:

我认为这里的问题是您如何定义“空时间序列”。您定义“空系列”的方式是它有零行。您的第一次合并忽略了x,因为它不知道如何使用零长度系列。 merge() 排除了您的空系列,因为没有要合并的公共列 by。事实上,您的除名系列应该有 3 行,每行都有 NA。这样您就可以将它们与相同行数的xts 对象进行比较。

library(xts)

x=xts(matrix(rep(NA, 3), dimnames=list(NULL, "Delist1")), as.Date(1:3))

y=xts(1:3,  as.Date(1:3))    
names(y)="List1"
z = merge(x,y)

# > z
#            Delist1 List1
# 1970-01-02      NA     1
# 1970-01-03      NA     2
# 1970-01-04      NA     3

class(z)

# > class(z)
# [1] "xts" "zoo"

【讨论】:

  • 您的想法在理论上可行,但在实践中却行不通,因为返回的天数从不遵循易于预定义的模式。我尝试在更新中评论详细信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-26
  • 2013-10-22
  • 2019-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多