Skip to content
All library documents

Calculating Maximum Drawdown from Cumulative Trade P&L

Article Quant Q&A · Author: djhanson

Summary

The document investigates why Monte Carlo resamples of trade profit and loss produced clustered maximum drawdown values instead of the expected bell-shaped distribution. The key issue is that the input values are individual P&L observations, while drawdown measures declines in a cumulative equity or profit-and-loss path. Applying a drawdown calculation directly to the unsummed observations does not represent that path.

The answer explains that the largest observed positive and negative P&L values can create repeated extreme results when they occur next to each other in a random ordering. It recommends first taking the cumulative sum of the resampled P&L sequence and then calculating drawdown. It also reports a drawdown result from that corrected approach. The discussion addresses this implementation issue in one dataset and resampling setup; it does not establish the shape of drawdown distributions generally or evaluate confidence bounds from the simulations.

Key ideas

  • Maximum drawdown should be measured on a cumulative P&L or equity path.
  • Applying a drawdown function directly to individual trade P&L values can produce misleading results.
  • Random adjacency of extreme gains and losses can create repeated extreme values in the flawed calculation.
  • Cumulatively sum each resampled P&L sequence before calculating its drawdown.

Tags

Full text
# Clustering of Maximum Drawdown Values in Monte Carlo Simulations (Jaekle & Tomasini example)


# Clustering of Maximum Drawdown Values in Monte Carlo Simulations (Jaekle & Tomasini example)












Hope this question isn't too naive. I've been trying to replicate the Monte Carlo method using sampling without replacement as described in the Jaekle & Tomasini book (Trading Systems: A New Approach to System Development and Portfolio Optimisation, 2nd Edition, Ch 4, pp 84-89). I took the P/L trade values from Luxor (GBP/USD) strategy results in the `luxor-p066.RData` dataset that accompanies the quantstrat R package. I wrote a little R script to store the trade P/L values in a vector, sample without replacement, and calculate the maximum drawdown for each simulation. My results, however, seem strange, as they cluster at the highest maximum drawdown, as shown in the section following the code below.

My R code is as follows:

```
data("luxor-p066")
pnl <- portfolio.luxor$symbols$GBPUSD$txn[, "Gross.Txn.Realized.PL"]
head(pnl)   # Check
indices <- which(pnl == 0)   # Remove trade entries (P/L = 0) 
pnl <- pnl[-indices]
pnl_df <- data.matrix(as.data.frame(pnl))   # Convert xts to vector

max_drawdown <- function(vec)
{
  peak <- vec[1]
  max_dd <- 0.0
  
  for (k in 1:length(vec))
  {
    if(vec[k] < peak)
      max_dd = max(peak - vec[k], max_dd)
   else if(peak < vec[k])
    peak = vec[k]
  }
  return(max_dd)
}

# Sanity check
max_drawdown(pnl_df)    # 14670

max_dd_vec <- vector("numeric")
for(k in 1:100)
{
  max_dd_vec <- c(max_dd_vec, max_drawdown(sample(pnl_df)))
}

(sort(max_dd_vec, decreasing = TRUE))
```

The output is as follows:

```
# Note the clustering at worst Max DD = 17137
# [1] 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137
# [15] 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137
# [29] 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137 17137
# [43] 16307 16307 16307 16307 16307 16307 16307 16307 16307 16307 16307 16307 16307 16307
# [57] 16307 16307 16307 16307 16307 16307 16307 16307 15067 15067 15067 15067 15067 14670
# [71] 14670 14670 14670 14670 14670 14670 14670 14670 14670 14670 14670 14520 14520 14520
# [85] 14520 14260 14260 14260 14260 13840 13840 13840 13730 13727 13727 13727 13727 13727
# [99] 13727 13380
```

In the Jaekle & Tomasini book, they seem to imply (albeit via a coin toss example) that the resulting distribution should be somewhat bell-shaped, from which one should be able to determine lower confidence bounds on worst possible maximum drawdown, but this is not what I'm seeing. Instead, it resembles more of a cumulative distribution, which I have not found discussed in the book.

Could someone perhaps explain this? Am I doing something wrong, or am I in fact generating an empirical CDF?

Thanks in advance.

## Answer by Enrico Schumann (score 1)

https://quant.stackexchange.com/a/77081

I do not know the book or that dataset (which, I think, is from package `quantstrat`?). But it seems that your `pnl` is daily profit/loss. But drawdown is computed on the cumulative profit/loss.

Here is why you get 17137:

```
## sort(coredata(pnl))
##   [1] -7570 -6740 -5500 -4160 -4035 -3970 -3750 -3625 -3550
##  [10] -3250 -3240 -3220 -3152 -3053 -2640 -2520 -2480 -2440
## ## ....
## [253]  4050  4260  4420  4480  5810  6060  6160  6690  6950
## [262]  7100  9567
```

Whenever the two extremes end up next to each other, then you get `9567+7570 == 17137`.

Try to use `cumsum` around `pnl`:

```
max_drawdown(cumsum(pnl_df))
## [1] 17370

NMOF::drawdown(cumsum(pnl_df), relative = FALSE)
## $maximum
## [1] 17370
## 
## $high
## [1] 35830
## 
## $high.position
## [1] 128
## 
## $low
## [1] 18460
## 
## $low.position
## [1] 163
```

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.