/** * 波动率指标计算类 *

* 波动率是衡量金融市场价格波动程度的指标,通常用价格的标准差与平均值的比率表示。 * 本类实现了基于滚动窗口的波动率计算,通过标准差与平均值的比值计算出百分比形式的波动率。 */ package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.LinkedList; import java.util.List; /** * 波动率指标实现类 *

波动率计算原理:使用标准差与平均值的比值,以百分比形式表示价格的波动程度。

*

计算公式:波动率 = (标准差 / 平均值) * 100%

* *

使用示例:

*
 * // 初始化20日波动率计算器
 * Volatility vol = new Volatility(20);
 *
 * // 动态添加每日价格
 * priceFeed.subscribe(price -> {
 * vol.addPrice(price);
 * vol.calculate();
 * });
 *
 * // 判断是否满足低波动条件(<1%)
 * if (vol.getValue().compareTo(new BigDecimal("1.00")) < 0) {
 * System.out.println("低波动市场,暂停交易");
 * }
 * 
*/ public class Volatility { /** 波动率计算的周期(如20日波动率) */ private final int period; /** 当前计算出的波动率值(百分比形式) */ private BigDecimal volatility = BigDecimal.ZERO; /** 使用LinkedList存储滚动窗口内的价格数据,便于添加和删除操作 */ private LinkedList priceWindow = new LinkedList<>(); /** 窗口内价格的总和,用于快速计算平均值 */ private BigDecimal sum = BigDecimal.ZERO; /** 窗口内价格平方的总和,用于快速计算方差 */ private BigDecimal sumSquares = BigDecimal.ZERO; /** * 构造函数,创建指定周期的波动率计算器 * * @param period 波动率计算周期,如20表示计算20日波动率 */ public Volatility(int period) { this.period = period; } /** * 添加新价格到计算窗口,并维护窗口内的价格数据 * 采用滑动窗口方式,当价格数量超过周期时,自动移除最早的价格 * * @param price 新的价格数据,使用BigDecimal确保计算精度 * @throws IllegalArgumentException 当价格为null时抛出异常 */ public void addPrice(BigDecimal price) { if (price == null) { throw new IllegalArgumentException("Price cannot be null"); } // 当窗口大小达到周期时,移除最早的价格,并从总和中减去 if (priceWindow.size() == period) { BigDecimal removed = priceWindow.removeFirst(); sum = sum.subtract(removed); sumSquares = sumSquares.subtract(removed.pow(2)); } // 添加新价格到窗口,并更新总和 priceWindow.add(price); sum = sum.add(price); sumSquares = sumSquares.add(price.pow(2)); } /** * 计算当前窗口内价格的波动率 * 使用标准差与平均值的比值计算波动率百分比 */ public void calculate() { // 数据点不足,无法计算波动率 if (priceWindow.size() < period) { return; } // 计算平均值:sum / period BigDecimal avg = sum.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP); // 防止除以零的情况 if (avg.compareTo(BigDecimal.ZERO) == 0) { volatility = BigDecimal.ZERO; return; } // 计算方差:(sumSquares / period) - avg^2 BigDecimal variance = sumSquares.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP) .subtract(avg.pow(2)); // 确保方差非负(防止浮点数计算误差导致负数方差) variance = variance.max(BigDecimal.ZERO); // 计算标准差:sqrt(variance) BigDecimal stdDev = sqrt(variance, 8); // 计算波动率:(标准差 / 平均值) * 100% volatility = stdDev.divide(avg, 8, RoundingMode.HALF_UP) .multiply(new BigDecimal(100)) .setScale(2, RoundingMode.HALF_UP); } /** * 计算BigDecimal的平方根(使用牛顿迭代法) * * @param value 要计算平方根的数值 * @param scale 结果的精度(小数位数) * @return 平方根结果 */ private BigDecimal sqrt(BigDecimal value, int scale) { // 负数没有实数平方根,返回0 if (value.compareTo(BigDecimal.ZERO) < 0) { return BigDecimal.ZERO; } // 使用牛顿迭代法计算平方根 BigDecimal x = value.divide(new BigDecimal(2), scale, RoundingMode.HALF_UP); // 初始猜测值 BigDecimal prev; do { prev = x; // 牛顿迭代公式:x(n+1) = (x(n) + value/x(n))/2 x = x.add(value.divide(x, scale, RoundingMode.HALF_UP)).divide(new BigDecimal(2), scale, RoundingMode.HALF_UP); } while (x.subtract(prev).abs().compareTo(BigDecimal.ONE.movePointLeft(scale)) > 0); // 直到满足精度要求 return x; } /** * 获取最新的波动率计算结果 * * @return 波动率值,以百分比形式表示(例如:2.5表示2.5%) */ public BigDecimal getValue() { return volatility; } }