最近量化研究员小白又碰到一个看似很简单的问题,最大回撤到底怎么算比较好?....
小白百度了一下最大回撤的数学定义:
max(1 - 策略当日价值 / 当日之前账户最高价值)。
根据定义,小白凭着大一时候学的C语言编程基础,捣鼓了半天写出了一个计算最大回撤的函数。只要输入为策略的每日净值,两次循环后,函数就返回最大回撤,似乎大功告成!
def maxdrawdown(arr):
drawdown_max=0
for i in range(len(arr)):
for j in range(i,len(arr)):
drawdown=(arr[i]-arr[j])/arr[i]
drawdown_max=max(drawdown_max,drawdown)
return drawdown_max
可是等到运行的时候,问题就来了。每运行一次这个函数居然要3到5分钟,时间就是生命啊!
小白仔细想想这个用时也是正常的,一个十年的样本约有2400天,双重循环意味着这个函数要跑2400*2400/2次循环。。。循环本来就不是PYTHON的强项,怪不得这么慢。。。
最大回撤要是最常用的函数之一,有什么方法能够算的更加快一点吗?这样以后一定能节约不少时间!
如何避免for循环的出现呢?小白灵光一闪,可以用向量思维来寻找最大回撤发生的起始点和终止点。
首先寻找最大回撤的终止点。numpy包自带的np.maximum.accumulate函数可以生成一列当日之前历史最高价值的序列。在当日价值与历史最高值的比例最小时,就是最大回撤结束的终止点。
找到最大回撤终点后,最大回撤的起始点就更加简单了。我们只需要寻找从策略第一天到最大回撤终点期间 最大净值发生的日期。一个argmax函数就可以搞定。
最后,根据最大回撤的起始点和终止点,计算最大回撤的大小即可。
小白根据以上思路,迅速改下写最大回撤的函数。
import numpy as np
def maxdrawdown(arr):
i = np.argmax((np.maximum.accumulate(arr) - arr)/np.maximum.accumulate(arr)) # end of the period
j = np.argmax(arr[:i]) # start of period
return (1-arr[i]/arr[j])
改写后代码更加简洁了,试用一下新方法,最大回撤在眨眼见就算了出来,而且结果和标准算法一样,任务顺利完成!
求赞,作者熊敛四爪会分享更多的量化小技巧!