首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >python中的最大有效降幅

python中的最大有效降幅
EN

Stack Overflow用户
提问于 2016-04-26 02:57:47
回答 4查看 4.7K关注 0票数 12

我最近问了一个关于calculating maximum drawdown的问题,在pandas中,Alexander提供了一种非常简洁有效的方法来使用DataFrame方法来计算它。

我想继续询问其他人是如何计算最大active降幅的

这将计算最大降幅。不!最大有效降幅

这是我根据Alexander对上面链接的问题的回答实现的最大降幅:

代码语言:javascript
复制
def max_drawdown_absolute(returns):
    r = returns.add(1).cumprod()
    dd = r.div(r.cummax()).sub(1)
    mdd = dd.min()
    end = dd.argmin()
    start = r.loc[:end].argmax()
    return mdd, start, end

它接受一个返回序列,并返回max_drawdown以及出现下跌的指数。

我们首先生成一系列累积回报作为回报指数。

代码语言:javascript
复制
r = returns.add(1).cumprod()

在每个时间点,通过将当前回报指数的水平与之前所有时期的最大回报指数进行比较来计算当前的下降。

代码语言:javascript
复制
dd = r.div(r.cummax()).sub(1)

最大降幅就是所有计算出的降幅中的最小值。

我的问题是:

我想通过询问其他人是如何计算最大active drawdown来跟进的?

假设解决方案将在上面的解决方案上扩展。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-04-26 02:57:47

从一系列投资组合回报和基准回报开始,我们为两者建立累积回报。假设下面的变量已经在累积回报空间中。

从period j到period i的有效收益为:

解决方案

这是我们如何扩展绝对解决方案的方法:

代码语言:javascript
复制
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

解释

与绝对情况类似,在每个时间点,我们都想知道到那个时间点为止的最大累积主动收益是多少。我们用p - b得到了这一系列累积的积极回报。不同的是,我们想要跟踪p和b在这个时候是什么,而不是差本身。

因此,我们生成了一系列在cam (cumulative argmax) )中捕获的'whens‘,以及随后在这些'whens’上的一系列投资组合和基准价值。

代码语言:javascript
复制
    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)

现在可以使用上面的公式进行类似的压降计算:

代码语言:javascript
复制
    dd = (p * b0 - b * p0) / (p0 * b0)

游行示威

代码语言:javascript
复制
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')

票数 10
EN

Stack Overflow用户

发布于 2016-04-26 08:47:28

您可能已经注意到,无论是以加法还是几何方式,您的单个组件都不等于整体:

代码语言:javascript
复制
>>> cum.tail(1)
     Portfolio  Benchmark    Active
199   1.342179   1.280958  1.025144

这总是一个令人不安的情况,因为它表明您的模型中可能发生了某种类型的泄漏。

混合单期和多期归因总是一个挑战。问题的一部分在于分析的目标,即你试图解释什么。

如果您正在查看上面的情况下的累积回报,那么执行分析的一种方法如下:

  1. 确保投资组合收益和基准收益都是超额收益,即减去相应时期(例如每日、每月等)的适当现金收益。
  2. 假设你有一位富有的叔叔借给你1亿美元来启动你的基金。现在你可以把你的投资组合想象成三笔交易,一笔现金和两笔衍生品交易: a)将你的1亿美元投资到一个现金账户,轻松地获得出价。b)签订名义上1亿美元的股权互换c)与零贝塔对冲基金达成互换交易,名义上也是1亿美元。

我们将很方便地假设这两笔掉期交易都由现金账户担保,并且没有交易成本(如果只是...!)。

第一天,股指上涨了1%多一点(扣除当天的现金支出后,超额回报率恰好为1.00% )。然而,不相关的对冲基金提供了-5%的超额回报。我们的基金现在有9600万美元。

第二天,我们如何实现再平衡?你的计算表明我们从来没有这样做过。每一个都是一个独立的投资组合,永远漂浮着…然而,出于归因的目的,我认为每天重新平衡是完全有意义的,即100%地对这两种策略中的每一种进行调整。

由于这些只是名义上的风险敞口,有充足的现金抵押品,我们可以调整金额。因此,我们不会在第二天对股指有1.01亿美元的敞口,也不会对对冲基金有9500万美元的敞口,相反,我们将(以零成本)进行再平衡,使我们对每种股票的敞口都有9600万美元。

你可能会问,这在熊猫中是如何工作的?您已经计算了cum['Portfolio'],这是投资组合的累积超额增长因子(即扣除现金回报后)。如果我们将当天的超额基准和活跃收益应用于前一天的投资组合增长因子,我们就计算出每日再平衡收益。

代码语言:javascript
复制
import numpy as np
import pandas as pd

np.random.seed(314)
df_returns = pd.DataFrame({
    'Portfolio': np.random.randn(200) / 100 + 0.001,
    'Benchmark': np.random.randn(200) / 100 + 0.001})
df_returns['Active'] = df.Portfolio - df.Benchmark

# Copy return dataframe shape and fill with NaNs.
df_cum = pd.DataFrame()  

# Calculate cumulative portfolio growth
df_cum['Portfolio'] = (1 + df_returns.Portfolio).cumprod()

# Calculate shifted portfolio growth factors.
portfolio_return_factors = pd.Series([1] + df_cum['Portfolio'].shift()[1:].tolist(), name='Portfolio_return_factor')

# Use portfolio return factors to calculate daily rebalanced returns.
df_cum['Benchmark'] = (df_returns.Benchmark * portfolio_return_factors).cumsum()
df_cum['Active'] = (df_returns.Active * portfolio_return_factors).cumsum()

现在我们看到,活跃收益加上基准收益加上初始现金等于投资组合的现值。

代码语言:javascript
复制
   >>> df_cum.tail(3)[['Benchmark', 'Active', 'Portfolio']]
         Benchmark    Active  Portfolio
    197   0.303995  0.024725   1.328720
    198   0.287709  0.051606   1.339315
    199   0.292082  0.050098   1.342179

通过构造,df_cum['Portfolio'] = 1 + df_cum['Benchmark'] + df_cum['Active']。因为这个方法很难计算(没有Pandas!)和理解(大多数人不会得到名义上的风险敞口),行业实践通常将积极回报定义为一段时间内回报的累积差异。例如,如果一只基金在一个月内上涨了5.0%,而市场下跌了1.0%,那么该月的超额回报通常被定义为+6.0%。然而,这种简单方法的问题是,由于计算中没有适当考虑复合和重新平衡问题,您的结果将随着时间的推移而分散。

因此,给定我们的df_cum.Active列,我们可以将降幅定义为:

代码语言:javascript
复制
drawdown = pd.Series(1 - (1 + df_cum.Active)/(1 + df_cum.Active.cummax()), name='Active Drawdown')

>>> df_cum.Active.plot(legend=True);drawdown.plot(legend=True)

然后,可以像以前一样确定绘制的起点和终点。

将我的累计活跃回报贡献与您计算的金额进行比较,您会发现它们一开始是相似的,然后随着时间的推移而分散(我的回报计算是绿色的):

票数 4
EN

Stack Overflow用户

发布于 2018-06-05 06:54:53

我用纯Python写的两便士:

代码语言:javascript
复制
def find_drawdown(lista):
    peak = 0
    trough = 0
    drawdown = 0
    for n in lista:
        if n > peak:
            peak = n
            trough = peak
        if n < trough:
            trough = n
        temp_dd = peak - trough
        if temp_dd > drawdown:
            drawdown = temp_dd
    return -drawdown
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36848866

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档