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.ArrayList;
|
import java.util.List;
|
|
/**
|
* MACD (Moving Average Convergence Divergence) 指标实现
|
* 计算逻辑:
|
* 1. DIF = EMA(12) - EMA(26)
|
* 2. DEA = EMA(DIF, 9)
|
* 3. MACD柱状图 = (DIF - DEA) * 2
|
*
|
* 作用:
|
* 1. 识别趋势方向和动能变化
|
* 2. DIF上穿DEA形成金叉,提示买入信号
|
* 3. DIF下穿DEA形成死叉,提示卖出信号
|
* 4. MACD柱状图由负转正,提示多头力量增强
|
* 5. MACD柱状图由正转负,提示空头力量增强
|
*
|
* 价格参数类型:
|
* - 参数名称:prices
|
* - 参数类型:List<BigDecimal>
|
* - 参数说明:需要至少2个价格数据点用于计算,数据越多计算越准确
|
*
|
* 推荐时间粒度及优缺点:
|
* 1. 1分钟(1m):
|
* - 优点:反应迅速,适合超短线交易
|
* - 缺点:MACD柱状图波动剧烈,信号频繁
|
* 2. 5分钟(5m):
|
* - 优点:平衡了反应速度和信号可靠性
|
* - 缺点:仍有一定噪音
|
* 3. 15分钟(15m):
|
* - 优点:适合日内交易,信号较为可靠
|
* - 缺点:反应速度较慢
|
* 4. 1小时(1h)及以上:
|
* - 优点:趋势信号明确,MACD柱状图变化稳定
|
* - 缺点:反应滞后,不适合短线交易
|
*/
|
@Slf4j
|
@Getter
|
@Setter
|
public class MACD extends IndicatorBase {
|
|
// 默认周期参数
|
public static final int DEFAULT_FAST_PERIOD = 12;
|
public static final int DEFAULT_SLOW_PERIOD = 26;
|
public static final int DEFAULT_SIGNAL_PERIOD = 9;
|
|
// 动态周期参数
|
private int fastPeriod;
|
private int slowPeriod;
|
private int signalPeriod;
|
|
private BigDecimal dif = BigDecimal.ZERO;
|
private BigDecimal dea = BigDecimal.ZERO;
|
private BigDecimal macdBar = BigDecimal.ZERO;
|
private BigDecimal prevFastEMA = null;
|
private BigDecimal prevSlowEMA = null;
|
private BigDecimal prevDea = null;
|
|
// 构造函数使用默认周期
|
public MACD() {
|
this.fastPeriod = DEFAULT_FAST_PERIOD;
|
this.slowPeriod = DEFAULT_SLOW_PERIOD;
|
this.signalPeriod = DEFAULT_SIGNAL_PERIOD;
|
}
|
|
/**
|
* 计算MACD指标(使用当前周期设置)
|
* @param prices 价格列表
|
*/
|
public void calculate(List<BigDecimal> prices) {
|
calculate(prices, null);
|
}
|
|
/**
|
* 计算MACD指标,并支持动态周期调整
|
* @param prices 价格列表
|
* @param volatility 标准化波动率(百分比),用于动态调整周期
|
*/
|
public void calculate(List<BigDecimal> prices, BigDecimal volatility) {
|
if (prices == null || prices.size() < 2) {
|
return;
|
}
|
|
// 如果提供了波动率,则动态调整周期
|
if (volatility != null) {
|
adjustPeriodsByVolatility(volatility);
|
}
|
|
// 计算快速EMA
|
prevFastEMA = calculateEMA(prices, fastPeriod, prevFastEMA);
|
|
// 计算慢速EMA
|
prevSlowEMA = calculateEMA(prices, slowPeriod, prevSlowEMA);
|
|
// 计算DIF
|
dif = prevFastEMA.subtract(prevSlowEMA).setScale(8, RoundingMode.HALF_UP);
|
|
// 计算DEA
|
List<BigDecimal> difList = new ArrayList<>();
|
difList.add(dif);
|
prevDea = calculateEMA(difList, signalPeriod, prevDea);
|
dea = prevDea.setScale(8, RoundingMode.HALF_UP);
|
|
// 计算MACD柱状图
|
macdBar = dif.subtract(dea).multiply(new BigDecimal(2)).setScale(8, RoundingMode.HALF_UP);
|
|
log.info("MACD计算结果 - DIF: {}, DEA: {}, MACD柱状图: {}, 参数: fast={}, slow={}, signal={}",
|
dif, dea, macdBar, fastPeriod, slowPeriod, signalPeriod);
|
}
|
|
/**
|
* 根据波动率调整MACD周期参数
|
* @param volatility 标准化波动率(百分比)
|
*/
|
private void adjustPeriodsByVolatility(BigDecimal volatility) {
|
// 波动率阈值
|
BigDecimal volatilityThreshold = new BigDecimal(15);
|
|
// 根据波动率调整MACD参数
|
if (volatility.compareTo(volatilityThreshold) < 0) {
|
// 低波动率环境,使用默认参数
|
fastPeriod = DEFAULT_FAST_PERIOD;
|
slowPeriod = DEFAULT_SLOW_PERIOD;
|
signalPeriod = DEFAULT_SIGNAL_PERIOD;
|
} else {
|
// 高波动率环境,使用更灵敏的参数
|
fastPeriod = 8;
|
slowPeriod = 17;
|
signalPeriod = 5;
|
}
|
|
log.info("根据波动率{}调整MACD周期: fast={}, slow={}, signal={}",
|
volatility, fastPeriod, slowPeriod, signalPeriod);
|
}
|
|
/**
|
* 判断金叉信号(DIF上穿DEA)
|
* @return 是否形成金叉
|
*/
|
public boolean isGoldenCross(BigDecimal previousDIF, BigDecimal previousDEA) {
|
return previousDIF.compareTo(previousDEA) < 0 && dif.compareTo(dea) > 0;
|
}
|
|
/**
|
* 判断死叉信号(DIF下穿DEA)
|
* @return 是否形成死叉
|
*/
|
public boolean isDeathCross(BigDecimal previousDIF, BigDecimal previousDEA) {
|
return previousDIF.compareTo(previousDEA) > 0 && dif.compareTo(dea) < 0;
|
}
|
}
|