سؤال

I'm using the blotter package to run a backtest, and using foreach to speed things up. I'm running into an error where blotter finds the portfolio with the same name even though they are supposed to be removed at the start of the function. Here's a sample code to reproduce the error

require('foreach')
require('doSNOW')
require('xts')
require('blotter')

backtestFunction <- function() {

  currency("USD")
  stock("AAPL", currency="USD", multiplier=1)
  Sys.setenv(TZ="US/Eastern")
  verbose = FALSE

  try(rm("account.Snazzy","portfolio.Snazzy",pos=.blotter),silent=TRUE)
  initPortf("Snazzy", "AAPL", initDate="2014-01-01", currency="USD")
  initAcct("Snazzy", portfolios="Snazzy", initDate="2014-01-01", initEq=1000, currency="USD")

  return (TRUE)
}

cl <- snow::makeCluster(8, type = "SOCK")
registerDoSNOW(cl)

results <- foreach(i=1:100, .combine=rbind, .packages=c('xts','blotter')) %dopar% {
  return (backtestFunction())
}
snow::stopCluster(cl)

Here's the error

Error in { : 
  task 9 failed - "Portfolio Snazzy already exists, use updatePortf() or addPortfInstr() to update it."

I understand that the portfolio and account objects are stored in the .blotter environment, however

  1. Wouldn't foreach spawn each worker in a new R session of sorts so that there will be no conflicts?
  2. Why didn't the try(rm("account.Snazzy","portfolio.Snazzy",pos=.blotter),silent=TRUE) work?
  3. How can I get foreach to work with blotter here?

If it matters, I'm using R 3.0.2, running RStudio on Windows. I'm including quantstrat in the tag because these are typically used together so its likely an experienced quantstrat user would know the fix. Thanks

هل كانت مفيدة؟

المحلول

The problem is that ".blotter" is being automatically exported to the workers, but to doSNOW's "export" environment, not to the global environment. This doesn't confuse the blotter package, but it does prevent your "rm" command from removing "account.Snazzy" and "portfolio.Snazzy" from the real ".blotter" environment.

One solution is to add .noexport=".blotter" to foreach. Another solution is to specify the environment more explicitly when executing "rm":

try(rm("account.Snazzy","portfolio.Snazzy",pos=.GlobalEnv$.blotter),
    silent=TRUE)

doSNOW doesn't spawn a worker for each task because that could be quite slow. Even for local workers, the time to launch an R session can be significant compared to the time to execute a task, especially on a cluster using ssh. And more importantly, if workers execute multiple tasks, you can send large data sets to them once, and reuse that data for many tasks, thus amortizing the communication costs.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top