Start, End and Duration of Maximum Drawdown in Python Start, End and Duration of Maximum Drawdown in Python numpy numpy

Start, End and Duration of Maximum Drawdown in Python


Just find out where running maximum minus current value is largest:

n = 1000xs = np.random.randn(n).cumsum()i = np.argmax(np.maximum.accumulate(xs) - xs) # end of the periodj = np.argmax(xs[:i]) # start of periodplt.plot(xs)plt.plot([i, j], [xs[i], xs[j]], 'o', color='Red', markersize=10)

drawdown


on the back of this I added unerwater analysis if that helps anyone...

def drawdowns(equity_curve):    i = np.argmax(np.maximum.accumulate(equity_curve.values) - equity_curve.values) # end of the period    j = np.argmax(equity_curve.values[:i]) # start of period    drawdown=abs(100.0*(equity_curve[i]-equity_curve[j]))    DT=equity_curve.index.values    start_dt=pd.to_datetime(str(DT[j]))    MDD_start=start_dt.strftime ("%Y-%m-%d")     end_dt=pd.to_datetime(str(DT[i]))    MDD_end=end_dt.strftime ("%Y-%m-%d")     NOW=pd.to_datetime(str(DT[-1]))    NOW=NOW.strftime ("%Y-%m-%d")    MDD_duration=np.busday_count(MDD_start, MDD_end)    try:        UW_dt=equity_curve[i:].loc[equity_curve[i:].values>=equity_curve[j]].index.values[0]        UW_dt=pd.to_datetime(str(UW_dt))        UW_dt=UW_dt.strftime ("%Y-%m-%d")        UW_duration=np.busday_count(MDD_end, UW_dt)    except:        UW_dt="0000-00-00"        UW_duration=np.busday_count(MDD_end, NOW)    return MDD_start, MDD_end, MDD_duration, drawdown, UW_dt, UW_duration


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:

  • 2007-08 financial crisis, drop 56.7%, 888.62 points
  • Recent Corona Virus crisis, drop 33.9%, 1,1148.75 points

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 = 1000xs = np.random.randn(n).cumsum()i = np.argmax(np.maximum.accumulate(xs) - xs) # end of the periodj = np.argmax(xs[:i]) # start of periodplt.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)