joshuaulrich / xts

Extensible time series class that provides uniform handling of many R time series classes by extending zoo.
http://joshuaulrich.github.io/xts/
GNU General Public License v2.0
220 stars 71 forks source link

a bug in plot.xts() and a possible solution / feature request #126

Open cloudcell opened 8 years ago

cloudcell commented 8 years ago

This code was extracted (with minor modifications/additions) from quantstrat::chart.forward.training and based on the data supplied with demo(luxor.sample.walk.forward), using R 3.2.2 on Windows 7.

require(devtools) # version 1.9.1
install_github("joshuaulrich/xts") # as of 2015 November 07
require(quantstrat) # version 0.9.1687
audit.filename <- (paste0(path.package("quantstrat"),"/data/luxor.wfa.ples.RData"))

.audit <- NULL
load(audit.filename)
portfolios.st = ls(name = .audit, pattern = "portfolio.*")
n <- length(portfolios.st)
PL.xts <- xts()
for (portfolio.st in portfolios.st) {
  p <- getPortfolio(portfolio.st, envir = .audit)
  from <- index(p$summary[2])
  R <- cumsum(p$summary[paste(from, "/", sep = ""), "Net.Trading.PL"])
  names(R) <- portfolio.st
  PL.xts <- cbind(PL.xts, R)
}
chosen.one <- .audit$param.combo.nr
chosen.portfolio.st = ls(name = .audit, pattern = glob2rx(paste("portfolio",
                                                                "*", chosen.one, sep = ".")))
R <- PL.xts[, chosen.portfolio.st]
PL.xts <- cbind(PL.xts, R)
PL.xts <- na.locf(PL.xts)
CumMax <- cummax(PL.xts)
Drawdowns.xts <- -(CumMax - PL.xts)
data.to.plot <- as.xts(cbind(PL.xts, Drawdowns.xts))

# DEMONSTRATION OF THE BUG:
# Clears each panel before drawing, so instead of 32 lines, there are only 2
plot.xts(data.to.plot,multi.panel=2,main='Walk Forward Analysis',
        col = c(rep("grey", n), "blue"))

# FEATURE SUGGESTION AS A POSSIBLE SOLUTION:
# Vectorized panel plot ordering would be nice (seems it's not currently implemented)
on_ = c(rep(1,n+1),rep(2,n+1))
plot.xts(data.to.plot,multi.panel=2,main='Walk Forward Analysis',
         col = c(rep("grey", n), "blue"), on=on_)
rossb34 commented 8 years ago

cloudcello, thank you for the reproducible example. From the ?plot.xts and the multi.panel argument, For example, if multi.panel = 2, then the data will be plotted in groups of 2 columns and each group is plotted in a separate panel. In your example, calling plot.xts with multi.panel=2 is actually creating 15 plot windows with 2 panels in each window. Also explained in the documentation, on is not an argument for plot.xts, it is an argument for lines.xts and points.xts.

This should produce the plot you are looking for

plot(PL.xts, col=c("blue", rep("grey", n-1)), main="Walk Forward Analysis")
# set on=NA so it is drawn on a new panel
lines(Drawdowns.xts, col=c("blue", rep("grey", n-1)), on=NA, main="Drawdowns")

I think we may have a bug with multi.panel behavior that I need to explore further.

cloudcell commented 8 years ago

Thank you for the solution, Ross. I definitely missed that option ("on=NA") while reading help. Also, I'm glad this has been helpful. Just one more comment: I think the code must nevertheless be as follows (as the total number of lines drawn is not n, but rather n+1:

plot(PL.xts, col=c("blue", rep("grey", n)), main="Walk Forward Analysis")
# set on=NA so it is drawn on a new panel
lines(Drawdowns.xts, col=c("blue", rep("grey", n)), on=NA, main="Drawdowns")