Administrator
8 days ago b6b63e31d3f25784a4f4e0add7045a3d724d22fb
refactor(indicator): 重构MACD指标计算工具类

- 移除原有的BearishSignalDetector和BullishSignalDetector类
- 新增IndicatorUtils工具类封装价格高低点查找功能
- 将价格高点低点查找方法从MACDCalculator迁移至IndicatorUtils
- 修复MACDCalculator中调用已移除方法的引用
- 优化MACD金叉死叉逻辑,移除额外的趋势判断条件
- 修正MACD死叉柱状线收缩为扩张的逻辑错误
2 files deleted
2 files modified
1 files added
502 ■■■■■ changed files
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/BearishSignalDetector.java 132 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/BullishSignalDetector.java 87 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/IndicatorUtils.java 154 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MACDCalculator.java 111 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java 18 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/BearishSignalDetector.java
File was deleted
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/BullishSignalDetector.java
File was deleted
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/IndicatorUtils.java
New file
@@ -0,0 +1,154 @@
/**
 * 指标计算工具类
 * 封装MACD策略中常用的通用功能,如高低点查找等
 */
package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
import java.math.BigDecimal;
import java.util.List;
/**
 * 指标计算工具类,提供MACD策略中常用的通用功能
 */
public class IndicatorUtils {
    /**
     * 找到最近的价格高点索引
     *
     * @param prices 价格列表
     * @param startIdx 起始索引
     * @return 最近的价格高点索引
     */
    public static int findRecentHighIndex(List<BigDecimal> prices, int startIdx) {
        if (prices == null || startIdx < 0 || startIdx >= prices.size()) {
            return -1;
        }
        int highIdx = startIdx;
        BigDecimal highPrice = prices.get(startIdx);
        for (int i = startIdx + 1; i < prices.size(); i++) {
            BigDecimal currentPrice = prices.get(i);
            if (currentPrice.compareTo(highPrice) > 0) {
                highPrice = currentPrice;
                highIdx = i;
            }
        }
        return highIdx;
    }
    /**
     * 找到最近的价格低点索引
     *
     * @param prices 价格列表
     * @param startIdx 起始索引
     * @return 最近的价格低点索引
     */
    public static int findRecentLowIndex(List<BigDecimal> prices, int startIdx) {
        if (prices == null || startIdx < 0 || startIdx >= prices.size()) {
            return -1;
        }
        int lowIdx = startIdx;
        BigDecimal lowPrice = prices.get(startIdx);
        for (int i = startIdx + 1; i < prices.size(); i++) {
            BigDecimal currentPrice = prices.get(i);
            if (currentPrice.compareTo(lowPrice) < 0) {
                lowPrice = currentPrice;
                lowIdx = i;
            }
        }
        return lowIdx;
    }
    /**
     * 找到最近价格高点之前的价格高点索引
     *
     * @param prices 价格列表
     * @param startIdx 起始索引
     * @param recentHighIdx 最近的价格高点索引
     * @return 之前的价格高点索引
     */
    public static int findPreviousHighIndex(List<BigDecimal> prices, int startIdx, int recentHighIdx) {
        if (prices == null || startIdx < 0 || recentHighIdx <= startIdx || recentHighIdx >= prices.size()) {
            return -1;
        }
        int highIdx = startIdx;
        BigDecimal highPrice = prices.get(startIdx);
        for (int i = startIdx + 1; i < recentHighIdx; i++) {
            BigDecimal currentPrice = prices.get(i);
            if (currentPrice.compareTo(highPrice) > 0) {
                highPrice = currentPrice;
                highIdx = i;
            }
        }
        return highIdx;
    }
    /**
     * 找到最近价格低点之前的价格低点索引
     *
     * @param prices 价格列表
     * @param startIdx 起始索引
     * @param recentLowIdx 最近的价格低点索引
     * @return 之前的价格低点索引
     */
    public static int findPreviousLowIndex(List<BigDecimal> prices, int startIdx, int recentLowIdx) {
        if (prices == null || startIdx < 0 || recentLowIdx <= startIdx || recentLowIdx >= prices.size()) {
            return -1;
        }
        int lowIdx = startIdx;
        BigDecimal lowPrice = prices.get(startIdx);
        for (int i = startIdx + 1; i < recentLowIdx; i++) {
            BigDecimal currentPrice = prices.get(i);
            if (currentPrice.compareTo(lowPrice) < 0) {
                lowPrice = currentPrice;
                lowIdx = i;
            }
        }
        return lowIdx;
    }
    /**
     * 寻找最近的价格高点(带有回调确认)
     *
     * @param prices 价格列表
     * @param startIndex 起始索引
     * @param endIndex 结束索引
     * @return 符合条件的价格高点索引,未找到则返回-1
     */
    public static int findRecentHighWithRetrace(List<BigDecimal> prices, int startIndex, int endIndex) {
        if (prices == null || startIndex < 0 || endIndex >= prices.size() || startIndex >= endIndex) {
            return -1;
        }
        int highIndex = -1;
        BigDecimal highPrice = BigDecimal.ZERO;
        // 从右向左搜索,找到第一个有效高点
        for (int i = endIndex; i >= startIndex; i--) {
            if (prices.get(i).compareTo(highPrice) > 0) {
                highPrice = prices.get(i);
                highIndex = i;
            }
            // 检查高点后是否有回调
            if (highIndex != -1 && i < endIndex) {
                if (prices.get(i + 1).compareTo(highPrice) < 0) {
                    return highIndex; // 找到确认回调的高点
                }
            }
        }
        return highIndex;
    }
}
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MACDCalculator.java
@@ -85,7 +85,7 @@
            result.add(data);
        }
        System.out.println(result.get(result.size() -1));
        return new MACDResult(result, startIdx);
    }
@@ -123,14 +123,14 @@
        }
        
        // 找到最近的价格高点和对应的DIF值
        int recentPriceHighIdx = findRecentHighIndex(closePrices, startIdx);
        if (recentPriceHighIdx < startIdx + 2) {
        int recentPriceHighIdx = IndicatorUtils.findRecentHighIndex(closePrices, startIdx);
        if (recentPriceHighIdx < startIdx + 2 || recentPriceHighIdx == -1) {
            return false;
        }
        
        // 找到之前的价格高点和对应的DIF值
        int previousPriceHighIdx = findPreviousHighIndex(closePrices, startIdx, recentPriceHighIdx);
        if (previousPriceHighIdx < startIdx) {
        int previousPriceHighIdx = IndicatorUtils.findPreviousHighIndex(closePrices, startIdx, recentPriceHighIdx);
        if (previousPriceHighIdx < startIdx || previousPriceHighIdx == -1) {
            return false;
        }
        
@@ -173,14 +173,14 @@
        }
        
        // 找到最近的价格低点和对应的DIF值
        int recentPriceLowIdx = findRecentLowIndex(closePrices, startIdx);
        if (recentPriceLowIdx < startIdx + 2) {
        int recentPriceLowIdx = IndicatorUtils.findRecentLowIndex(closePrices, startIdx);
        if (recentPriceLowIdx < startIdx + 2 || recentPriceLowIdx == -1) {
            return false;
        }
        
        // 找到之前的价格低点和对应的DIF值
        int previousPriceLowIdx = findPreviousLowIndex(closePrices, startIdx, recentPriceLowIdx);
        if (previousPriceLowIdx < startIdx) {
        int previousPriceLowIdx = IndicatorUtils.findPreviousLowIndex(closePrices, startIdx, recentPriceLowIdx);
        if (previousPriceLowIdx < startIdx || previousPriceLowIdx == -1) {
            return false;
        }
        
@@ -202,95 +202,4 @@
        return recentPrice.compareTo(previousPrice) < 0 && 
               recentDif.compareTo(previousDif) > 0;
    }
    /**
     * 找到最近的价格高点索引
     *
     * @param prices 价格列表
     * @param startIdx 起始索引
     * @return 最近的价格高点索引
     */
    private static int findRecentHighIndex(List<BigDecimal> prices, int startIdx) {
        int highIdx = startIdx;
        BigDecimal highPrice = prices.get(startIdx);
        for (int i = startIdx + 1; i < prices.size(); i++) {
            BigDecimal currentPrice = prices.get(i);
            if (currentPrice.compareTo(highPrice) > 0) {
                highPrice = currentPrice;
                highIdx = i;
            }
        }
        return highIdx;
    }
    /**
     * 找到最近的价格低点索引
     *
     * @param prices 价格列表
     * @param startIdx 起始索引
     * @return 最近的价格低点索引
     */
    private static int findRecentLowIndex(List<BigDecimal> prices, int startIdx) {
        int lowIdx = startIdx;
        BigDecimal lowPrice = prices.get(startIdx);
        for (int i = startIdx + 1; i < prices.size(); i++) {
            BigDecimal currentPrice = prices.get(i);
            if (currentPrice.compareTo(lowPrice) < 0) {
                lowPrice = currentPrice;
                lowIdx = i;
            }
        }
        return lowIdx;
    }
    /**
     * 找到最近价格高点之前的价格高点索引
     *
     * @param prices 价格列表
     * @param startIdx 起始索引
     * @param recentHighIdx 最近的价格高点索引
     * @return 之前的价格高点索引
     */
    private static int findPreviousHighIndex(List<BigDecimal> prices, int startIdx, int recentHighIdx) {
        int highIdx = startIdx;
        BigDecimal highPrice = prices.get(startIdx);
        for (int i = startIdx + 1; i < recentHighIdx; i++) {
            BigDecimal currentPrice = prices.get(i);
            if (currentPrice.compareTo(highPrice) > 0) {
                highPrice = currentPrice;
                highIdx = i;
            }
        }
        return highIdx;
    }
    /**
     * 找到最近价格低点之前的价格低点索引
     *
     * @param prices 价格列表
     * @param startIdx 起始索引
     * @param recentLowIdx 最近的价格低点索引
     * @return 之前的价格低点索引
     */
    private static int findPreviousLowIndex(List<BigDecimal> prices, int startIdx, int recentLowIdx) {
        int lowIdx = startIdx;
        BigDecimal lowPrice = prices.get(startIdx);
        for (int i = startIdx + 1; i < recentLowIdx; i++) {
            BigDecimal currentPrice = prices.get(i);
            if (currentPrice.compareTo(lowPrice) < 0) {
                lowPrice = currentPrice;
                lowIdx = i;
            }
        }
        return lowIdx;
    }
}
}
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java
@@ -357,15 +357,13 @@
        boolean isGoldenCross = prevPrev.getDif().compareTo(prevPrev.getDea()) <= 0 && 
                              previous.getDif().compareTo(previous.getDea()) > 0;
        boolean isUp = latest.getDif().compareTo(BigDecimal.ZERO) > 0 && latest.getDea().compareTo(BigDecimal.ZERO) > 0;
        // 柱状线扩张判断:连续正值且绝对值增大
        boolean isExpanding = latest.getMacdHist().compareTo(BigDecimal.ZERO) > 0 &&
                            previous.getMacdHist().compareTo(BigDecimal.ZERO) > 0 &&
                            previous.getMacdHist().abs().compareTo(latest.getMacdHist().abs()) < 0;
        
        // 金叉或柱状线扩张任一满足即可
        return isGoldenCross && isExpanding && isUp;
        // 金叉柱状线扩张满足
        return isGoldenCross && isExpanding;
    }
    
    /**
@@ -390,14 +388,14 @@
    }
    /**
     * MACD死叉且柱状线收缩检查
     * MACD死叉且柱状线扩张检查
     * <p>
     * 条件:
     * 1. DIF线从上往下穿过DEA线(死叉)
     * 2. MACD柱状线绝对值减小且为负值(动量减弱)
     * 2. MACD柱状线绝对值增大且为负值(动量增强)
     * 
     * @param macdResult MACD计算结果
     * @return 是否形成MACD死叉或柱状线收缩
     * @return 是否形成MACD死叉且柱状线扩张
     */
    private boolean isMacdDeathCrossAndContracting(MACDResult macdResult) {
        List<PriceData> macdData = macdResult.getMacdData();
@@ -413,15 +411,13 @@
        boolean isDeathCross = prevPrev.getDif().compareTo(prevPrev.getDea()) >= 0 && 
                             previous.getDif().compareTo(previous.getDea()) < 0;
        
        boolean isDown  = latest.getDif().compareTo(BigDecimal.ZERO) < 0 && latest.getDea().compareTo(BigDecimal.ZERO) < 0;
        // 优化后的死叉柱状线条件:空头趋势中,死叉应伴随柱状线扩张(绝对值增大)
        boolean isExpanding = latest.getMacdHist().compareTo(BigDecimal.ZERO) < 0 &&
                previous.getMacdHist().compareTo(BigDecimal.ZERO) < 0 &&
                previous.getMacdHist().abs().compareTo(latest.getMacdHist().abs()) < 0;
        
        // 死叉或柱状线收缩任一满足即可
        return isDeathCross && isExpanding && isDown;
        // 死叉且柱状线扩张
        return isDeathCross && isExpanding;
    }
    
    /**