我最近问了一个关于calculating maximum drawdown的问题,在pandas中,Alexander提供了一种非常简洁有效的方法来使用DataFrame方法来计算它。
我想继续询问其他人是如何计算最大active降幅的
这将计算最大降幅。不!最大有效降幅
这是我根据Alexander对上面链接的问题的回答实现的最大降幅:
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以及出现下跌的指数。
我们首先生成一系列累积回报作为回报指数。
r = returns.add(1).cumprod()
在每个时间点,通过将当前回报指数的水平与之前所有时期的最大回报指数进行比较来计算当前的下降。
dd = r.div(r.cummax()).sub(1)
最大降幅就是所有计算出的降幅中的最小值。
我的问题是:
我想通过询问其他人是如何计算最大active drawdown来跟进的?
假设解决方案将在上面的解决方案上扩展。
发布于 2016-04-26 02:57:47
从一系列投资组合回报和基准回报开始,我们为两者建立累积回报。假设下面的变量已经在累积回报空间中。
从period j到period i的有效收益为:
解决方案
这是我们如何扩展绝对解决方案的方法:
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’上的一系列投资组合和基准价值。
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)
现在可以使用上面的公式进行类似的压降计算:
dd = (p * b0 - b * p0) / (p0 * b0)
游行示威
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')
发布于 2016-04-26 08:47:28
您可能已经注意到,无论是以加法还是几何方式,您的单个组件都不等于整体:
>>> cum.tail(1)
Portfolio Benchmark Active
199 1.342179 1.280958 1.025144
这总是一个令人不安的情况,因为它表明您的模型中可能发生了某种类型的泄漏。
混合单期和多期归因总是一个挑战。问题的一部分在于分析的目标,即你试图解释什么。
如果您正在查看上面的情况下的累积回报,那么执行分析的一种方法如下:
我们将很方便地假设这两笔掉期交易都由现金账户担保,并且没有交易成本(如果只是...!)。
第一天,股指上涨了1%多一点(扣除当天的现金支出后,超额回报率恰好为1.00% )。然而,不相关的对冲基金提供了-5%的超额回报。我们的基金现在有9600万美元。
第二天,我们如何实现再平衡?你的计算表明我们从来没有这样做过。每一个都是一个独立的投资组合,永远漂浮着…然而,出于归因的目的,我认为每天重新平衡是完全有意义的,即100%地对这两种策略中的每一种进行调整。
由于这些只是名义上的风险敞口,有充足的现金抵押品,我们可以调整金额。因此,我们不会在第二天对股指有1.01亿美元的敞口,也不会对对冲基金有9500万美元的敞口,相反,我们将(以零成本)进行再平衡,使我们对每种股票的敞口都有9600万美元。
你可能会问,这在熊猫中是如何工作的?您已经计算了cum['Portfolio']
,这是投资组合的累积超额增长因子(即扣除现金回报后)。如果我们将当天的超额基准和活跃收益应用于前一天的投资组合增长因子,我们就计算出每日再平衡收益。
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()
现在我们看到,活跃收益加上基准收益加上初始现金等于投资组合的现值。
>>> 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
列,我们可以将降幅定义为:
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)
然后,可以像以前一样确定绘制的起点和终点。
将我的累计活跃回报贡献与您计算的金额进行比较,您会发现它们一开始是相似的,然后随着时间的推移而分散(我的回报计算是绿色的):
发布于 2018-06-05 06:54:53
我用纯Python写的两便士:
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
https://stackoverflow.com/questions/36848866
复制相似问题