5

I have DataFrame final with returns of my portfolio. I am trying to calculate the MaxDrawdown using the returns. I have tried the below code and did see many stackexchange questions. But not able to solve this. Is there any way possible to calculate the maximum draw down using returns of the portfolio.

              Returns
1/2/2009     0.030483579
1/5/2009     0.002872092
1/6/2009     0.01461333
1/7/2009    -0.032431836
1/8/2009     0.0055774
1/9/2009    -0.019844336
1/12/2009   -0.019705618
1/13/2009    0.001093185
1/14/2009   -0.032726765
1/15/2009    0.013635182
1/16/2009    0.009807648
1/20/2009   -0.044440252
1/21/2009    0.035156229
1/22/2009   -0.01460641
1/23/2009    0.007399468
1/26/2009    0.007910521
1/27/2009    0.007848472
1/28/2009    0.028944903
1/29/2009   -0.023816962
1/30/2009   -0.02550717
2/2/2009    -0.000292223
2/3/2009     0.020191091
2/4/2009    -7.93651E-06
2/5/2009     0.020070065
2/6/2009     0.026235957
2/9/2009    -0.001606124
2/10/2009   -0.03629415
2/11/2009    0.00248416
2/12/2009    0.001925152
2/13/2009   -0.00441840

Code:

cum_returns = (1 + final).cumprod()
drawdown =  1 - final.div(final.cummax())

Can anyone help me in solving this. Thanks!

3 Answers 3

6

IIUC after cumprod adding diff and min is the max-draw-down

(df.Returns+1).cumprod().diff().min()
Out[316]: -0.043177386133390616

Base on the MDD definition

s=(df.Returns+1).cumprod()
np.ptp(s)/s.max()
Out[319]: 0.11457761692384323
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the answer! How can a drawdown be negative?? Can you explain more in detail what the code is doing.
THe calculation I think is drawdown rather than Maximum Drawdown . Correct me if I am wrong
Thanks! SOlved my problem
5

You can get a dataframe with the maximum drawdown up to the date using pandas.expanding()(doc) and then applying max to the window.

pandas.expanding will apply a function in the manner pandas.rolling does, but with a window that starts at the beginning of the dataframe and expands up to the current row (more info about the Window Functions here and pandas.expanding):

>> cum_returns = (1 + final).cumprod()
>> drawdown =  1 - final.div(final.cummax())
>> drawdown.expanding().max()

            Returns
1/2/2009   0.000000
1/5/2009   0.000000
1/6/2009   0.000000
1/7/2009   0.032432
1/8/2009   0.032432
1/9/2009   0.046343
1/12/2009  0.065136
1/13/2009  0.065136
1/14/2009  0.094742
1/15/2009  0.094742
1/16/2009  0.094742
1/20/2009  0.114578
1/21/2009  0.114578
1/22/2009  0.114578
1/23/2009  0.114578
1/26/2009  0.114578
1/27/2009  0.114578
1/28/2009  0.114578
1/29/2009  0.114578
1/30/2009  0.114578
2/2/2009   0.114578
2/3/2009   0.114578
2/4/2009   0.114578
2/5/2009   0.114578
2/6/2009   0.114578
2/9/2009   0.114578
2/10/2009  0.114578
2/11/2009  0.114578
2/12/2009  0.114578
2/13/2009  0.114578

Putting drawdowns and the Maximum Drawdown (MDD) together in a dataframe so you can compare the result:

>> df_dd =  pd.concat([drawdown, drawdown.expanding().max()], axis=1)

>> df_dd.columns = ['drawdown', 'MDD'] 

>> df_dd
           drawdown       MDD
1/2/2009   0.000000  0.000000
1/5/2009   0.000000  0.000000
1/6/2009   0.000000  0.000000
1/7/2009   0.032432  0.032432
1/8/2009   0.027035  0.032432
1/9/2009   0.046343  0.046343
1/12/2009  0.065136  0.065136
1/13/2009  0.064114  0.065136
1/14/2009  0.094742  0.094742
1/15/2009  0.082399  0.094742
1/16/2009  0.073399  0.094742
1/20/2009  0.114578  0.114578
1/21/2009  0.083450  0.114578
1/22/2009  0.096837  0.114578
1/23/2009  0.090154  0.114578
1/26/2009  0.082957  0.114578
1/27/2009  0.075759  0.114578
1/28/2009  0.049007  0.114578
1/29/2009  0.071657  0.114578
1/30/2009  0.095336  0.114578
2/2/2009   0.095601  0.114578
2/3/2009   0.077340  0.114578
2/4/2009   0.077347  0.114578
2/5/2009   0.058830  0.114578
2/6/2009   0.034137  0.114578
2/9/2009   0.035688  0.114578
2/10/2009  0.070687  0.114578
2/11/2009  0.068379  0.114578
2/12/2009  0.066585  0.114578
2/13/2009  0.070709  0.114578

3 Comments

Can you explain more about the code. It is a bit unclear
Added more comments. You have more info in the links.
Thanks a lot @Alex_MN
1

Assuming you already have a column with the cumulative return, it is pretty straight forward: you want to get the max value at any given point and compare it with the actual cumulative return of the rows occurring only after such point.

Then, if you take the the lowest value, you get the maximum drawdown of the array.

import pandas as import pd
import numpy as np

def max_drawdown(arr: pd.Series) -> int:
    return np.min(arr / arr.expanding().max()) - 1

In case you need to calculate the cumulative return first, using log makes it pretty straight forward:

import numpy as np

final['log_return'] = np.log(1 + final['Returns'])
final['log_cum_return'] = np.cumsum(final['log_return'])
final['cumulative_returns'] = np.expm1(final['log_cum_return'])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.