zoukankan      html  css  js  c++  java
  • 最大回撤,最大回撤恢复时间与最大回撤持续期

    概要

    这两个概念在刚接触量化分析时,实在时折腾了许久,故在此作下总结。

     
        最大回撤
        最大回撤恢复时间
        最大回撤持续期
        图示
        源代码

     


    内容

     

    最大回撤(Max Drawdown)

    简单来说最大回撤就是从一个高点到一个低点最大的下跌幅度,用来描述一个策略可能出现的最糟糕的情况,衡量了最极端可能的亏损。如果一个策略的最大回撤是 50%,那么它的意思是,运气不好的话,我们的持有价值可能要拦腰截断了。计算公式为

    egin{align} label{e6}
    MaxDrawDown_t = max(1-frac{P_j}{P_i} )
    end{align}

    其中

    • (MaxDrawDown_t)(t) 日的最大回撤
    • (P_i)(P_j) 分别为 (i) 日和 (j) 日的策略总资产,且需要满足 (t geqslant j >i)

    有的教程给出的计算公式是刚好反过来的,即取负值,实际计算公式是一样的,了解下即可。公式可能看起来为容易理解,用语言描述就是

    egin{align} label{e7}
    MaxDrawDown_t = 1-frac{t ext{日持有价值}}{t ext{日之前持有最高价值}}
    end{align}

    这样是不是容易理解多了。

     

    最大回撤恢复时间(Max Drawdown)

    这个我的理解是:从最大回撤结束时间开始,需要多久才能达到回撤前的顶峰状态。这个可以参考图示。

     

    最大回撤持续期(MaxDrawDownDuration)

    最大回撤持续期描述的是持有价值从回撤开始到再创新高所经历的时间,如果说最大回撤是在资产空间维度上描述资产的波动风险,那么最大回撤持续期则是在资产的时间维度上给出一个风险描述。直观地说就是资产创新高的频率是怎样的。

     

    图示

    下边一张图展示了我们介绍的三个概念,直观地表示了三个概念范围。

    图 1:回撤效果图!

     
     

    源代码

    本篇用的代码(python)如下,该代码也包含了 python 绘折线图的大部分设置,可以作为参考。

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """
    Created on Sun Jun  2 15:32:13 2019
    
    @author: zk
    """
    import datetime
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdate
    import matplotlib.ticker as ticker
    import numpy as np
    import random
    
    DAYS = 365  
    
    def Init():
        timedelta = datetime.timedelta(days = 1)
        startdate = datetime.date.today()
        
        xdate = [startdate+i*timedelta for i in range(DAYS)]
        
        ycapital = [3000]
        for _ in range(DAYS-1):
            ycapital.append(ycapital[-1]+random.uniform(-1, 1.1))
            
        return xdate, ycapital
    
    def max_drawdown(xdate, ycapital):
        
        # 计算每日的回撤
        drawdown = []
        tmp_max_capital = ycapital[0]
        for c in ycapital:
            tmp_max_capital = max(c, tmp_max_capital)
            drawdown.append(1 - c / tmp_max_capital)
        
        # 最大回撤
        MaxDrawdown = max(drawdown)
        # 计算最大回撤日期范围
        endidx = np.argmax(drawdown)
        #enddate = xdate[endidx]
        
        startidx = np.argmax(ycapital[:endidx])
        #startdate = xdate[startidx]
        #仅仅画图的话,我们只要索引值更加方便
        return MaxDrawdown, startidx, endidx
    
    def max_drawdown_duration(xdate, ycapital):
        
        duration = []
        tmp_max_capital = ycapital[0]
        for c in ycapital:
            if c >= tmp_max_capital:
                duration.append(0)
            else:
                duration.append(duration[-1]+1)
            tmp_max_capital = max(c, tmp_max_capital)
    
        MaxDDD = max(duration)
        
        #fig, ax = plt.subplots(figsize = (21, 9)) 
        #plt.plot(xdate, duration)
        #ax.xaxis.set_major_formatter(mdate.DateFormatter('%Y-%m-%d'))
        endidx = np.argmax(duration)
        startidx = endidx - MaxDDD
        
        return MaxDDD, startidx, endidx
    
    def max_drawdown_restore_time(startidx, endidx, xdate, ycapital):
        """
        startidx:表示最大回撤的开始时间在 xdate 中的索引,由 max_drawdown 方法返回
        endidx:表示最大回撤的结束时间在 xdate 中的索引,由 max_drawdown 方法返回
        """
        maxdd_resore_time = 0
        restore_endidx = np.inf
        for t in range(endidx, len(xdate)):
            if ycapital[t] >= ycapital[startidx]:
                restore_endidx = t
                break
            else:
                maxdd_resore_time += 1
        
        restore_endidx = min(restore_endidx, len(xdate)-1)
        return maxdd_resore_time, restore_endidx
        
    def plot(xdate, ycapital):
        # 指定画布大小
        fig, ax = plt.subplots(figsize = (21, 9))  
        # 绘图并设置颜色,图例标签,线宽
        plt.plot(xdate, ycapital, 'red', label = 'My Strategy', linewidth = 2)
        
        # 绘制最大回撤日期范围标识 marker = 'v'
        MaxDrawdown, startidx, endidx = max_drawdown(xdate, ycapital)
        print("最大回撤为:", MaxDrawdown)
        plt.scatter([xdate[startidx], xdate[endidx]], [ycapital[startidx], ycapital[endidx]],
                    s = 100, c = 'b', marker = 's', label = 'MaxDrawdown')
        # 绘制最大回撤恢复时间
        maxdd_resore_time, restore_endidx = max_drawdown_restore_time(startidx, endidx, xdate, ycapital)
        print("最大回撤恢复时间为(天):", maxdd_resore_time)
        plt.scatter([xdate[endidx], xdate[restore_endidx]], [ycapital[endidx], ycapital[restore_endidx]],
                    s = 100, c = 'cyan', marker = 'D', label = 'MaxDrawdown Restore Time')
        
        # 绘制最大回撤持续期标识 marker = 'D'
        MaxDDD, startidx, endidx = max_drawdown_duration(xdate, ycapital)
        plt.scatter([xdate[startidx], xdate[endidx]], [ycapital[startidx], ycapital[endidx]],
                    s = 80, c = 'g', marker = 'v', label = 'MaxDrawdown Duration')
        print("最大回撤持续期为(天):", MaxDDD)
        # 设置刻度值颜色
        plt.yticks(color = 'gray')
        # 设置 y 轴百分比显示,注意将 y 轴数据乘以 100
        #ax.yaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f%%'))
        # 颜色,旋转刻度
        plt.xticks(color = 'gray',rotation = 15)
        # 指定字体,大小,颜色 
        fontdict = {"family":"Times New Roman", 'size':12, 'color':'gray'} #Times New Roman, Arial
        plt.title("random account value", fontdict = fontdict)
        plt.xlabel("date(day)", fontdict = fontdict)
        plt.ylabel("account value", fontdict = fontdict)
        # 去掉边框 top left right bottom
        ax.spines['top'].set_visible(False) 
        ax.spines['left'].set_visible(False)
        ax.spines['right'].set_visible(False)
        # 设置 x 轴颜色
        ax.spines['bottom'].set_color('lightgray')
        #设置时间标签显示格式
        ax.xaxis.set_major_formatter(mdate.DateFormatter('%Y-%m-%d'))
        #设置时间刻度间隔
        #timedelta = (xdate[-1] - xdate[0]) / 10  # 这种方式不能保证显示最后一个日期
        #plt.xticks(mdate.drange(xdate[0], xdate[-1], timedelta))
        # 分成 10 份
        delta = round(len(xdate) / 9)
        plt.xticks([xdate[i*delta] for i in range(9)] + [xdate[-1]])
        #通过修改tick_spacing的值可以修改x轴的密度
        #ax.xaxis.set_major_locator(ticker.MultipleLocator(10))
        # 去掉 y 轴刻度线,四个方向均可设置
        plt.tick_params(left = 'off')
        # 设置刻度的朝向,宽,长度
        plt.tick_params(which = 'major', direction = 'out', width = 0.2, length = 5) # in, out or inout
        # 设置刻度显示在哪个方向上
        #tick_params(labeltop='on',labelbottom='off',labelleft='off',labelright='off')
        # 设置 y 轴方向的网络线
        plt.grid(axis = 'y', color = 'lightgray', linestyle = '-', linewidth = 0.5)
        
        # 设置图例 列宽:columnspacing=float (upper left) 
        plt.legend(loc = 'best', fontsize = 12, frameon=False, ncol = 1)
        # 设置图例字体颜色
        #leg = 上一行 plt.legend 的返回值
        #for line,text in zip(leg.legendHandles, leg.get_texts()): 
        #    text.set_color(line.get_color())
        
        fig.show()
        # fig.savefig("test.png")  # dpi = 150
        
        
    if __name__ == '__main__':
        # 构造绘图数据
        xdate, ycapital = Init()
        plot(xdate, ycapital)
        #max_drawdown_duration(xdate, ycapital)
    
    

     

  • 相关阅读:
    超详细的Chrome插件Vimium使用教程!
    Chrome浏览器快捷键详细介绍,让你摆脱鼠标的束缚!
    为什么你的电脑越来越卡?很可能是因为这个!
    像黑客一样用命令打开应用!
    电脑桌面乱?看完这篇文章是不存在这种情况的!
    任务栏简化,让你的任务栏更美观!
    USB无法识别?简单详细的驱动程序安装教程!
    文件扩展名是什么?有什么用?通俗易懂的文件扩展名讲解!
    Win2008 IIS7.5安装配置PHP7.3.2步骤,及500错误解决
    用命令行方式关闭CentOS防火墙
  • 原文地址:https://www.cnblogs.com/zhoukui/p/10166873.html
Copyright © 2011-2022 走看看