首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >加速WMA (加权移动平均)计算

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

Stack Overflow用户
提问于 2012-01-04 07:20:04
回答 1查看 1.9K关注 0票数 4

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

假设我们从2012-01-01开始(对于这个例子,我们有每个日历日的数据),在2012-01-15结束时,我们有第一个完整的15天条形图。在2012-03-01完成了4个完整的15天条形之后,我们可以开始计算4个条形均线( EMA (x,n=4))。在2012-03-02年末,我们使用到现在为止的信息,计算2012-03-02的EMA,假装2012-03-02的OHLC是进行中的15天吧。因此,我们取4个完整的条形和2012-03-02的条形,并计算均方根均值(x,n=4)。然后我们再等一天,看看新的15天条在进行中发生了什么(详细信息请参见下面的函数to.period.cumulative ),并计算EMA的新值。所以在接下来的15天里...有关详细信息,请参阅下面的函数EMA.cumulative ...

请在下面找到我到目前为止所能想到的。性能对我来说是不可接受的,以我有限的R知识,我不能让它更快。

代码语言:javascript
复制
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)
)

在我的系统上

代码语言:javascript
复制
   user  system elapsed 
  4.708   0.000   4.410 

可接受的执行时间将少于一秒...是否有可能使用纯R来实现这一点?

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

任何关于如何加速这一过程的想法都将受到高度赞赏。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-01-16 05:36:08

我没有找到一个令人满意的解决方案,我的问题使用R,所以我使用旧的工具,c语言,结果比我预期的要好。感谢你“推”我使用这个伟大的工具的Rcpp,内联等。神奇。我想,当我将来有性能要求,而使用R不能满足时,我会将C添加到R中,性能就在那里。所以,请看下面我的代码和性能问题的解决方案。

代码语言:javascript
复制
# 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)

编辑:为了给出我笨拙的性能改进的指示(我相信它可以变得更好,因为实际上我已经创建了double for循环)R这里是一个打印输出:

代码语言:javascript
复制
> 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

所以,根据我的标准,一种科幻类型的改进...

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8720055

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档