Reputation: 14400
I am a bit rusty with data.table
, I want to find the max drawdown of a serie X_t
(the maximal drawdown at any time t can be defined as argmin{X_T-X_t} where T>t
, in english, for each element of the time serie I need to find the element of the serie with T>t
such that minimize X_T-X-t, if the serie is increasing there is no drawdown).
library(data.table)
set.seed(1)
DT = data.table(x=rnorm(10))
DT[,cumsumX:=cumsum(x)]
#I am interested in the drawdown for cumsumX
DT
x cumsumX
1: -0.6264538107 -0.6264538107 => max drawdown is -1.27.. index 3 (-1.27+0.62 is mini)
2: 0.1836433242 -0.4428104865 => max drawdown is -1.27.. index 3 (-1.27+0.62 is mini)
3: -0.8356286124 -1.2784390989 => max drawdown is NA (-1.27 is global minima)
4: 1.5952808021 0.3168417032 => max drawdown is -0.17.. index 6
5: 0.3295077718 0.6463494750 ...
6: -0.8204683841 -0.1741189091
7: 0.4874290524 0.3133101433
8: 0.7383247051 1.0516348485
9: 0.5757813517 1.6274162001
10: -0.3053883872 1.3220278130
How can I find the maxdrawdow using data.table
Here is my solution
DT[,`:=`(dd=min(0,min(DT$cumsumX[.I:nrow(DT)])-cumsumX),ddIDX=.I-1L+which.min(DT$cumsumX[.I:nrow(DT)])),by=IDX]
DT
x cumsumX IDX dd ddIDX
1: -0.6264538 -0.6264538 1 -0.6519853 3
2: 0.1836433 -0.4428105 2 -0.8356286 3
3: -0.8356286 -1.2784391 3 0.0000000 3
4: 1.5952808 0.3168417 4 -0.4909606 6
5: 0.3295078 0.6463495 5 -0.8204684 6
6: -0.8204684 -0.1741189 6 0.0000000 6
7: 0.4874291 0.3133101 7 0.0000000 7
8: 0.7383247 1.0516348 8 0.0000000 8
9: 0.5757814 1.6274162 9 -0.3053884 10
10: -0.3053884 1.3220278 10 0.0000000 10
Upvotes: 2
Views: 436
Reputation: 49448
It seems like you want:
DT[, maxdrawdown := rev(cummin(rev(cumsumX)))]
DT[, index := .I[.N], by = maxdrawdown]
DT[cumsumX == min(cumsumX), `:=`(index = NA, maxdrawdown = NA)]
# x cumsumX maxdrawdown index
# 1: -0.6264538 -0.6264538 -1.2784391 3
# 2: 0.1836433 -0.4428105 -1.2784391 3
# 3: -0.8356286 -1.2784391 NA NA
# 4: 1.5952808 0.3168417 -0.1741189 6
# 5: 0.3295078 0.6463495 -0.1741189 6
# 6: -0.8204684 -0.1741189 -0.1741189 6
# 7: 0.4874291 0.3133101 0.3133101 7
# 8: 0.7383247 1.0516348 1.0516348 8
# 9: 0.5757814 1.6274162 1.3220278 10
#10: -0.3053884 1.3220278 1.3220278 10
Upvotes: 4
Reputation: 8041
Here is one possible approach:
# Load package
library(data.table)
# Generate data
set.seed(1)
DT = data.table(x=rnorm(10))
DT[,cumsumX:=cumsum(x)]
# Define number of rows in data table and index variable
DT$index <- rownames(DT)
length.DT <- nrow(DT)
# Calculate maxdrawdown
DT[ ,maxdrawdown:=min(DT$cumsumX[index:length.DT]), by=index]
# Substitute the minimum value of the entire column to be NA
DT$maxdrawdown[DT$cumsumX==min(DT$cumsumX)] <- NA
The result would look like this:
> DT
x cumsumX index maxdrawdown
1: -0.6264538 -0.6264538 1 -1.2784391
2: 0.1836433 -0.4428105 2 -1.2784391
3: -0.8356286 -1.2784391 3 NA
4: 1.5952808 0.3168417 4 -0.1741189
5: 0.3295078 0.6463495 5 -0.1741189
6: -0.8204684 -0.1741189 6 -0.1741189
7: 0.4874291 0.3133101 7 0.3133101
8: 0.7383247 1.0516348 8 1.0516348
9: 0.5757814 1.6274162 9 1.3220278
10: -0.3053884 1.3220278 10 1.3220278
Upvotes: 2