Maximum Active Drawdown in python

前端 未结 3 845
孤街浪徒
孤街浪徒 2021-02-01 09:10

I recently asked a question about calculating maximum drawdown where Alexander gave a very succinct and efficient way of calculating it with DataFrame methods in pandas.

3条回答
  •  渐次进展
    2021-02-01 09:58

    Starting with a series of portfolio returns and benchmark returns, we build cumulative returns for both. the variables below are assumed to already be in cumulative return space.

    The active return from period j to period i is:

    Solution

    This is how we can extend the absolute solution:

    def max_draw_down_relative(p, b):
        p = p.add(1).cumprod()
        b = b.add(1).cumprod()
        pmb = p - b
        cam = pmb.expanding(min_periods=1).apply(lambda x: x.argmax())
        p0 = pd.Series(p.iloc[cam.values.astype(int)].values, index=p.index)
        b0 = pd.Series(b.iloc[cam.values.astype(int)].values, index=b.index)
        dd = (p * b0 - b * p0) / (p0 * b0)
        mdd = dd.min()
        end = dd.argmin()
        start = cam.ix[end]
        return mdd, start, end
    

    Explanation

    Similar to the absolute case, at each point in time, we want to know what the maximum cumulative active return has been up to that point. We get this series of cumulative active returns with p - b. The difference is that we want to keep track of what the p and b were at this time and not the difference itself.

    So, we generate a series of 'whens' captured in cam (cumulative argmax) and subsequent series of portfolio and benchmark values at those 'whens'.

        p0 = pd.Series(p.ix[cam.values.astype(int)].values, index=p.index)
        b0 = pd.Series(b.ix[cam.values.astype(int)].values, index=b.index)
    

    The drawdown caclulation can now be made analogously using the formula above:

        dd = (p * b0 - b * p0) / (p0 * b0)
    

    Demonstration

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    
    np.random.seed(314)
    p = pd.Series(np.random.randn(200) / 100 + 0.001)
    b = pd.Series(np.random.randn(200) / 100 + 0.001)
    
    keys = ['Portfolio', 'Benchmark']
    cum = pd.concat([p, b], axis=1, keys=keys).add(1).cumprod()
    cum['Active'] = cum.Portfolio - cum.Benchmark
    
    
    mdd, sd, ed = max_draw_down_relative(p, b)
    
    f, a = plt.subplots(2, 1, figsize=[8, 10])
    
    cum[['Portfolio', 'Benchmark']].plot(title='Cumulative Absolute', ax=a[0])
    a[0].axvspan(sd, ed, alpha=0.1, color='r')
    
    cum[['Active']].plot(title='Cumulative Active', ax=a[1])
    a[1].axvspan(sd, ed, alpha=0.1, color='r')
    

提交回复
热议问题