Given a time series, I want to calculate the maximum drawdown, and I also want to locate the beginning and end points of the maximum drawdown so I can calculate the duration. I want to mark the beginning and end of the drawdown on a plot of the timeseries like this:
So far I've got code to generate a random time series, and I've got code to calculate the max drawdown. If anyone knows how to identify the places where the drawdown begins and ends, I'd really appreciate it!
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# create random walk which I want to calculate maximum drawdown for:
T = 50
mu = 0.05
sigma = 0.2
S0 = 20
dt = 0.01
N = round(T/dt)
t = np.linspace(0, T, N)
W = np.random.standard_normal(size = N)
W = np.cumsum(W)*np.sqrt(dt) ### standard brownian motion ###
X = (mu-0.5*sigma**2)*t + sigma*W
S = S0*np.exp(X) ### geometric brownian motion ###
plt.plot(S)
# Max drawdown function
def max_drawdown(X):
mdd = 0
peak = X[0]
for x in X:
if x > peak:
peak = x
dd = (peak - x) / peak
if dd > mdd:
mdd = dd
return mdd
drawSeries = max_drawdown(S)
MaxDD = abs(drawSeries.min()*100)
print MaxDD
plt.show()
Then for j: xs[:i] takes all the points from the start of the period until point i, where the max drawdown concludes. np. argmax(xs[:i]) finds the location/index of the highest (maximum) point in the graph up till that point, so that is the peak we are looking for.
The drawdown duration is the length of any peak to peak period, or the time between new equity highs. The max drawdown duration is the worst (the maximum/longest) amount of time an investment has seen between peaks (equity highs).
You can get this using a pandas rolling_max to find the past maximum in a window to calculate the current day's drawdown, then use a rolling_min to determine the maximum drawdown that has been experienced.
Just find out where running maximum minus current value is largest:
n = 1000 xs = np.random.randn(n).cumsum() i = np.argmax(np.maximum.accumulate(xs) - xs) # end of the period j = np.argmax(xs[:i]) # start of period plt.plot(xs) plt.plot([i, j], [xs[i], xs[j]], 'o', color='Red', markersize=10)
behzad.nouri solution is very clean, but it's not a maximum drawdow (couldn't comment as I just opened my account and I don't have enough reputation atm).
What you end up having is the maximum drop in the nominal value rather than a relative drop in value (percentage drop). For example, if you would apply this to time series that is ascending over the long run (for example stock market index S&P 500), the most recent drop in value (higher nominal value drops) will be prioritized over the older decrease in value as long as the drop in nominal value/points is higher.
For example S&P 500:
By applying this method to period after 2000, you'll see Corona Virus Crisis rather than 2007-08 Financial Crisis
Related code (from behzad.nouri) below:
n = 1000
xs = np.random.randn(n).cumsum()
i = np.argmax(np.maximum.accumulate(xs) - xs) # end of the period
j = np.argmax(xs[:i]) # start of period
plt.plot(xs)
plt.plot([i, j], [xs[i], xs[j]], 'o', color='Red', markersize=10)
You just need to divide this drop in nominal value by the maximum accumulated amount to get the relative ( % ) drawdown.
( np.maximum.accumulate(xs) - xs ) / np.maximum.accumulate(xs)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With