去年在项目里写了一个计算投资风险指标的计算工具类,包含夏普比率,波动率,Var值,最大回撤率四个指标。
计算全部采用BigDecimal类型,开方计算采用牛顿迭代法计算。
其计算公式如下:
工具类实现:
/*** @describe 投资分析数学计算工具类*/public class MathUtil {/*** 默认保留小数位数*/private final static Integer DECIMAL_SCALE = 15;/*** 默认牛顿迭代法计算平方根时迭代次数*/private final static Integer PRECISION = 20;private final static Integer COUNT = 0;/*** @describe 计算收益率* @params startNav 期初单位净值 endNav 期末单位净值*/public static BigDecimal dayYield(BigDecimal startNav, BigDecimal endNav) {return dayYield(startNav, endNav, DECIMAL_SCALE);}public static BigDecimal dayYield(BigDecimal startNav, BigDecimal endNav, int decimalScale) {return dayYield(startNav, endNav, decimalScale, BigDecimal.ROUND_HALF_UP);}public static BigDecimal dayYield(BigDecimal startNav, BigDecimal endNav, int decimalScale, int roundingMode) {BigDecimal dValue = endNav.subtract(startNav);return dValue.divide(startNav, decimalScale, roundingMode);}/*** @describe 计算累计求和*/public static BigDecimal sum(BigDecimal[] dataArray) {BigDecimal sum = BigDecimal.ZERO;for (BigDecimal data : dataArray) {sum = sum.add(data);}return sum;}/*** @describe 计算算术平均值*/public static BigDecimal avg(BigDecimal[] dataArray) {return avg(dataArray, DECIMAL_SCALE);}public static BigDecimal avg(BigDecimal[] dataArray, int decimalScale) {return avg(dataArray, decimalScale, BigDecimal.ROUND_HALF_UP);}public static BigDecimal avg(BigDecimal[] dataArray, int decimalScale, int roundingMode) {BigDecimal sum = sum(dataArray);BigDecimal count = new BigDecimal(dataArray.length);return sum.divide(count, decimalScale, roundingMode);}/*** @describe 计算样本方差*/public static BigDecimal variance(BigDecimal[] dataArray) {return variance(dataArray, DECIMAL_SCALE);}public static BigDecimal variance(BigDecimal[] dataArray, int decimalScale) {return variance(dataArray, decimalScale, BigDecimal.ROUND_HALF_UP);}public static BigDecimal variance(BigDecimal[] dataArray, int decimalScale, int roundingMode) {BigDecimal avg = avg(dataArray, decimalScale, roundingMode);BigDecimal[] resultArray = new BigDecimal[dataArray.length];for (int i = 0; i < dataArray.length; i++) {BigDecimal dValue = dataArray[i].subtract(avg);resultArray[i] = dValue.multiply(dValue);}BigDecimal sum = sum(resultArray);BigDecimal count = new BigDecimal(resultArray.length - 1);return sum.divide(count, decimalScale, roundingMode);}/*** @describe 计算平方根*/public static BigDecimal standardDeviation(BigDecimal data) {return standardDeviation(data, DECIMAL_SCALE);}public static BigDecimal standardDeviation(BigDecimal data, int decimalScale) {return standardDeviation(data, decimalScale, BigDecimal.ROUND_HALF_UP);}public static BigDecimal standardDeviation(BigDecimal data, int decimalScale, int roundingMode) {BigDecimal result = data;int count = COUNT;while (count < PRECISION && pareTo(BigDecimal.ZERO) != 0) {result = (result.add(data.divide(result, decimalScale, roundingMode))).divide(BigDecimal.valueOf(2), decimalScale, roundingMode);count++;}return result;}/*** @describe 计算夏普比率*/public static BigDecimal sharpeRatio(BigDecimal[] yieldArray, BigDecimal drVal, BigDecimal vol) {return sharpeRatio(yieldArray, drVal, vol, DECIMAL_SCALE);}public static BigDecimal sharpeRatio(BigDecimal[] yieldArray, BigDecimal drVal, BigDecimal vol, int decimalScale) {return sharpeRatio(yieldArray, drVal, vol, decimalScale, BigDecimal.ROUND_HALF_UP);}public static BigDecimal sharpeRatio(BigDecimal[] yieldArray, BigDecimal drVal, BigDecimal vol, int decimalScale, int roundingMode) {BigDecimal avg = avg(yieldArray, decimalScale, roundingMode);BigDecimal variance = variance(yieldArray, decimalScale, roundingMode);BigDecimal standardDeviation = standardDeviation(variance, decimalScale, roundingMode);return avg.subtract(drVal).divide(standardDeviation, decimalScale, roundingMode).multiply(vol).setScale(decimalScale, roundingMode);}/*** @describe 计算波动率*/public static BigDecimal yieldVar(BigDecimal[] yieldArray, BigDecimal vol) {return yieldVar(yieldArray, vol, DECIMAL_SCALE);}public static BigDecimal yieldVar(BigDecimal[] yieldArray, BigDecimal vol, int decimalScale) {return yieldVar(yieldArray, vol, decimalScale, BigDecimal.ROUND_HALF_UP);}public static BigDecimal yieldVar(BigDecimal[] yieldArray, BigDecimal vol, int decimalScale, int roundingMode) {BigDecimal variance = variance(yieldArray, decimalScale, roundingMode);BigDecimal standardDeviation = standardDeviation(variance, decimalScale, roundingMode);return standardDeviation.multiply(vol).setScale(decimalScale, roundingMode);}/*** @describe 计算Var*/public static BigDecimal var(BigDecimal[] yieldArray, BigDecimal zVal) {return var(yieldArray, zVal, DECIMAL_SCALE);}public static BigDecimal var(BigDecimal[] yieldArray, BigDecimal zVal, int decimalScale) {return var(yieldArray, zVal, decimalScale, BigDecimal.ROUND_HALF_UP);}public static BigDecimal var(BigDecimal[] yieldArray, BigDecimal zVal, int decimalScale, int roundingMode) {BigDecimal variance = variance(yieldArray, decimalScale, roundingMode);BigDecimal standardDeviation = standardDeviation(variance, decimalScale, roundingMode);return standardDeviation.multiply(zVal).setScale(decimalScale, roundingMode);}/*** @describe 计算最大回撤率*/public static BigDecimal maxRetracement(BigDecimal[] dataArray) {return maxRetracement(dataArray, DECIMAL_SCALE);}public static BigDecimal maxRetracement(BigDecimal[] dataArray, int decimalScale) {return maxRetracement(dataArray, decimalScale, BigDecimal.ROUND_HALF_UP);}public static BigDecimal maxRetracement(BigDecimal[] yieldArray, int decimalScale, int roundingMode) {BigDecimal maxRetracement = BigDecimal.ZERO;BigDecimal maxTotalYield = BigDecimal.ZERO;BigDecimal totalDayYield = BigDecimal.ZERO;for (int i = 1; i < yieldArray.length; i++) {totalDayYield = (totalDayYield.add(BigDecimal.ONE)).multiply(yieldArray[i].add(BigDecimal.ONE)).subtract(BigDecimal.ONE);if (pareTo(maxTotalYield) >= 0) {maxTotalYield = totalDayYield;} else {BigDecimal retracement = maxTotalYield.subtract(totalDayYield).divide(BigDecimal.ONE.add(maxTotalYield), decimalScale, roundingMode);maxRetracement = pareTo(maxRetracement) > 0 ? retracement : maxRetracement;}}return maxRetracement;}/*** @describe 用资产净值计算日收益率数组*/public static BigDecimal[] yieldArray(BigDecimal[] assetArray, BigDecimal[] cashFlowArray) {//日收益率数组BigDecimal[] yieldArray = new BigDecimal[assetArray.length - 1];for (int i = 0; i < assetArray.length - 1; i++) {yieldArray[i] = dayYield(assetArray[i], assetArray[i + 1].subtract(cashFlowArray[i + 1]));}return yieldArray;}/*** @describe 用单位净值计算日收益率数组*/public static BigDecimal[] yieldArray(BigDecimal[] navArray) {// 日收益率数组BigDecimal[] yieldArray = new BigDecimal[navArray.length - 1];for (int i = 0; i < navArray.length - 1; i++) {yieldArray[i] = dayYield(navArray[i], navArray[i + 1]);}return yieldArray;}}