Administrator
2025-12-25 5755881472e2060832dc7f626109a68aa71fce90
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/MA.java
@@ -10,18 +10,50 @@
/**
 * MA (Moving Average) 指标实现
 * 支持不同周期的简单移动平均线(SMA)和指数移动平均线(EMA)
 *
 * 作用:
 * 1. 平滑价格波动,识别趋势方向
 * 2. 短周期MA上穿长周期MA形成金叉,提示买入信号
 * 3. 短周期MA下穿长周期MA形成死叉,提示卖出信号
 * 4. 价格上穿/下穿MA线,也可作为买卖参考
 *
 * 价格参数类型:
 * - 参数名称:prices
 * - 参数类型:List<BigDecimal>
 * - 参数说明:需要至少1个价格数据点用于计算,根据不同周期需求更多数据点
 *
 * 推荐时间粒度及优缺点:
 * 1. 1分钟(1m):
 *    - 优点:反应迅速,适合超短线交易
 *    - 缺点:噪音多,容易产生虚假信号
 * 2. 5分钟(5m):
 *    - 优点:平衡了反应速度和噪音过滤
 *    - 缺点:仍有一定噪音
 * 3. 15分钟(15m):
 *    - 优点:适合日内交易,信号相对可靠
 *    - 缺点:反应速度较慢
 * 4. 1小时(1h)及以上:
 *    - 优点:趋势信号明确,虚假信号少
 *    - 缺点:反应滞后,不适合短线交易
 */
@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;
    // 默认周期
    public static final int DEFAULT_MA5 = 5;
    public static final int DEFAULT_MA10 = 10;
    public static final int DEFAULT_MA20 = 20;
    public static final int DEFAULT_MA30 = 30;
    public static final int DEFAULT_MA60 = 60;
    // 动态周期参数
    private int ma5Period;
    private int ma10Period;
    private int ma20Period;
    private int ma30Period;
    private int ma60Period;
    private BigDecimal ma5 = BigDecimal.ZERO;
    private BigDecimal ma10 = BigDecimal.ZERO;
@@ -41,52 +73,101 @@
    private BigDecimal prevEma30 = null;
    private BigDecimal prevEma60 = null;
    // 构造函数使用默认周期
    public MA() {
        this.ma5Period = DEFAULT_MA5;
        this.ma10Period = DEFAULT_MA10;
        this.ma20Period = DEFAULT_MA20;
        this.ma30Period = DEFAULT_MA30;
        this.ma60Period = DEFAULT_MA60;
    }
    /**
     * 计算所有周期的MA指标
     * 计算所有周期的MA指标(使用当前周期设置)
     * @param prices 价格列表
     */
    public void calculate(List<BigDecimal> prices) {
        calculate(prices, null);
    }
    /**
     * 计算所有周期的MA指标,并支持动态周期调整
     * @param prices 价格列表
     * @param volatility 标准化波动率(ATR百分比),用于动态调整周期
     */
    public void calculate(List<BigDecimal> prices, BigDecimal volatility) {
        if (prices == null || prices.size() < 1) {
            return;
        }
        // 如果提供了波动率,则动态调整周期
        if (volatility != null) {
            adjustPeriodsByVolatility(volatility);
        }
        // 计算SMA
        if (prices.size() >= MA5) {
            ma5 = calculateMA(prices, MA5);
        if (prices.size() >= ma5Period) {
            ma5 = calculateMA(prices, ma5Period);
        }
        if (prices.size() >= MA10) {
            ma10 = calculateMA(prices, MA10);
        if (prices.size() >= ma10Period) {
            ma10 = calculateMA(prices, ma10Period);
        }
        if (prices.size() >= MA20) {
            ma20 = calculateMA(prices, MA20);
        if (prices.size() >= ma20Period) {
            ma20 = calculateMA(prices, ma20Period);
        }
        if (prices.size() >= MA30) {
            ma30 = calculateMA(prices, MA30);
        if (prices.size() >= ma30Period) {
            ma30 = calculateMA(prices, ma30Period);
        }
        if (prices.size() >= MA60) {
            ma60 = calculateMA(prices, MA60);
        if (prices.size() >= ma60Period) {
            ma60 = calculateMA(prices, ma60Period);
        }
        // 计算EMA
        prevEma5 = calculateEMA(prices, MA5, prevEma5);
        prevEma5 = calculateEMA(prices, ma5Period, prevEma5);
        ema5 = prevEma5;
        
        prevEma10 = calculateEMA(prices, MA10, prevEma10);
        prevEma10 = calculateEMA(prices, ma10Period, prevEma10);
        ema10 = prevEma10;
        
        prevEma20 = calculateEMA(prices, MA20, prevEma20);
        prevEma20 = calculateEMA(prices, ma20Period, prevEma20);
        ema20 = prevEma20;
        
        prevEma30 = calculateEMA(prices, MA30, prevEma30);
        prevEma30 = calculateEMA(prices, ma30Period, prevEma30);
        ema30 = prevEma30;
        
        prevEma60 = calculateEMA(prices, MA60, prevEma60);
        prevEma60 = calculateEMA(prices, ma60Period, 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);
        log.info("MA计算结果 - MA5({}): {}, MA10({}): {}, MA20({}): {}, MA30({}): {}, MA60({}): {}",
                ma5Period, ma5, ma10Period, ma10, ma20Period, ma20, ma30Period, ma30, ma60Period, ma60);
        log.info("EMA计算结果 - EMA5({}): {}, EMA10({}): {}, EMA20({}): {}, EMA30({}): {}, EMA60({}): {}",
                ma5Period, ema5, ma10Period, ema10, ma20Period, ema20, ma30Period, ema30, ma60Period, ema60);
    }
    /**
     * 根据波动率调整MA周期
     * @param volatility 标准化波动率(ATR百分比)
     */
    private void adjustPeriodsByVolatility(BigDecimal volatility) {
        // 根据波动率缩放均线周期
        // 3%、5%、8%作为ATR阈值
        BigDecimal lowVolatility = new BigDecimal(3);
        BigDecimal midVolatility = new BigDecimal(5);
        BigDecimal highVolatility = new BigDecimal(8);
        // 快速MA周期 (ma5)
        ma5Period = volatility.compareTo(lowVolatility) < 0 ? 10 : 6;
        // 中期MA周期 (ma10, ma20)
        ma10Period = volatility.compareTo(midVolatility) < 0 ? 10 : 8;
        ma20Period = volatility.compareTo(midVolatility) < 0 ? 21 : 13;
        // 长期MA周期 (ma30, ma60)
        ma30Period = volatility.compareTo(highVolatility) < 0 ? 30 : 24;
        ma60Period = volatility.compareTo(highVolatility) < 0 ? 50 : 34;
        log.info("根据波动率{}调整MA周期: ma5={}, ma10={}, ma20={}, ma30={}, ma60={}",
                volatility, ma5Period, ma10Period, ma20Period, ma30Period, ma60Period);
    }
    /**