2011-10-10 27 views
5

在quantstrat包中,我找到了applyRule函数缓慢的主要元凶之一,并想知道是否有更高效的编写while循环。任何反馈都会有帮助。对于任何经验包装这部分并行R.虽然循环R量子代码 - 如何使其更快?

作为一个选项申请将工作,而不是?还是应该将这部分重新写入新的函数,如ruleProc和nextIndex?我也在研究Rcpp,但这可能是一个streach。任何帮助和建设性的意见非常感谢?

while (curIndex) { 
    timestamp = Dates[curIndex] 
    if (isTRUE(hold) & holdtill < timestamp) { 
     hold = FALSE 
     holdtill = NULL 
    } 
    types <- sort(factor(names(strategy$rules), levels = c("pre", 
     "risk", "order", "rebalance", "exit", "enter", "entry", 
     "post"))) 
    for (type in types) { 
     switch(type, pre = { 
      if (length(strategy$rules[[type]]) >= 1) { 
       ruleProc(strategy$rules$pre, timestamp = timestamp, 
       path.dep = path.dep, mktdata = mktdata, portfolio = portfolio, 
       symbol = symbol, ruletype = type, mktinstr = mktinstr) 
      } 
     }, risk = { 
      if (length(strategy$rules$risk) >= 1) { 
       ruleProc(strategy$rules$risk, timestamp = timestamp, 
       path.dep = path.dep, mktdata = mktdata, portfolio = portfolio, 
       symbol = symbol, ruletype = type, mktinstr = mktinstr) 
      } 
     }, order = { 
      if (length(strategy$rules[[type]]) >= 1) { 
       ruleProc(strategy$rules[[type]], timestamp = timestamp, 
       path.dep = path.dep, mktdata = mktdata, portfolio = portfolio, 
       symbol = symbol, ruletype = type, mktinstr = mktinstr,) 
      } else { 
       if (isTRUE(path.dep)) { 
       timespan <- paste("::", timestamp, sep = "") 
       } else timespan = NULL 
       ruleOrderProc(portfolio = portfolio, symbol = symbol, 
       mktdata = mktdata, timespan = timespan) 
      } 
     }, rebalance = , exit = , enter = , entry = { 
      if (isTRUE(hold)) next() 
      if (type == "exit") { 
       if (getPosQty(Portfolio = portfolio, Symbol = symbol, 
       Date = timestamp) == 0) next() 
      } 
      if (length(strategy$rules[[type]]) >= 1) { 
       ruleProc(strategy$rules[[type]], timestamp = timestamp, 
       path.dep = path.dep, mktdata = mktdata, portfolio = portfolio, 
       symbol = symbol, ruletype = type, mktinstr = mktinstr) 
      } 
      if (isTRUE(path.dep) && length(getOrders(portfolio = portfolio, 
       symbol = symbol, status = "open", timespan = timestamp, 
       which.i = TRUE))) { 
      } 
     }, post = { 
      if (length(strategy$rules$post) >= 1) { 
       ruleProc(strategy$rules$post, timestamp = timestamp, 
       path.dep = path.dep, mktdata = mktdata, portfolio = portfolio, 
       symbol = symbol, ruletype = type, mktinstr = mktinstr) 
      } 
     }) 
    } 
    if (isTRUE(path.dep)) 
     curIndex <- nextIndex(curIndex) 
    else curIndex = FALSE 
} 
+0

我怀疑问题是固有的'while',但'while'内无论发生什么情况。你的代码似乎没有做任何事情 - 没有赋值或返回值。所以你必须运行这个,因为'ruleProc'的副作用。如果其中一个副作用是你在其他地方赋值,我会从重构开始。根据我的经验,在结果列表中使用'lapply'和'do.call'通常比使用'[<-''选择性分配更快。 – Andrie

+0

如果您发布了每个提供的每个基础数据结构的玩具示例,那么我认为'for'可以是矢量化的。而且,像nextIndex和ruleProc这样的函数也需要被显示。只有在这之后,有人才能对“while”循环做出很好的评估。 – John

+0

好的,只是查找了这个代码...尝试先获得ruleProc矢量化。事实上,如果'ruleProc'是这个代码非常慢的例子,那么你可以轻松地进行大幅加速,几乎没有任何想法。通过'ruleProc'并把所有的东西都从包含整个函数的巨大'for'循环中移出。很多。如果你不能自己做那部分,然后张贴它进行矢量化。但先行动吧。 – John

回答

7

加勒特的回答确实指向了R-SIG金融名单上最后一次讨论相关问题的主要讨论。

quantstrat中的applyRules函数绝对是大部分时间都花在哪里的地方。

在此问题中复制的while循环代码是applyRules执行的路径依赖部分。我相信所有这些都包含在文档中,但我将简要回顾一下SO的后代。

我们构建内部applyRules降维的索引,这样我们就不必遵守每一个时间戳和检查。我们只注意策略可能合理预期在订单簿上执行的具体时间点,或者可合理预期订单被填充的时间点。

这是状态依赖路径依赖代码。在这种情况下,闲谈“矢量化”并没有任何意义。如果我需要了解市场的当前状态,订单和我的位置,并且如果我的订单可能会按照其他规则以时间依赖方式进行修改,那么我不会看到如何将此代码进行矢量化。

从计算机科学的角度来看,这是一台状态机。几乎所有我能想到的语言中的状态机通常写成while循环。这不是真的谈判或改变。

的问题询问是否使用适用会有所帮助。 R中的应用语句被实现为循环,所以不,它不会帮助。即使是并行应用,例如mclapply的foreach不能帮助,因为这是代码的状态相关的部分内。评估不同的时间点而不考虑状态没有任何意义。您会注意到quantstrat的非状态依赖部分在任何可能的情况下都是矢量化的,并且只占运行时间的很少部分。

John发表的评论建议删除中的for循环ruleProc。 for循环所做的就是在此时检查与策略相关的每个规则。该循环中唯一的计算密集型部分是调用规则函数的do.call。 for循环的其余部分仅仅是为这些函数定位和匹配参数,而从代码剖析来看,并不需要太多时间。在这里使用并行应用也没什么意义,因为规则函数按类型顺序应用,因此可以在新条目指令之前应用取消或风险指令。就像数学有一个操作订单一样,或者银行有一个存款/提款处理订单,Quantstrat有一个规则类型评估订单,如文档中所述。

要加快执行速度,也有可以做的四个主要方面:

  1. 写一个非路径依赖的战略:这是由代码的支持,简单的策略,可以模拟这种方式。在这个模型中,你会写一个自定义规则函数,当你认为你应该得到你的填充时直接调用addTxn。它可能是一个矢量化的功能,可以根据您的指标/信号进行操作,并且速度应该非常快。
  2. 预处理您的信号:如果状态机需要评估订单簿/规则/组合的状态以查看它是否需要执行某些操作的位置较少,那么速度增加几乎与减少信号。这是大多数用户忽视的领域,写信号功能并不真正评估何时可能需要修改位置或订单簿的操作。
  3. 显式并行您的分析问题的部分:我一般写显式并行包装分离出不同的参数评估或符号的评价,看到applyParameter使用的foreach一个例子
  4. 改写状态机内applyRules在C/C++:修补程序欢迎,但看到链接Garrett张贴的其他细节。

我可以向您保证,如果对信号生成函数采取一些小心的措施,大多数策略可以在每个核心每个符号每分钟核心分钟的时间内运行。不建议在笔记本电脑上运行大型备用测试。

编号:quantstrat - applyRules