【问题标题】:Vectorized change of all but first same/repeated values in vector b based on values from vector a基于向量 a 的值对向量 b 中除第一个相同/重复值之外的所有值进行向量化更改
【发布时间】:2013-08-11 02:01:28
【问题描述】:

我正在尝试找到基于向量 a 的值更新向量 b 值的向量化解决方案。我遇到的问题是这样的:

> # Vector a is the "driver" meaning if there is 1 or -1 in vector a
> # -1 or 1 needs to follow in vector b. The challenge I have is when 
> # I have 1 or -1 in a and in b I have two or more -1 or 1
> # then all but first same values in b should be set to 0 if values 
> # in a does not change
> a <- c(0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 1, 1,-1,-1, 0, 0, 1, 0, 0,-1, 0, 1, 0, 0, 0, 0, 0)
> b <- c(0, 0,-1, 0,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1, 0, 0,-1, 0, 0, 1, 0,-1,-1, 0,-1, 0)
> a
 [1]  0  1  0  0  0  0  0 -1  0  0  1  1 -1 -1  0  0  1  0  0 -1  0  1  0  0  0  0  0
> b
 [1]  0  0 -1  0 -1  0  0  0  0  1  1 -1 -1  1  1  0  0 -1  0  0  1  0 -1 -1  0 -1  0
> 
> # I need a vectorized function(a, b), if possible, that changes b 
> # based on a like below (removing some repeated values in b)
> # like below
> b[5] <- 0
> b[11] <- 0
> b[24] <- 0
> b[26] <- 0
> a
 [1]  0  1  0  0  0  0  0 -1  0  0  1  1 -1 -1  0  0  1  0  0 -1  0  1  0  0  0  0  0
> b
 [1]  0  0 -1  0  0  0  0  0  0  1  0 -1 -1  1  1  0  0 -1  0  0  1  0 -1  0  0  0  0

非常感谢任何有关如何以矢量化方式执行此操作的帮助/提示。

我尝试了使用 rle、cumsum、diff、...的“标准”方法

# I tried to play around with
test <- data.frame(
        a=a,
        b=b,
        a.plus.b=a + b,
        diff.a.plus.b=c(0, diff(a + b)),
        cumsum.a.plus.b=cumsum(a + b),
        diff.cumsum.a.plus.b=c(0, diff(cumsum(a + b)))
)
test 

rle(b)
rle(b)$values
rle(b)$lengths

编辑: 根据大卫要求更清楚地了解我想要做什么,我将详细解释这个问题。

我正在构建简化的交易回测功能(因为 quantstrat 太复杂且速度慢,以满足我的需求)。

当我得到一个值为 1(做多)或 -1(做空)的入场信号向量 a 时,就会出现上述问题(在消息的顶部)。在进入信号之后,可能会发生三件事(保存在向量 b 中):
- 达到时间停止(在一天结束时退出 b==-1 如果多头,b==1 如果空头),
- 达到利润目标(再次 b==-1,b==1)或
- 触发止损(再次 b==-1,b==1)。

所以向量 b 代表每次进场后可能的事件/退出(没有重叠交易 - 一个在另一个进入之前关闭)。有时交易直接对我有利,我们立即达到了利润目标。伟大的。有时我们在达到利润目标之前就停止了。有时既没有达到止损,也没有在一天结束时达到利润目标,所以,我们只剩下一天结束了。

我需要在进入后删除除第一个退出事件之外的所有事件(a==1 或 a==-1)。由于并非所有都可以/将会发生,所以应该只保留第一个(从时间角度来看),而我应该删除后续的。

让我举个例子。我们在 9:31 进入多头交易(在第一分钟常规交易时间栏收盘时)。所以 a 变成:

a <- c(1, 0, 0, 0, 0, ..., 0)

我们总是在最后一分钟柱(时间停止)结束时退出,因此我们将最后可能的退出添加到 b:

b <- c(0, 0, 0, 0, 0, ...,-1)

我们也知道(在回测中)我们的利润目标在 9:35 柱收盘时已经达到,所以我们将这个事实添加到 b (b[5]

b <- c(0, 0, 0, 0,-1, ...,-1)

而且,我们还知道(在回测中)会在 9:33 触发停止,因此我们将其添加到 b (b[3]

b <- c(0, 0,-1, 0,-1, ...,-1)

因此,由于我的利润目标永远不会达到(之前已达到止损)并且我们不会在市场收盘时进行交易,我应该设置 b[5]

b <- c(0, 0,-1, 0, 0, ..., 0)

我需要在过去的几千天里处理这个......

我希望这能阐明我想要做什么。

【问题讨论】:

  • 您是否要删除重复项? R中有一个duplicate()函数。
  • 感谢您的想法,但我认为这不会解决我的挑战。查看示例,在该示例中,b 中的值应设置为 0,同时考虑到 a。
  • 你能提供一个更小的例子吗?数字太多
  • 请只取 a 和 b 的前 6 个元素。这是第一步。但也请查看向量 a 和 b 的中间部分,因为该示例揭示了在哪些条件下可重复数字是可以的。
  • 好的,我会尝试查看并理解您的问题。但是为什么 b[8] 是 0?

标签: r finance algorithmic-trading quantitative-finance


【解决方案1】:

我不确定我是否真的理解你想要做什么,但如果理解我想我有一个适合你的矢量化解决方案。

> f <- function(a,b){
+   b[unique(c(which(a[-length(a)] == 0 & b[-1] != 0) + 1,which(b[-length(b)] == b[-1] & b[-1] != 0)))] <- 0
+   return(b)
+ }
> f(a,b)
 [1]  0  0 -1  0  0  0  0  0  0  0  0  0 -1  0  1  0  0 -1  0  0  1  0  0  0  0  0  0

这是我的理性。我认为您想根据两种不同的情况将 b 的值设置为零:

1) 当 b 的非零值重复时。如果是这样,这应该找到这些索引:

which(b[-length(b)] == b[-1] & b[-1] != 0)

2) 当 a 的前一个索引为零时出现 b 的非零值。如果是这样,这应该可以解决问题:

which(a[-length(a)] == 0 & b[-1] != 0) + 1

希望我没有误解你的目标。

编辑:

第二次在这里尝试。我仍然很确定我不明白你要做什么,因为我的解决方案仍然标记 b[10] (你说它不应该),但是从你写的最好的我能理解是您要进行以下更改:

“a”的零值之后的“b”的非零值必须设置为零。

由于这条规则错误地标记了 b[10],你能告诉我为什么它不正确吗?我认为这个问题需要这样表述,以便我给你一个解决方案,因为金融谈话对我来说听起来像是胡言乱语。

无论如何,这是我列出的规则的矢量化解决方案。:

> f <- function(a,b) {
+   b[which(b != 0)[which(!which(b != 0) %in% (which(a[-length(a)] != 0) + 1))]] <- 0
+   return(b)
+ }
> f.indices <- function(a,b) which(b != 0)[which(!which(b != 0) %in% (which(a[-length(a)] != 0) + 1))]
> f(a,b)
 [1]  0  0 -1  0  0  0  0  0  0  0  0 -1 -1  1  1  0  0 -1  0  0  1  0 -1  0  0  0  0
> f.indices(a,b)
[1]  5 10 11 24 26

编辑:第三次尝试是魅力......

现在假设目标是将 b 的所有非零值设置为零,除了 a 的非零值之后的第一个值。我不确定是否/如何完全矢量化,但这里应该有一个快速的解决方案:

> a <- c(0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 1, 1,-1,-1, 0, 0, 1, 0, 0,-1, 0, 1, 0, 0, 0, 0, 0)
> b <- c(0, 0,-1, 0,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1, 0, 0,-1, 0, 0, 1, 0,-1,-1, 0,-1, 0)
> 
> f <- function(a,b){
+   #non-zero b indices
+   nz.b <- which(b != 0)
+   #non-zero a indices
+   nz.a <- which(a != 0)  
+   #non-zero b indices that do not follow non-zero a indices
+   nz.b.rm <- nz.b
+   for(i in nz.a){
+     nz.b.rm <- nz.b.rm[!nz.b.rm %in% nz.b[nz.b > i][1]] 
+   }
+   #print non-zero b indices that do no folow non-zero a indices
+   print(paste0("Indices Removed: ",paste(nz.b.rm,collapse=",")))
+   #remove non-zero b indices that do not follow non-zero a indices
+   return(b[-nz.b.rm])
+ }
> 
> b.new <- f(a,b)
[1] "Indices Removed: 5,11,24,26"
> b.new
 [1]  0  0 -1  0  0  0  0  0  1 -1 -1  1  1  0  0 -1  0  0  1  0 -1  0  0

【讨论】:

  • 大卫谢谢。好的和聪明的想法。然而,它并不完全正确。在我的 b 示例中,只有这些值需要更改/设置为 0:b[5]、b[11]、b[24]、b[26]。所有其他的,尤其是向量 b 中间的那些(从 12 到 22)都不要管。让我举一个我想要的简单例子: # 不同的例子 a
  • 对,我不明白为什么这些价值观需要改变。如果您能更清楚地说明值需要更改时背后的逻辑,那么我可能会提供帮助,但我只能花这么多时间试图弄清楚手头的问题。
  • 大卫,我编辑了最初的帖子并提供了更多解释。我希望现在更清楚了。如果您需要更多详细信息,我当然会提供。谢谢。
  • 我又试了一次,但还是不明白。如果你能纠正我的新“规则”,那将是一个很大的帮助,但否则我就是不明白你想要这个函数做什么。
  • 好的,所以规则实际上是:“'b' 的所有非零值都必须设置为零,除了 'a' 中的非零值之后的第一个值”?如果这是真的,我可以写一些东西来做到这一点,但我认为它不能被矢量化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-09
  • 1970-01-01
  • 2011-04-23
  • 2016-05-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多