package com.xcong.excoin.modules.okxNewPrice.indicator; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; import java.util.List; /** * MA (Moving Average) 指标实现 * 支持不同周期的简单移动平均线(SMA)和指数移动平均线(EMA) */ @Slf4j @Getter @Setter public class MA extends IndicatorBase { // 常用周期 public static final int MA5 = 5; public static final int MA10 = 10; public static final int MA20 = 20; public static final int MA30 = 30; public static final int MA60 = 60; private BigDecimal ma5 = BigDecimal.ZERO; private BigDecimal ma10 = BigDecimal.ZERO; private BigDecimal ma20 = BigDecimal.ZERO; private BigDecimal ma30 = BigDecimal.ZERO; private BigDecimal ma60 = BigDecimal.ZERO; private BigDecimal ema5 = BigDecimal.ZERO; private BigDecimal ema10 = BigDecimal.ZERO; private BigDecimal ema20 = BigDecimal.ZERO; private BigDecimal ema30 = BigDecimal.ZERO; private BigDecimal ema60 = BigDecimal.ZERO; private BigDecimal prevEma5 = null; private BigDecimal prevEma10 = null; private BigDecimal prevEma20 = null; private BigDecimal prevEma30 = null; private BigDecimal prevEma60 = null; /** * 计算所有周期的MA指标 * @param prices 价格列表 */ public void calculate(List prices) { if (prices == null || prices.size() < 1) { return; } // 计算SMA if (prices.size() >= MA5) { ma5 = calculateMA(prices, MA5); } if (prices.size() >= MA10) { ma10 = calculateMA(prices, MA10); } if (prices.size() >= MA20) { ma20 = calculateMA(prices, MA20); } if (prices.size() >= MA30) { ma30 = calculateMA(prices, MA30); } if (prices.size() >= MA60) { ma60 = calculateMA(prices, MA60); } // 计算EMA prevEma5 = calculateEMA(prices, MA5, prevEma5); ema5 = prevEma5; prevEma10 = calculateEMA(prices, MA10, prevEma10); ema10 = prevEma10; prevEma20 = calculateEMA(prices, MA20, prevEma20); ema20 = prevEma20; prevEma30 = calculateEMA(prices, MA30, prevEma30); ema30 = prevEma30; prevEma60 = calculateEMA(prices, MA60, prevEma60); ema60 = prevEma60; log.debug("MA计算结果 - MA5: {}, MA10: {}, MA20: {}, MA30: {}, MA60: {}", ma5, ma10, ma20, ma30, ma60); log.debug("EMA计算结果 - EMA5: {}, EMA10: {}, EMA20: {}, EMA30: {}, EMA60: {}", ema5, ema10, ema20, ema30, ema60); } /** * 判断短期均线是否上穿长期均线(金叉) * @param shortMA 短期均线 * @param longMA 长期均线 * @param prevShortMA 前一期短期均线 * @param prevLongMA 前一期长期均线 * @return 是否形成金叉 */ public boolean isGoldenCross(BigDecimal shortMA, BigDecimal longMA, BigDecimal prevShortMA, BigDecimal prevLongMA) { return prevShortMA != null && prevLongMA != null && prevShortMA.compareTo(prevLongMA) < 0 && shortMA.compareTo(longMA) > 0; } /** * 判断短期均线是否下穿长期均线(死叉) * @param shortMA 短期均线 * @param longMA 长期均线 * @param prevShortMA 前一期短期均线 * @param prevLongMA 前一期长期均线 * @return 是否形成死叉 */ public boolean isDeathCross(BigDecimal shortMA, BigDecimal longMA, BigDecimal prevShortMA, BigDecimal prevLongMA) { return prevShortMA != null && prevLongMA != null && prevShortMA.compareTo(prevLongMA) > 0 && shortMA.compareTo(longMA) < 0; } /** * 判断价格是否上穿均线 * @param price 当前价格 * @param ma 均线值 * @param prevPrice 前一期价格 * @param prevMA 前一期均线值 * @return 是否上穿 */ public boolean isPriceCrossUp(BigDecimal price, BigDecimal ma, BigDecimal prevPrice, BigDecimal prevMA) { return prevPrice != null && prevMA != null && prevPrice.compareTo(prevMA) < 0 && price.compareTo(ma) > 0; } /** * 判断价格是否下穿均线 * @param price 当前价格 * @param ma 均线值 * @param prevPrice 前一期价格 * @param prevMA 前一期均线值 * @return 是否下穿 */ public boolean isPriceCrossDown(BigDecimal price, BigDecimal ma, BigDecimal prevPrice, BigDecimal prevMA) { return prevPrice != null && prevMA != null && prevPrice.compareTo(prevMA) > 0 && price.compareTo(ma) < 0; } }