title用法 - 用python中的向量化解决方案计算最大绘制




plt.title用法 (2)

假设df_returns是一个返回数据df_returns ,其中每列是一个单独的策略/经理/安全,每一行都是一个新的日期(如每月或每日)。

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

https://code.i-harness.com

最大跌幅是量化金融中常用的风险度量标准,用以评估已经经历的最大负回报。

最近,我变得不耐烦的时候用我的循环方法来计算最大跌幅。

def max_dd_loop(returns):
    """returns is assumed to be a pandas series"""
    max_so_far = None
    start, end = None, None
    r = returns.add(1).cumprod()
    for r_start in r.index:
        for r_end in r.index:
            if r_start < r_end:
                current = r.ix[r_end] / r.ix[r_start] - 1
                if (max_so_far is None) or (current < max_so_far):
                    max_so_far = current
                    start, end = r_start, r_end
    return max_so_far, start, end

我熟悉一个常见的看法,即矢量化解决方案会更好。

问题是:

  • 我可以矢量化这个问题吗?
  • 这个解决方案是什么样的?
  • 它有多好处?

编辑

我将Alexander的答案修改为以下函数:

def max_dd(returns):
    """Assumes returns is a pandas Series"""
    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

给定一个时间序列的回报,我们需要评估每个起点到终点组合的总回报。

第一个诀窍是将时间序列的收益转化为一系列的收益指数。 给定一系列的回报指数,我可以计算任何子期间的回报,其中回报指数在开始ri_0和结束ri_1。 计算是:ri_1 / ri_0 - 1。

第二个诀窍是产生第二个回归指数倒数。 如果r是我的一系列回报指数,那么1 / r是我的一系列逆。

第三个技巧是取r *(1 / r)的矩阵乘积。

r是一个nx 1矩阵。 (1 / r).Transpose是一个1 xn矩阵。 生成的产品包含ri_j / ri_k的每个组合。 只要减去1,我已经得到了回报。

第四个诀窍是确保我限制我的分母来代表分子所代表的时间段。

以下是我的矢量化函数。

import numpy as np
import pandas as pd

def max_dd(returns):
    # make into a DataFrame so that it is a 2-dimensional
    # matrix such that I can perform an nx1 by 1xn matrix
    # multiplication and end up with an nxn matrix
    r = pd.DataFrame(returns).add(1).cumprod()

    # I copy r.T to ensure r's index is not the same
    # object as 1 / r.T's columns object
    x = r.dot(1 / r.T.copy()) - 1
    x.columns.name, x.index.name = 'start', 'end'

    # let's make sure we only calculate a return when start
    # is less than end.
    y = x.stack().reset_index()
    y = y[y.start < y.end]

    # my choice is to return the periods and the actual max
    # draw down
    z = y.set_index(['start', 'end']).iloc[:, 0]
    return z.min(), z.argmin()[0], z.argmin()[1]

这是如何执行的?

对于向量化解决方案,我在时间序列长度[10,50,100,150,200]上进行10次迭代。 所花的时间如下:

10:   0.032 seconds
50:   0.044 seconds
100:  0.055 seconds
150:  0.082 seconds
200:  0.047 seconds

下面是环路解决方案的相同测试:

10:   0.153 seconds
50:   3.169 seconds
100: 12.355 seconds
150: 27.756 seconds
200: 49.726 seconds

编辑

亚历山大的答案提供了出色的结 使用修改的代码进行相同的测

10:   0.000 seconds
50:   0.000 seconds
100:  0.004 seconds
150:  0.007 seconds
200:  0.008 seconds

我将他的代码修改为以下函数:

def max_dd(returns):
    r = returns.add(1).cumprod()
    dd = r.div(r.cummax()).sub(1)
    mdd = drawdown.min()
    end = drawdown.argmin()
    start = r.loc[:end].argmax()
    return mdd, start, end






quantitative-finance