我有以下xts对象(表示长/短条目(第1列和第2列)和退出(第3列和第4列)触发器,其中“aggregate”信号列应为1(系统为长),-1(系统是短的)或0(系统是平的)。我不能使这个工作为“聚合”信号column5 ...
数据:
LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal
18.02.93 0 0 1 0 0
19.02.93 0 0 0 1 0
22.02.93 1 0 0 0 1
23.02.93 0 0 0 0 0
24.02.93 0 0 0 0 0
25.02.93 0 0 0 0 0
26.02.93 0 0 1 0 0
01.03.93 0 0 1 0 0
04.03.93 0 1 0 0 -1
05.03.93 0 0 0 0 0
11.03.93 0 0 0 1 0
12.03.93 0 0 1 0 0
我想以这种形式转换数据:
LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal
18.02.93 0 0 1 0 0
19.02.93 0 0 0 1 0
22.02.93 1 0 0 0 1
23.02.93 0 0 0 0 1
24.02.93 0 0 0 0 1
25.02.93 0 0 0 0 1
26.02.93 0 0 1 0 1
01.03.93 0 0 1 0 0
04.03.93 0 1 0 0 -1
05.03.93 0 0 0 0 -1
11.03.93 0 0 0 1 -1
12.03.93 0 0 1 0 0
我尝试对下面的函数进行uprogramming(但是id不起作用;注释掉的部分也不起作用并且非常慢 - 我知道在R中使用循环很慢但是这是我唯一的想法) :
padMinusPlusOnes<-function(signals, longEntryColumn=1, shortEntryColumn=2, signalsColumn=5) {
ret<-signals
#get all indexes between long entry equals 1 to long exit equals 1 and set signalsColumn for these rows to 1
ret[(lag(ret)[, longEntryColumn] == 1) & (ret[, signalsColumn] == 0), signalsColumn]<-1
#get all indexes between short entry equals 1 to short exit equals 1 and set signalsColumn for these rows to -1
ret[(lag(ret)[, shortEntryColumn] == -1) & (ret[, signalsColumn] == 0), signalsColumn]<--1
return(ret)
# ret<-signals
# for (i in 2:NROW(ret)) {
# if ((ret[i - 1, longEntryColumn] == 1) & (ret[, signalsColumn] == 0)) {
# ret[i, signalsColumn]<-1
# }
# if ((ret[i - 1, shortEntryColumn] == -1) & (ret[, signalsColumn] == 0)) {
# ret[i, signalsColumn]<--1
# }
# }
#
# return(ret)
}
感谢您在如何转换数据方面提供的帮助。
亲切的问候,萨莫。
编辑说明:在收到Prasad Chalasani和J. Winchester的两个非常有用且富有洞察力的答案后,我意识到我遗漏了关于我的数据结构的重要信息。因此,我更改了上面的数据以更好地反映我的数据并复制原始文件(基于以下两个答案所基于的):
数据:
LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal
18.02.93 0 0 0 0 0
19.02.93 0 0 0 0 0
22.02.93 1 0 0 0 1
23.02.93 0 0 0 0 0
24.02.93 0 0 0 0 0
25.02.93 0 0 0 0 0
26.02.93 0 0 1 0 0
01.03.93 0 0 0 0 0
04.03.93 0 1 0 0 -1
05.03.93 0 0 0 0 0
11.03.93 0 0 0 1 0
12.03.93 0 0 0 0 0
我想以这种形式转换数据:
LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal
18.02.93 0 0 0 0 0
19.02.93 0 0 0 0 0
22.02.93 1 0 0 0 1
23.02.93 0 0 0 0 1
24.02.93 0 0 0 0 1
25.02.93 0 0 0 0 1
26.02.93 0 0 1 0 1
01.03.93 0 0 0 0 0
04.03.93 0 1 0 0 -1
05.03.93 0 0 0 0 -1
11.03.93 0 0 0 1 -1
12.03.93 0 0 0 0 0
答案 0 :(得分:4)
您不需要使用循环,也不需要“回顾”。您可以使用矢量化函数cumsum
来获得所需内容。假设您的长期进入/退出和短期进入/退出期间不重叠,您可以这样做:首先编制虚拟信号:
n <- 15
zeros <- rep(0,n)
LongEnt <- replace(zeros, c(1, 12), 1)
LongEx <- replace(zeros, c(4, 14), 1)
ShortEnt <- replace(zeros, 6, 1)
ShortEx <- replace(zeros, 10, 1)
现在做一些cumsum
魔法来获得正确的“聚合”信号列:
SigLong <- cumsum(LongEnt) - cumsum(LongEx) + LongEx
SigShort <- -cumsum(ShortEnt) + cumsum(ShortEx) - ShortEx
> cbind(LongEnt, LongEx, ShortEnt, ShortEx, Signal = SigLong + SigShort)
LongEnt LongEx ShortEnt ShortEx Signal
[1,] 1 0 0 0 1
[2,] 0 0 0 0 1
[3,] 0 0 0 0 1
[4,] 0 1 0 0 1
[5,] 0 0 0 0 0
[6,] 0 0 1 0 -1
[7,] 0 0 0 0 -1
[8,] 0 0 0 0 -1
[9,] 0 0 0 0 -1
[10,] 0 0 0 1 -1
[11,] 0 0 0 0 0
[12,] 1 0 0 0 1
[13,] 0 0 0 0 1
[14,] 0 1 0 0 1
[15,] 0 0 0 0 0
<强>更新即可。根据OP的修改问题,我们需要处理任意一系列进入/退出信号的情况,并找到第一个条目和相应的第一个出口之间的时间段。这是通过非常简单的arihtmetic操作(即没有昂贵的回顾或if / else检查)来实现这一目的的方法。我们只需要对cumsum
函数进行一些小修改,我将其称为cumplus
- 这就像cumsum
一样,除了在获取每个总和后,它将其替换为1或0,具体取决于是否积极:
cumplus <- function(y) Reduce(function(a,b) a + b > 0, y, 0, accum=TRUE)[-1]
(顺便说一下,Reduce
是一种很好的方法,可以在没有明确写出for
循环的情况下紧凑地定义累积函数 - 有关详细信息,请参阅?Reduce
。
现在举一个进入/退出信号的例子:
LongEnt <- c(1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
0, 1, 0, 0)
LongEx <- c(0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
1, 0, 0, 1)
x <- LongEnt - LongEx
z <- cumplus(x)
这几乎是我们想要的......我们只需要在每个块的末尾插入1。
z <- z - c(0,pmin(0,diff(z)))
> cbind(LongEnt, LongEx, signal = z)
LongEnt LongEx signal
[1,] 1 0 1
[2,] 0 0 1
[3,] 0 0 1
[4,] 1 0 1
[5,] 0 0 1
[6,] 0 0 1
[7,] 1 0 1
[8,] 0 0 1
[9,] 0 1 1
[10,] 0 0 0
[11,] 0 0 0
[12,] 0 1 0
[13,] 1 0 1
[14,] 0 0 1
[15,] 0 0 1
[16,] 1 0 1
[17,] 0 0 1
[18,] 0 0 1
[19,] 0 1 1
[20,] 0 0 0
[21,] 0 1 0
[22,] 1 0 1
[23,] 0 0 1
[24,] 0 1 1
处理短入/出口当然是类似的。
答案 1 :(得分:0)
我做了几个逻辑假设,即:系统在中性状态下启动(即零);如果系统通过任何类型(长/短)的“进入”信号离开“零状态”,则下一个信号必须是相同类型的“退出”信号。如果我将数据读入名为sigmat
的矩阵,我可以执行以下操作。
streamLong <- with(sigmat, LongEntrySignal == 1 | LongExitSignal == 1)
switches <- which(streamLong)
mat <- cbind(c(1, switches), c(switches, length(streamLong) + 1), 0:1)
stateLong <- do.call("c", apply(mat, 1, function(ro)rep(ro[3], ro[2] - ro[1])))
streamShort <- with(sigmat, ShortEntrySignal == 1 | ShortExitSignal == 1)
switches <- which(streamShort)
mat <- cbind(c(1, switches), c(switches, length(streamShort) + 1), 0:1)
stateShort <- do.call("c", apply(mat, 1, function(ro)rep(ro[3], ro[2] - ro[1])))
# EDIT: The entry signal stays "on" until end of the exit day
# so add one to the on sequences, and subtract one from the off sequences
sigRLE <- rle(stateLong - stateShort)
sigRLE$lengths[-1] <- sigRLE$lengths[-1] + 1:0 + 0:-1
sigmat$signal <- rep(sigRLE$values, sigRLE$lengths)
这是输出。
R> sigmat
date LongEntrySignal ShortEntrySignal LongExitSignal ShortExitSignal Signal signal
1 18.02.93 0 0 0 0 0 0
2 19.02.93 0 0 0 0 0 0
3 22.02.93 1 0 0 0 1 1
4 23.02.93 0 0 0 0 0 1
5 24.02.93 0 0 0 0 0 1
6 25.02.93 0 0 0 0 0 1
7 26.02.93 0 0 1 0 0 1
8 01.03.93 0 0 0 0 0 0
9 04.03.93 0 1 0 0 -1 -1
10 05.03.93 0 0 0 0 0 -1
11 11.03.93 0 0 0 1 0 -1
12 12.03.93 0 0 0 0 0 0
答案 2 :(得分:0)
我确信这是一种“神奇的”(即矢量化)方式,但是现在,这是一个可行的循环解决方案。
# your example data
sigmat <- structure(list(
date = structure(c(6L, 7L, 8L, 9L, 10L, 11L, 12L, 1L, 2L, 3L, 4L, 5L),
.Label = c("01.03.93", "04.03.93", "05.03.93", "11.03.93", "12.03.93",
"18.02.93", "19.02.93", "22.02.93", "23.02.93", "24.02.93",
"25.02.93", "26.02.93"), class = "factor"),
LongEntrySignal = c(0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L),
ShortEntrySignal = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L),
LongExitSignal = c(1L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L),
ShortExitSignal = c(0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L),
Signal = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
.Names = c("date", "LongEntrySignal", "ShortEntrySignal",
"LongExitSignal", "ShortExitSignal", "Signal"),
row.names = c(NA, -12L), class = "data.frame")
# if there is an entry/exit signal, turn on/off
# otherwise keep the same state as the day before
sigShort <- sigmat$ShortEntrySignal - sigmat$ShortExitSignal
sigLong <- sigmat$LongEntrySignal - sigmat$LongExitSignal
for(i in 2:nrow(sigmat)) {
if(sigShort[i] == 0) sigShort[i] <- sigShort[i-1]
if(sigLong[i] == 0) sigLong[i] <- sigLong[i-1]
}
# The entry signal stays "on" until end of the exit day
# so extend the on sequences by one day, and shorten the off sequences
sigRLE <- rle((sigLong > 0) * 1 - (sigShort > 0) * 1)
sigRLE$lengths[-1] <- sigRLE$lengths[-1] + 1:0 + 0:-1
sigmat$Signal <- rep(sigRLE$values, sigRLE$lengths)