Search code examples
pythonfinance

Calculate Portfolio Drawdown using .expanding() Python


I'm trying to calculate the drawdown of a portfolio over time of a portfolio using the code below. I have tried to use the .expanding() function but can't seem to get the desired output. I'd really appreciate if anyone could let me know where I am going wrong.

def drawdown_2(arr):
    tot_return = arr.add(1).cumprod()
    max_return = tot_return.add(1).cummax()
    return (tot_return / max_return) - 1

df['Drawdown'] = df.groupby(df.portfolio)['performance'].expanding().apply(drawdown_2)

The input data is in the format below

portfolio   period  performance
port1   201501  0.003718
port1   201502  -0.004890
port1   201503  -0.004171
port1   201504  -0.006922
port1   201505  0.003545
port1   201506  0.003545
port1   201507  0.006901
port1   201508  0.000101
port1   201509  0.009081
port1   201510  0.003062
port1   201511  -0.008425
port1   201512  0.002580
port2   201501  0.009135
port2   201502  0.009149
port2   201503  -0.004252
port2   201504  -0.008788
port2   201505  -0.006210
port2   201506  0.006020
port2   201507  0.002983
port2   201508  0.008498
port2   201509  0.008080
port2   201510  0.000138
port2   201511  -0.008425
port2   201512  0.002580

The desired output isan array that is the difference between the portfolio's previous maximum value and the portfolio's current value. The drawdown figures for the above inputs are below in the desired format:

portfolio   period  performance Drawdown
port1   201501  0.003718    0.00000
port1   201502  -0.004890   -0.00490
port1   201503  -0.004171   -0.00900
port1   201504  -0.006922   -0.01590
port1   201505  0.003545    -0.01240
port1   201506  0.003545    -0.00890
port1   201507  0.006901    -0.00210
port1   201508  0.000101    -0.00200
port1   201509  0.009081    0.00000
port1   201510  0.003062    0.00000
port1   201511  -0.008425   -0.00842
port1   201512  0.002580    -0.00587
port2   201501  0.009135    0.00000
port2   201502  0.009149    0.00000
port2   201503  -0.004252   -0.00430
port2   201504  -0.008788   -0.01300
port2   201505  -0.006210   -0.01910
port2   201506  0.006020    -0.01320
port2   201507  0.002983    -0.01030
port2   201508  0.008498    -0.00190
port2   201509  0.008080    0.00000
port2   201510  0.000138    0.00000
port2   201511  -0.008425   -0.00860
port2   201512  0.002580    -0.00605

Thanks a million for the help in advance.


Solution

  • I am using this data from yfinance:

    import yfnance as yf
    
    df = yf.download('aapl', start='2020-01-01')[['Close']]
    df['Chg'] = df['Close'].pct_change()
    
        Close
    Date    
    2019-12-31  73.412498
    2020-01-02  75.087502
    2020-01-03  74.357498
    2020-01-06  74.949997
    2020-01-07  74.597504
    ... ...
    2020-09-03  120.879997
    2020-09-04  120.959999
    2020-09-08  112.820000
    2020-09-09  117.320000
    2020-09-10  118.930000
    

    Calculate the cumulative returns, rolling max peaks and the drawdown from the trailing peak as:

    df['Cum_ret'] = (1+ df['Chg']).cumprod()  # cumulative return
    df['Peaks'] = df['Cum_ret'].cummax()      # cumulative peaks
    df['Drawdown'] = (df['Cum_ret'] - df['Peaks']) / df['Peaks']  # drawdown from trailing peak
    

    Cumulative return and peaks: enter image description here

    Drawdowns: enter image description here

    EDIT: just noticed you have 2 portfolio returns that you are dealing with, so this hasn't really answered your question...

    I think this will do what you want:

    df['Drawdown'] = df.groupby('portfolio')['performance'].apply(drawdown_2)
    
        portfolio   period  performance Drawdown
    0   port1   201501  0.003718    0.000000
    1   port1   201502  -0.004890   -0.004890
    2   port1   201503  -0.004171   -0.009041
    3   port1   201504  -0.006922   -0.015900
    4   port1   201505  0.003545    -0.012411
    5   port1   201506  0.003545    -0.008910
    6   port1   201507  0.006901    -0.002071
    7   port1   201508  0.000101    -0.001970
    8   port1   201509  0.009081    0.000000
    9   port1   201510  0.003062    0.000000
    10  port1   201511  -0.008425   -0.008425
    11  port1   201512  0.002580    -0.005867
    12  port2   201501  0.009135    0.000000
    13  port2   201502  0.009149    0.000000
    14  port2   201503  -0.004252   -0.004252
    15  port2   201504  -0.008788   -0.013003
    16  port2   201505  -0.006210   -0.019132
    17  port2   201506  0.006020    -0.013227
    18  port2   201507  0.002983    -0.010284
    19  port2   201508  0.008498    -0.001873
    20  port2   201509  0.008080    0.000000
    21  port2   201510  0.000138    0.000000
    22  port2   201511  -0.008425   -0.008425
    23  port2   201512  0.002580    -0.005867