4

I'm learning R (and its application to trading tasks via quantmod lib) and looking through the community pretty regularly to get a lot of new knowledge and tricks from here. My impression about R in general and quantmod lib in particular - it's awesome.

At this point I need help of seasoned R users. I'm using timeseries downloaded via getSymbols and I need to calculate cumulative growth/drawdown from local minimum/maximum respectively.

I can solve my task using FOR cycles as well as I can do necessary modelling in MS Excel, but I want to figure out more simple solution that does not require FOR cycles and that is more "native" in R.

Example. Input data:

20121121    79810
20121122    79100
20121123    80045
20121126    81020
20121127    80200
20121128    81350
20121129    81010
20121130    80550
20121203    80780
20121204    81700
20121205    83705
20121206    83350
20121207    83800
20121210    85385

Result:

            CLOSE   Cumulative gr/dd
20121121    79810   N/A
20121122    79100   0.58%
20121123    80045   1.55%
20121126    81020   2.37%
20121127    80200   -0.10%
20121128    81350   0.06%
20121129    81010   -0.76%
20121130    80550   -0.82%
20121203    80780   0.73%
20121204    81700   3.78%
20121205    83705   5.19%
20121206    83350   -1.50%
20121207    83800   1.67%
20121210    85385   2.22%
Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
UncleKo
  • 61
  • 2
  • 7
  • 3
    You assume that people here are familiar with calculate cumulative growth/drawdown concepts.Can you detail how you obtain "Cumulative gr/dd"? – agstudy Feb 06 '13 at 20:32
  • 1
    ..to take @agstudy's point further: maybe make the data set fewer rows and highlight exactly the steps you take to calculate 0.58% 1.55% and so on with a `for` loop.. then perhaps we can help you improve it :) – Anthony Damico Feb 06 '13 at 20:41
  • Yes, you both are correct. I should have provided more details and sample code (with FOR) to clarify the task. I'll so so as soon as I get to my home PC with R. Simply - while the asset is growing, we calculate cumulative ROC. When asset starts falling - we start calculating cumulative ROC from the local maximum (point where the asset finished growing and started falling). When the asset stops falling and starts growing again - we start calculating cumulative ROC from local minimum (i.e. the point where the asset has stopped falling and started new wave of growing). – UncleKo Feb 07 '13 at 08:10
  • I've solved my task after some googling and trials-and-errors and updated initial post with my results, for reference. – UncleKo Feb 10 '13 at 07:29
  • @UncleKo, instead of adding "Solved" to the title of your question you should post your solution as an answer and accept it. – Julius Vainora Feb 10 '13 at 11:48
  • Ok, did as you suggested. Thanks. – UncleKo Feb 10 '13 at 13:35

4 Answers4

1

The calculation is already in the tseries package as function maxdrawdown. Here is the beginning of its example:

mxdrwdR> # Toy example
mxdrwdR> x <- c(1:10, 9:7, 8:14, 13:8, 9:20)

mxdrwdR> mdd <- maxdrawdown(x)

mxdrwdR> mdd
$maxdrawdown
[1] 6

$from
[1] 20

$to
[1] 26

Turning this into percentages is pretty easy -- look at the (short) code of the function itself.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • Thanks, this was not exactly what I was looking for, but helped me to proceed with googling and finally solve the task. I've updated the post and provided my code. Thanks again! – UncleKo Feb 10 '13 at 07:29
1

To complement Dirk's answer, the PerformanceAnalytics package has various drawdown options. Here is an excerpt from some of my code, that also shows the growth calculation (and sharpe ratio, as a bonus):

#x is an xts object containing OHLC data
profit=ROC(x$Close)
growth=sum(na.omit(profit)),
equity=exp(sum(na.omit(profit))),
sharpe=as.vector(SharpeRatio.annualized(profit)),
maxDrawdown=maxDrawdown(profit)
Darren Cook
  • 27,837
  • 13
  • 117
  • 217
  • Thanks, this was not exactly what I was looking for, but helped me to proceed with googling and finally solve the task. I've updated the post and provided my code. Thanks again! – UncleKo Feb 10 '13 at 07:30
1

Finally, I've managed to solve it. Dirk and Darren, many thanks for your comments - the "maxdrawdown" function from PerformanceAnalytics package was not exactly what I needed, but this made me paying attention to PerformanceAnalytics and make some search through this site and the Internet. The findDrawdowns function from the same package that was close to my need, but anyway was not exacly what I was looking for (it needs the last high to be updated to start calculating new drawdown, while I need even local maxima and minima to be taken into account). Making further trials-and-errors, I made my own code that solves my task without FOR cycles. :) Here is the code. As a bonus - it returns vector with number of bars of constant growing/falling of the asset. I'll be happy if anyone can advise how to improve it.

library(rusquant)
library(quantmod)
library(tseries)

na.zero <- function(x) {
  tmp <- x
  tmp[is.na(tmp)] <- 0

  return(tmp)
}

my.cumulative.grdd <- function(asset) {
  # creating list for temporary data
  tmp <- list()
  # 
  #   tmp$asset.lag <- na.locf(lag(asset), fromLast=TRUE)

  # calculating ROC for the asset + getting ROC shifted by 1 element to the left and to the right
  # to compare ROC[i] and ROC[i+1] and ROC[i-1]
  tmp$asset.roc <- na.zero(ROC(asset))
  tmp$asset.roc.lag <- na.zero(lag(tmp$asset.roc))
  tmp$asset.roc.lag1 <- na.locf(lag(tmp$asset.roc, k=-1))

  # calculating indices of consequent growth/drawdown waves start and end
  tmp$indexfrom <- sapply(index(tmp$asset.roc[sign(tmp$asset.roc) * sign(tmp$asset.roc.lag) <= 0]), function(i) which(index(tmp$asset.roc) == i), simplify=TRUE)
  tmp$indexto <- c(sapply(index(tmp$asset.roc[sign(tmp$asset.roc) * sign(tmp$asset.roc.lag1) <= 0]), function(i) which(index(tmp$asset.roc.lag1) == i), simplify=TRUE), length(index(tmp$asset.roc)))

  # this is necessary to work around ROC[1] = 1
  tmp$indexfrom <- tmp$indexfrom[-2]
  tmp$indexto <- tmp$indexto[-1]

  # calculating dates of waves start/end based on indices
  tmp$datesfrom <- (sapply(tmp$indexfrom, FUN=function(x) format(index(asset)[x])))
  tmp$datesto <- (sapply(tmp$indexto, FUN=function(x) format(index(asset)[x])))
  tmp$dates <- apply(cbind(tmp$indexfrom, tmp$indexto), 2, FUN=function(x) format(index(asset)[x]))

  # merging dates for selection (i.e. "2012-01-02::2012-01-05") and calculation of cumulative product
  tmp$txtdates <- paste(tmp$datesfrom, tmp$datesto, sep="::")
  # extracting consequent growth/drawdowns
  tmp$drawdowns.sequences <- lapply(tmp$txtdates, function(i) tmp$asset.roc[i])
  # calculating cumulative products for extracted sub-series
  tmp$drawdowns.sequences.cumprods <- lapply(tmp$drawdowns.sequences, function(x) cumprod(1+x)-1)

  # generating final result
  result <- list()
  result$len <- tmp$indexto - tmp$indexfrom + 1
  result$cumgrdd <- xts(unlist(tmp$drawdowns.sequences.cumprods), index(tmp$asset.roc))

  return(result)
}

# let's test
getSymbols("SPY", from="2012-01-01")
spy.cl <- Cl(SPY)
spy.grdd <- my.cumulative.grdd(spy.cl)
spy.grdd
UncleKo
  • 61
  • 2
  • 7
1

you can use zig zag points to find the peaks and valleys and then calculate percent decrease/increase. for example

    s <- get(getSymbols('goog'))["2012::"]
    z <- ZigZag(s[,2:3],10,percent=TRUE)
    # 10 in this example is the sensitivity to changes. 
    # if you want to use closing prices use s instad of s[,2:3]

    # extract the extreme points
    z <- rbind(z[findPeaks(z)-1],z[findValleys(z)-1])
    # calculate the difference
    names(z) <- c("zig")
    z$PercentChange <- ((z - Lag(z)) / z) * 100 

hope it helps

haki
  • 9,389
  • 15
  • 62
  • 110