gpt4 book ai didi

r - 加速 WMA(加权移动平均)计算

转载 作者:行者123 更新时间:2023-12-05 00:36:00 25 4
gpt4 key购买 nike

我正在尝试计算 15 天柱的指数移动平均线,但希望在每个(结束)日/柱上看到 15 天柱 EMA 的“演变”。所以,这意味着我有 15 天的柱线。当每天都有新数据出现时,我想使用新信息重新计算 EMA。实际上我有 15 天的柱线,然后,每天之后我的新 15 天柱线开始增长,并且出现的每个新柱线都应该与之前的完整 15 天柱线一起用于 EMA 计算。

假设我们从 2012 年 1 月 1 日开始(我们有每个日历日的数据),在 2012 年 1 月 15 日结束时,我们有第一个完整的 15 天柱。在 2012 年 3 月 1 日完成 4 个完整的 15 天柱线后,我们可以开始计算 4 柱线 EMA (EMA(x, n=4))。在 2012 年 3 月 2 日结束时,我们使用我们目前掌握的信息并计算 2012 年 3 月 2 日的 EMA,假设 2012 年 3 月 2 日的 OHLC 是正在进行的 15 天柱线。所以我们取 4 个完整的柱线和 2012-03-02 的柱线并计算 EMA(x, n=4)。然后我们再等一天,看看新的 15 天柱线发生了什么(有关详细信息,请参阅下面的函数 to.period.cumulative)并计算 EMA 的新值......然后在接下来的 15 天......见函数 EMA.cumulative 下面的详细信息...

请在下面找到我到现在为止能想出的东西。性能对我来说是 Not Acceptable ,而且以我有限的 R 知识,我无法让它更快。

library(quantmod)

do.call.rbind <- function(lst) {
while(length(lst) > 1) {
idxlst <- seq(from=1, to=length(lst), by=2)

lst <- lapply(idxlst, function(i) {
if(i==length(lst)) { return(lst[[i]]) }

return(rbind(lst[[i]], lst[[i+1]]))
})
}
lst[[1]]
}

to.period.cumulative <- function(x, name=NULL, period="days", numPeriods=15) {
if(is.null(name))
name <- deparse(substitute(x))

cnames <- c("Open", "High", "Low", "Close")
if (has.Vo(x))
cnames <- c(cnames, "Volume")

cnames <- paste(name, cnames, sep=".")

if (quantmod:::is.OHLCV(x)) {
x <- OHLCV(x)
out <- do.call.rbind(
lapply(split(x, f=period, k=numPeriods),
function(x) cbind(rep(first(x[,1]), NROW(x[,1])),
cummax(x[,2]), cummin(x[,3]), x[,4], cumsum(x[,5]))))
} else if (quantmod:::is.OHLC(x)) {
x <- OHLC(x)
out <- do.call.rbind(
lapply(split(x, f=period, k=numPeriods),
function(x) cbind(rep(first(x[,1]), NROW(x[,1])),
cummax(x[,2]), cummin(x[,3]), x[,4])))
} else {
stop("Object does not have OHLC(V).")
}

colnames(out) <- cnames

return(out)
}

EMA.cumulative<-function(cumulativeBars, nEMA = 4, period="days", numPeriods=15) {
barsEndptCl <- Cl(cumulativeBars[endpoints(cumulativeBars, on=period, k=numPeriods)])

# TODO: This is sloooooooooooooooooow...
outEMA <- do.call.rbind(
lapply(split(Cl(cumulativeBars), period),
function(x) {
previousFullBars <- barsEndptCl[index(barsEndptCl) < last(index(x)), ]
if (NROW(previousFullBars) >= (nEMA - 1)) {
last(EMA(last(rbind(previousFullBars, x), n=(nEMA + 1)), n=nEMA))
} else {
xts(NA, order.by=index(x))
}
}))

colnames(outEMA) <- paste("EMA", nEMA, sep="")

return(outEMA)
}

getSymbols("SPY", from="2010-01-01")

SPY.cumulative <- to.period.cumulative(SPY, , name="SPY")

system.time(
SPY.EMA <- EMA.cumulative(SPY.cumulative)
)

在我的系统上需要
   user  system elapsed 
4.708 0.000 4.410

可接受的执行时间将少于一秒......是否可以使用纯 R 实现这一目标?

这篇文章链接到 Optimize moving averages calculation - is it possible?我没有收到任何答复。我现在能够创建一个可重现的示例,其中更详细地解释了我想要加速的内容。我希望这个问题现在更有意义。

任何有关如何加快速度的想法都受到高度赞赏。

最佳答案

我还没有找到一个令人满意的解决方案来解决我使用 R 的问题。所以我使用了旧工具,c 语言,结果比我预期的要好。感谢您使用 Rcpp、inline 等这些很棒的工具“插入”我。太棒了。我想,每当我将来有性能要求并且使用 R 无法满足时,我都会将 C 添加到 R 并且性能就在那里。因此,请在下面查看我的代码和性能问题的解决方案。

# How to speedup cumulative EMA calculation
#
###############################################################################

library(quantmod)
library(Rcpp)
library(inline)
library(rbenchmark)

do.call.rbind <- function(lst) {
while(length(lst) > 1) {
idxlst <- seq(from=1, to=length(lst), by=2)

lst <- lapply(idxlst, function(i) {
if(i==length(lst)) { return(lst[[i]]) }

return(rbind(lst[[i]], lst[[i+1]]))
})
}
lst[[1]]
}

to.period.cumulative <- function(x, name=NULL, period="days", numPeriods=15) {
if(is.null(name))
name <- deparse(substitute(x))

cnames <- c("Open", "High", "Low", "Close")
if (has.Vo(x))
cnames <- c(cnames, "Volume")

cnames <- paste(name, cnames, sep=".")

if (quantmod:::is.OHLCV(x)) {
x <- quantmod:::OHLCV(x)
out <- do.call.rbind(
lapply(split(x, f=period, k=numPeriods),
function(x) cbind(rep(first(x[,1]), NROW(x[,1])),
cummax(x[,2]), cummin(x[,3]), x[,4], cumsum(x[,5]))))
} else if (quantmod:::is.OHLC(x)) {
x <- OHLC(x)
out <- do.call.rbind(
lapply(split(x, f=period, k=numPeriods),
function(x) cbind(rep(first(x[,1]), NROW(x[,1])),
cummax(x[,2]), cummin(x[,3]), x[,4])))
} else {
stop("Object does not have OHLC(V).")
}

colnames(out) <- cnames

return(out)
}

EMA.cumulative<-function(cumulativeBars, nEMA = 4, period="days", numPeriods=15) {
barsEndptCl <- Cl(cumulativeBars[endpoints(cumulativeBars, on=period, k=numPeriods)])

# TODO: This is sloooooooooooooooooow...
outEMA <- do.call.rbind(
lapply(split(Cl(cumulativeBars), period),
function(x) {
previousFullBars <- barsEndptCl[index(barsEndptCl) < last(index(x)), ]
if (NROW(previousFullBars) >= (nEMA - 1)) {
last(EMA(last(rbind(previousFullBars, x), n=(nEMA + 1)), n=nEMA))
} else {
xts(NA, order.by=index(x))
}
}))

colnames(outEMA) <- paste("EMA", nEMA, sep="")

return(outEMA)
}

EMA.c.c.code <- '
/* Initalize loop and PROTECT counters */
int i, P=0;

/* ensure that cumbars and fullbarsrep is double */
if(TYPEOF(cumbars) != REALSXP) {
PROTECT(cumbars = coerceVector(cumbars, REALSXP)); P++;
}

/* Pointers to function arguments */
double *d_cumbars = REAL(cumbars);
int i_nper = asInteger(nperiod);
int i_n = asInteger(n);
double d_ratio = asReal(ratio);

/* Input object length */
int nr = nrows(cumbars);

/* Initalize result R object */
SEXP result;
PROTECT(result = allocVector(REALSXP,nr)); P++;
double *d_result = REAL(result);

/* Find first non-NA input value */
int beg = i_n*i_nper - 1;
d_result[beg] = 0;
for(i = 0; i <= beg; i++) {
/* Account for leading NAs in input */
if(ISNA(d_cumbars[i])) {
d_result[i] = NA_REAL;
beg++;
d_result[beg] = 0;
continue;
}
/* Set leading NAs in output */
if(i < beg) {
d_result[i] = NA_REAL;
}
/* Raw mean to start EMA - but only on full bars*/
if ((i != 0) && (i%i_nper == (i_nper - 1))) {
d_result[beg] += d_cumbars[i] / i_n;
}
}

/* Loop over non-NA input values */
int i_lookback = 0;
for(i = beg+1; i < nr; i++) {
i_lookback = i%i_nper;

if (i_lookback == 0) {
i_lookback = 1;
}
/*Previous result should be based only on full bars*/
d_result[i] = d_cumbars[i] * d_ratio + d_result[i-i_lookback] * (1-d_ratio);
}

/* UNPROTECT R objects and return result */
UNPROTECT(P);
return(result);
'

EMA.c.c <- cfunction(signature(cumbars="numeric", nperiod="numeric", n="numeric", ratio="numeric"), EMA.c.c.code)

EMA.cumulative.c<-function(cumulativeBars, nEMA = 4, period="days", numPeriods=15) {
ratio <- 2/(nEMA+1)

outEMA <- EMA.c.c(cumbars=Cl(cumulativeBars), nperiod=numPeriods, n=nEMA, ratio=ratio)

outEMA <- reclass(outEMA, Cl(cumulativeBars))

colnames(outEMA) <- paste("EMA", nEMA, sep="")

return(outEMA)
}

getSymbols("SPY", from="2010-01-01")

SPY.cumulative <- to.period.cumulative(SPY, name="SPY")

system.time(
SPY.EMA <- EMA.cumulative(SPY.cumulative)
)

system.time(
SPY.EMA.c <- EMA.cumulative.c(SPY.cumulative)
)


res <- benchmark(EMA.cumulative(SPY.cumulative), EMA.cumulative.c(SPY.cumulative),
columns=c("test", "replications", "elapsed", "relative", "user.self", "sys.self"),
order="relative",
replications=10)

print(res)

编辑:为了表明性能比我的笨重有所改进(我相信它可以做得更好,因为实际上我已经创建了双循环)R 这里是一个打印输出:
> print(res)
test replications elapsed relative user.self
2 EMA.cumulative.c(SPY.cumulative) 10 0.026 1.000 0.024
1 EMA.cumulative(SPY.cumulative) 10 57.732 2220.462 56.755

所以,按照我的标准,SF 类型的改进......

关于r - 加速 WMA(加权移动平均)计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8720055/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com