在R量子代码中循环 - 如何使其更快?

时间:2011-10-10 12:28:25

标签: r while-loop quantstrat

在quantstrat包中,我找到了applyRule函数缓慢的主要罪魁祸首之一,并想知道是否有更高效的写入while循环。任何反馈都会有所帮助。任何人都可以将这部分包装成Parallel R.

作为一种选择,申请可以改为吗?或者我应该将此部分重新编写为新函数,例如ruleProc和nextIndex?我也在沉迷于Rcpp,但这可能是一个特殊的问题。非常感谢任何帮助和建设性的建议?

   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
}

1 个答案:

答案 0 :(得分:7)

Garrett的回答确实指出了关于R-SIG财务列表的最后一次重要讨论,其中讨论了相关问题。

quantstrat中的applyRules函数绝对是花费大部分时间的地方。

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

我们在applyRules中构建一个降维索引,这样我们就不必观察每个时间戳并检查它。我们只注意到可以合理地预期该策略会对订单执行的具体时间点,或者可能合理地预期订单将被填补的情况。

这是依赖于状态的路径相关的代码。在这种背景下,对“矢量化”的闲谈没有任何意义。如果我需要知道市场的当前状态,订单和我的位置,如果我的订单可能会被其他规则以时间依赖的方式修改,我看不出这个代码是如何被矢量化的。

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

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

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

为了加快执行速度,可以做四件事:

  1. 编写非路径依赖策略:代码支持此功能,可以通过这种方式对简单策略进行建模。在这个模型中,你会编写一个自定义规则函数,当你认为你应该得到你的填充时直接调用 addTxn 。它可能是一个操作指标/信号的矢量化函数,应该非常快。
  2. 预处理您的信号:如果状态机需要评估订单簿/规则/组合的状态以查看是否需要执行某些操作的地方较少,则速度几乎会提高与信号减少呈线性关系。这是大多数用户忽视的区域,编写的信号函数并不真正评估何时需要采取行动来修改位置或订单簿。
  3. 显式并行化部分分析问题:我通常会明确地编写并行包装来分隔出不同的参数评估或符号评估,请参阅 applyParameter 以获取的示例foreach
  4. 在C / C ++中重写applyRules中的状态机:欢迎使用补丁,但请参阅Garrett发布的链接以获取更多详细信息。
  5. 我可以向您保证,如果对信号生成功能稍加注意,大多数策略可以在每个核心每个核心每分钟的核心分钟上运行。不建议在笔记本电脑上运行大型背景测试。

    参考:quantstrat - applyRules