5

在 quantstrat 包中,我找到了导致 applyRule 函数运行缓慢的主要原因之一,并想知道编写 while 循环是否更有效率。任何反馈都会有所帮助。对于任何有将此部分包装到 Parallel R 中的经验的人。

作为一个选项 apply 会代替而工作吗?或者我应该把这部分重新写成新的函数,比如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
}
4

1 回答 1

7

Garrett 的回答确实指向了 R-SIG-Finance 列表上的最后一次主要讨论,其中讨论了相关问题。

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

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

我们在 applyRules 内部构造了一个降维索引,这样我们就不必观察每个时间戳并检查它。我们只记录可以合理预期策略会在订单簿上起作用的特定时间点,或者可以合理预期订单会被执行的特定时间点。

这是状态相关路径相关的代码。在这种情况下,关于“矢量化”的闲谈没有任何意义。如果我需要了解当前的市场状态、订单簿和我的头寸,并且我的订单可能会被其他规则以时间相关的方式修改,我看不出如何将这段代码向量化。

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

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

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

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

  1. 编写一个不依赖路径的策略:这是代码支持的,简单的策略可以这样建模。在此模型中,您将编写一个自定义规则函数,当您认为应该得到满足时直接调用addTxn 。它可能是一个在您的指标/信号上运行的矢量化函数,并且应该非常快。
  2. 预处理你的信号:如果状态机需要评估订单簿/规则/投资组合的状态以查看它是否需要做某事的地方较少,则速度的增加几乎与信号的减少呈线性关系。这是大多数用户忽略的领域,编写信号函数并不真正评估何时可能需要修改仓位或订单簿的操作。
  3. 显式并行化部分分析问题:我通常编写显式并行包装器来分离不同的参数评估或符号评估,请参阅applyParameter以获取使用foreach的示例
  4. 在 C/C++ 中重写 applyRules 中的状态机:欢迎使用补丁,但请参阅 Garrett 发布的链接以获取更多详细信息。

我可以向你保证,如果对信号生成功能稍加注意,大多数策略可以在每个核心每天每个符号每核心分钟的一小部分内运行。不建议在笔记本电脑上运行大型回测。

参考:quantstrat - applyRules

于 2011-10-12T12:48:47.627 回答