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<BigDecimal>
|
* - 参数说明:需要至少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<BigDecimal> 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.info("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;
|
}
|
}
|
}
|