package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; /** * 波动率指标实现类 * * 波动率是衡量价格波动程度的技术指标,反映市场的活跃度和风险水平。 * 本类通过计算价格的标准差来衡量波动率,使用高精度BigDecimal计算避免精度损失。 * * 【核心功能】 * 1. 计算指定周期内价格的波动率(标准差) * 2. 使用牛顿迭代法实现BigDecimal的平方根计算,确保金融计算的高精度要求 * 3. 提供获取最新计算结果的接口 * * 【使用场景】 * - 在MACD+MA策略中,用于过滤低波动率的市场环境(波动率<1%时跳过交易) * - 适用于各种时间周期的价格数据,通常使用20日或30日周期 * 【注意事项】 * - 波动率指标对市场流动性和交易活跃度敏感 * - 低波动率可能预示着市场趋势即将发生变化 */ public class Volatility { /** * 波动率计算的周期 */ private final int period; /** * 最新计算的波动率值 */ private BigDecimal volatility = BigDecimal.ZERO; /** * 构造方法 * * @param period 波动率计算的周期 */ public Volatility(int period) { this.period = period; } /** * 计算波动率 * * @param prices 历史价格数据列表 */ public void calculate(List prices) { // 如果价格数据不足计算周期,不进行计算 if (prices.size() < period) { return; } BigDecimal sum = BigDecimal.ZERO; BigDecimal avg = calculateAverage(prices); // 计算平均价格 // 计算每个价格与平均价格的偏差平方和 for (int i = prices.size()-period; i < prices.size(); i++) { BigDecimal dev = prices.get(i).subtract(avg); sum = sum.add(dev.pow(2)); } // 计算方差,保留8位小数 BigDecimal variance = sum.divide(new BigDecimal(period), 8, RoundingMode.HALF_UP); // 计算标准差(波动率),使用牛顿迭代法确保高精度 volatility = sqrt(variance, 8); } /** * 计算价格平均值 * * @param prices 历史价格数据列表 * @return 平均价格 */ private BigDecimal calculateAverage(List prices) { BigDecimal sum = BigDecimal.ZERO; for (int i = prices.size()-period; i < prices.size(); i++) { sum = sum.add(prices.get(i)); } return sum.divide(new BigDecimal(period), 8, 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 波动率值 */ public BigDecimal getValue() { return volatility; } }