# Global Maximum Drawdown and Maximum Drawdown Duration Implementation in Python

Following along with E.P. Chan’s book, I’m attempting to calculate the maximum drawdown and the longest drawdown duration from cumulative portfolio returns. He codes it in MATLAB, but I wanted to try my hand at the same code in Python.

import pandas as pd

def drawdownCalculator(data):
highwatermark = data.copy()
highwatermark[:] = 0
drawdown = data.copy()
drawdown[:] = 0
drawdownduration = data.copy()
drawdownduration[:]=0
t = 1
while t <= len(data):
highwatermark[t] = max(highwatermark[t-1], data[t])
drawdown[t] = (1 + highwatermark[t])/(1 + data[t]) - 1
if drawdown[t] == 0:
drawdownduration[t] = 0
else:
drawdownduration[t] = drawdownduration[t-1] + 1
t += 1
return drawdown.max(), drawdownduration.max()
max_drawdown, max_drawdown_time = drawdownCalculator(cumulative_returns) #cumulative_returns is a Pandas series


I thought I had it figured out, but I’m getting the following error:

return self._engine.get_value(s, k, tz=getattr(series.dtype, "tz", None))
File "pandas/_libs/index.pyx", line 80, in pandas._libs.index.IndexEngine.get_value
File "pandas/_libs/index.pyx", line 88, in pandas._libs.index.IndexEngine.get_value
File "pandas/_libs/index.pyx", line 131, in pandas._libs.index.IndexEngine.get_loc
File "pandas/_libs/hashtable_class_helper.pxi", line 992, in pandas._libs.hashtable.Int64HashTable.get_item
File "pandas/_libs/hashtable_class_helper.pxi", line 998, in pandas._libs.hashtable.Int64HashTable.get_item
KeyError: 0


Quantitative Finance Asked by DickyBrown on March 2, 2021

I'm guessing your Series is indexed by a timestamp, which would explain why accessing by an integer doesn't work. But I can't tell for sure since you haven't shown us any data.

The good news is that I don't need that anyway. Here is a more idiomatic way to compute what you want:

highwatermarks = cumulative_returns.cummax()

drawdowns = (1 + highwatermarks)/(1 + cumulative_returns) - 1

max_drawdown = max(drawdowns)


There is no simple way to compute duration with array notation. Fortunately, this question shows how to use an accumulator for exactly your scenario:

from itertools import accumulate

drawdown_times = (drawdowns > 0).astype(np.int64)

max_drawdown_time = max(accumulate(drawdown_times, lambda x,y: (x+y)*y))


Alternatively, you can group the consecutive durations together. I don't recommend this approach, but I'll include it for posterity:

max_drawdown_time = drawdown_times.groupby((drawdown_times != drawdown_times.shift()).cumsum()).cumsum().max()


Correct answer by chrisaycock on March 2, 2021

In addition to chrisaycock's answer, we could also normalize the maximum drawdown with the high wartermarks instead of the current cumulative returns.

highwatermarks = cumulative_returns.cummax()
drawdowns = 1 - (1 + cumulative_returns) / (1 + highwatermarks)
max_drawdown = max(drawdowns)


Here we observe the drawdown definition defined here. $$MDD=frac{Trough Value−Peak Value}{Peak Value}$$

Answered by Kevin on March 2, 2021

## Related Questions

### Is there a reason why futures and options have more substitutes than other financial instruments?

1  Asked on March 11, 2021 by lithium123

### Global Maximum Drawdown and Maximum Drawdown Duration Implementation in Python

2  Asked on March 2, 2021 by dickybrown

### GARCH model using high frequency price return

1  Asked on February 25, 2021

### when deep itm european options time value increase from negative to positive

0  Asked on February 16, 2021 by wei-wu

### For option spreads, why ought the debit paid $le 75%$ of the strike width?

1  Asked on February 10, 2021

### Differentiability of solutions of a stochastic differential equation

1  Asked on February 9, 2021 by user144410

### Is there any website for a detail chronological description of U.S. index futures market development?

1  Asked on February 8, 2021 by tsz-chun-leung

### QuantLib python ql.schedule getting end of month dates

2  Asked on February 8, 2021 by user51725

### How to link market risk and the transition to the new risk-free rates?

0  Asked on February 8, 2021 by browl

### An example of Feynman-Kac

0  Asked on February 6, 2021 by moh514

### Credit VaR for this portfolio assuming no default correlation and no recovery?

0  Asked on February 5, 2021

### Mapping One symbol’s Support/Resistance to another Symbol

1  Asked on February 4, 2021 by rc76

### Volatility of multimodal distribution of returns

0  Asked on February 3, 2021 by vivek-subramanian

### What is the importance of alpha, beta, rho in the SABR volatility model?

3  Asked on January 25, 2021 by user330060

### Is there any way to get a list of all trades that took place for a stock?

3  Asked on January 23, 2021 by dirtside

### Software for backtesting outside strategies (CSV transaction upload)

5  Asked on January 20, 2021 by dordal

### Pricing deep OTM and short expiry options with Monte Carlo methods

0  Asked on January 17, 2021 by ffbzona

### Obtain order level data for German stocks

0  Asked on January 15, 2021 by user49942

### How does Bloomberg calculate beta?

0  Asked on January 8, 2021 by friedrich