2012-01-03 121 views
4

我试图计算15天线条上的指数移动平均线,但希望看到15日线条EMA在每个(尾)日/线条上的“演变”。所以,这意味着我有15天的酒吧。当每天都有新的数据出现时,我想使用新的信息重新计算EMA。其实我有15天的酒吧,然后,每天过后,我新的15天酒吧开始增长,每个新酒吧应该用于EMA计算以及以前的整整15天的酒吧。加速WMA(加权移动平均线)的计算

假设我们从2012-01-01开始(本例中为每个日历日的数据),在2012-01-15年底,我们有第一个完整的15天吧。我们可以在2012-03-01完成4个完整的15天的条形图后,开始计算4 bar EMA(EMA(x,n = 4))。在2012年3月2日结束时,我们将使用我们目前为止的信息,并在2012-03-02计算EMA,假设2012-03-02的OHLC是15天的酒吧进行中。所以我们在2012-03-02拿4个完整的酒吧和酒吧并且计算EMA(x,n = 4)。然后,我们再等一天,看看正在进行的新的15天工作条发生了什么(有关详细信息,请参阅下面的函数to.period.cumulative),并计算EMA的新值......并且在接下来的15天之后... ...请参阅功能EMA.cumulative以下详细...

下面请找到我能够想出到现在。这种表现对我来说是不可接受的,而且我对有限的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 

可接受的执行时间将超过1秒,少...是否有可能实现这一目标使用纯的R?

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

任何想法如何加快这一点高度赞赏。

+0

嗯,那么我有一个问题。可以说我们每天都有数据。我想以15天为单位/小节计算4小时EMA(EMA(x,n = 4))。因此,使用to.period将日常数据转换为15天的酒吧。那很简单。我想得到的是我想每天在15天酒吧看到4天EMA的发展。就像您希望随着新数据持续进入EMA的实时图形(附近)一样。您将最后一次已知数据视为完整的15天条(即使它仅仅是3天“旧”)。然后你把你现在知道的和以前所有完整的15天酒吧和EMA计算出来。好点? – Samo 2012-01-03 23:51:29

+0

约书亚,谢谢你的好意。只是为了让你意识到边界和开始条件:我是一个兼职的无利可图的零售交易者/程序员与一个小交易账户,使之成为一个业余爱好(或编程练习)谁选择R作为支持我的交易平台(好吧,只有backtesting实际上)活动。我没有为任何法律实体的商业目的而开发此项服务。我非常感谢您在空闲时间提供的所有支持和所有支持。如果我没有“免费”的其他想法,那么我肯定会接受你的好意。 – Samo 2012-01-04 00:10:35

+0

约书亚,这个没有收入,对不起。感谢您推动我学习如何在R中使用C.感谢TTR中的C和Fortran代码。 – Samo 2012-01-15 21:37:53

回答

6

我还没有找到一个令人满意的解决方案,我的问题使用R.所以我采用了旧的工具,c语言,结果比我预想的要好。感谢您使用Rcpp的这些优秀工具“推”我,内联等。令人惊叹。我想,只要我将来有性能需求,并且无法使用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) 

编辑:为了让过我麻烦的性能改进的指示(我相信它可以变得更好,因为实际上我已经创建了双重的for循环)这里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类型的改善...

+0

感谢您分享此代码并展示C等的实用程序。您对示例的时间有何评论?即'benchmark()'调用的输出是什么? – Iterator 2012-01-18 13:41:43

+0

我对性能改进感到兴奋(请参阅编辑后)。这是可以预料的,因为在我的R代码(由注释#TODO表示:这是sloooooooooooooooooow ...)我已经有效地创建了一个使用rbind和lapply的double循环。但是我的R技能是基本能够使用R恢复到C的性能提高...... – Samo 2012-01-21 12:14:51