计算最大回撤率(Java)

4,272 阅读2分钟

最大回撤率

        在选定周期内任一历史时点往后推,产品净值走到最低点时的收益率回撤幅度的最大值。最大回撤用来描述买入产品后可能出现的最糟糕的情况。最大回撤是一个重要的风险指标,对于对冲基金和数量化策略交易,该指标比波动率还重要。(来自百度百科)

转化为公式

        drawdown=max(Di-Dj)/Di

        D为某一天的净值,i为某一天,j为i后的某一天,Di为第i天的产品净值,Dj则是Di后面某一天的净值 drawdown就是最大回撤率

实现

import com.google.common.collect.Lists;

import java.math.BigDecimal;
import java.util.List;

/**
 * @author natsume
 * @date 2019-06-20
 */
class MaxDrawDownUtil {

    /**
     * 获取最大回撤率
     *
     * @param list
     * @return
     */
    public static BigDecimal getMaxDrawDown(List<BigDecimal> list) {
        // 只有数据量大于等于2个的时候才有回撤率
        if (list == null || list.size() <= 1) {
            return BigDecimal.ZERO;
        }

        // 获得数组的最小值
        BigDecimal minInRange = getMinInRange(list);
        // 第一个回撤率
        BigDecimal maxDrawDown = (list.get(0).subtract(minInRange)).divide(list.get(0), 4, BigDecimal.ROUND_HALF_UP);

        // 并不是每一次都需要计算最小值,一开始计算一次,等待下次达到最小值再计算
        boolean needCalculateMin = false;
        for (int i = 1; i < list.size() - 1; i++) {
            List<BigDecimal> subList = list.subList(i + 1, list.size());
            if (needCalculateMin) {
                minInRange = getMinInRange(subList);
            }

            // 到达最小值,下次需要计算最小值
            if (minInRange.compareTo(list.get(i)) == 0) {
                needCalculateMin = true;
            }else{
                needCalculateMin = false;
            }

            BigDecimal rate = (list.get(i).subtract(minInRange).divide(list.get(i), 4, BigDecimal.ROUND_HALF_UP));
            // 获得最大回撤率
            if (rate.compareTo(maxDrawDown) > 0) {
                maxDrawDown = rate;
            }
        }

        return maxDrawDown;
    }

    /**
     * 获取区间内最小值
     *
     * @param list
     * @return
     */
    public static BigDecimal getMinInRange(List<BigDecimal> list) {
        BigDecimal min = list.get(0);
        for (int i = 1; i < list.size(); i++) {
            if (list.get(i).compareTo(min) < 0) {
                min = list.get(i);
            }
        }

        return min;
    }

    // 测试方法
    public static void main(String[] args) {
        List<BigDecimal> list =
                Lists.newArrayList(new BigDecimal(100), new BigDecimal(200), new BigDecimal(50), new BigDecimal(300),
                        new BigDecimal(150), new BigDecimal(100), new BigDecimal(200));

        System.out.println("最大回撤率:" + getMaxDrawDown(list));
    }
}

优化过程

        将每次都需要计算区间最小值,修改为记录最小值,并且当达到最小值的时候,下一次重新计算最小值,可以避免不必要的计算。