package com.xcong.excoin.modules.okxNewPrice.indicator; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; /** * BOLL (Bollinger Bands) 指标实现 * 计算逻辑: * 1. 中轨(MB)= N日移动平均线 * 2. 上轨(UP)= 中轨 + K倍标准差 * 3. 下轨(DN)= 中轨 - K倍标准差 * * 作用: * 1. 测量价格波动范围和市场宽度 * 2. 价格突破上轨,提示超买或趋势加速 * 3. 价格跌破下轨,提示超卖或趋势加速 * 4. 轨道收窄,提示即将发生剧烈波动 * 5. 价格回归轨道内,提示趋势可能反转 * * 价格参数类型: * - 参数名称:prices * - 参数类型:List * - 参数说明:需要至少20个(默认周期)价格数据点用于计算 * * 推荐时间粒度及优缺点: * 1. 1分钟(1m): * - 优点:反应迅速,适合超短线突破策略 * - 缺点:布林带宽度窄,假突破多 * 2. 5分钟(5m): * - 优点:布林带宽度适中,突破信号相对可靠 * - 缺点:仍有一定假突破 * 3. 15分钟(15m): * - 优点:适合日内交易,突破信号较为可靠 * - 缺点:反应速度较慢 * 4. 1小时(1h)及以上: * - 优点:布林带宽度稳定,突破信号可靠 * - 缺点:反应滞后,不适合短线交易 */ @Slf4j @Getter @Setter public class BOLL extends IndicatorBase { private static final int DEFAULT_PERIOD = 20; private static final double DEFAULT_K = 2.0; private int period = DEFAULT_PERIOD; private BigDecimal k = new BigDecimal(DEFAULT_K); private BigDecimal mid = BigDecimal.ZERO; private BigDecimal upper = BigDecimal.ZERO; private BigDecimal lower = BigDecimal.ZERO; public BOLL() {} public BOLL(int period, double k) { this.period = period; this.k = new BigDecimal(k); } /** * 计算BOLL指标 * @param prices 价格列表 */ public void calculate(List prices) { if (prices == null || prices.size() < period) { return; } // 计算中轨(MB)= N日移动平均线 mid = calculateMA(prices, period); // 计算标准差 BigDecimal stdDev = calculateStdDev(prices, period); // 计算上轨(UP)和下轨(DN) BigDecimal bandWidth = k.multiply(stdDev); upper = mid.add(bandWidth).setScale(8, RoundingMode.HALF_UP); lower = mid.subtract(bandWidth).setScale(8, RoundingMode.HALF_UP); log.debug("BOLL计算结果 - 中轨: {}, 上轨: {}, 下轨: {}", mid, upper, lower); } /** * 判断价格是否突破上轨 * @param price 当前价格 * @return 是否突破上轨 */ public boolean isBreakUpper(BigDecimal price) { return price.compareTo(upper) > 0; } /** * 判断价格是否跌破下轨 * @param price 当前价格 * @return 是否跌破下轨 */ public boolean isBreakLower(BigDecimal price) { return price.compareTo(lower) < 0; } /** * 判断价格是否回归上轨下方 * @param price 当前价格 * @param prevPrice 前一期价格 * @return 是否回归上轨下方 */ public boolean isReturnFromUpper(BigDecimal price, BigDecimal prevPrice) { return prevPrice.compareTo(upper) > 0 && price.compareTo(upper) <= 0; } /** * 判断价格是否回归下轨上方 * @param price 当前价格 * @param prevPrice 前一期价格 * @return 是否回归下轨上方 */ public boolean isReturnFromLower(BigDecimal price, BigDecimal prevPrice) { return prevPrice.compareTo(lower) < 0 && price.compareTo(lower) >= 0; } /** * 判断价格是否在中轨上方 * @param price 当前价格 * @return 是否在中轨上方 */ public boolean isAboveMid(BigDecimal price) { return price.compareTo(mid) > 0; } /** * 判断价格是否在中轨下方 * @param price 当前价格 * @return 是否在中轨下方 */ public boolean isBelowMid(BigDecimal price) { return price.compareTo(mid) < 0; } /** * 计算布林带宽度 * @return 布林带宽度 */ public BigDecimal calculateBandWidth() { if (mid.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; } return upper.subtract(lower).divide(mid, 8, RoundingMode.HALF_UP); } /** * 计算价格相对于布林带的位置 * @param price 当前价格 * @return 价格位置指标 (-1: 下轨外, 0: 轨道内, 1: 上轨外) */ public int getPricePosition(BigDecimal price) { if (price.compareTo(upper) > 0) { return 1; } else if (price.compareTo(lower) < 0) { return -1; } else { return 0; } } }