Administrator
8 days ago b6b63e31d3f25784a4f4e0add7045a3d724d22fb
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java
@@ -22,6 +22,13 @@
public class MacdMaStrategy {
    /** 持仓状态枚举 */
    public enum OperationType {
        /** 开仓平仓 */
        open,
        close
    }
    /** 持仓状态枚举 */
    public enum PositionType {
        /** 多头持仓 */
        LONG_BUY,
@@ -40,10 +47,6 @@
    private int volatilityPeriod; // 波动率计算周期
    private BigDecimal stopLossRatio;   // 止损比例
    private BigDecimal takeProfitRatio; // 止盈比例
    // 持仓信息
    private BigDecimal entryPrice;       // 开仓价格
    private long entryTime;              // 开仓时间戳
    /**
     * 默认构造函数,使用标准MACD参数
@@ -73,9 +76,6 @@
        this.stopLossRatio = stopLossRatio;
        this.takeProfitRatio = takeProfitRatio;
        // 初始化持仓状态为空仓
        this.entryPrice = BigDecimal.ZERO;
        this.entryTime = 0;
    }
    /**
@@ -84,7 +84,7 @@
     * @param closePrices 收盘价序列
     * @return 生成的交易信号(LONG、SHORT或NONE)
     */
    public PositionType analyze(List<BigDecimal> closePrices) {
    public PositionType analyzeOpen(List<BigDecimal> closePrices) {
        // 数据检查:确保有足够的数据点进行计算
        if (closePrices == null || closePrices.size() < 34) {
            return PositionType.NONE; // 数据不足,无法生成信号
@@ -109,24 +109,49 @@
        // 多头开仓条件检查
        if (isLongEntryCondition(macdResult, closePrices, volatility.getValue())) {
            // 执行开多
            this.entryPrice = latestPrice;
            this.entryTime = System.currentTimeMillis();
            log.info( "多头开仓信号,价格:{}", latestPrice);
            return PositionType.LONG_BUY;
        }
        // 空头开仓条件检查
        if (isShortEntryCondition(macdResult, closePrices, volatility.getValue())) {
            // 执行开空
            this.entryPrice = latestPrice;
            this.entryTime = System.currentTimeMillis();
             log.info( "空头开仓信号,价格:{}", latestPrice);
            return PositionType.SHORT_SELL;
        }
         if (isLongExitCondition(macdResult, latestPrice)) {
              // 执行平多
             return PositionType.LONG_SELL;
        // 无信号
        return PositionType.NONE;
    }
    /**
     * 分析最新价格数据并生成交易信号
     *
     * @param closePrices 收盘价序列
     * @return 生成的交易信号(LONG、SHORT或NONE)
     */
    public PositionType analyzeClose(List<BigDecimal> closePrices) {
        // 数据检查:确保有足够的数据点进行计算
        if (closePrices == null || closePrices.size() < 34) {
            return PositionType.NONE; // 数据不足,无法生成信号
        }
         if (isShortExitCondition(macdResult, latestPrice)) {
              return PositionType.SHORT_BUY;
        // 1. 计算MACD指标
        MACDResult macdResult = MACDCalculator.calculateMACD(
                closePrices, shortPeriod, longPeriod, signalPeriod);
        // 最新收盘价
        BigDecimal latestPrice = closePrices.get(closePrices.size() - 1);
        if (isLongExitCondition(macdResult, latestPrice)) {
            // 执行平多
            log.info( "多头平仓信号,价格:{}", latestPrice);
            return PositionType.LONG_SELL;
        }
        if (isShortExitCondition(macdResult, latestPrice)) {
            // 执行平空
            log.info( "空头平仓信号,价格:{}", latestPrice);
            return PositionType.SHORT_BUY;
        }
        // 无信号
@@ -166,9 +191,18 @@
     * @param historicalPrices 历史价格序列
     * @return 交易指令(包含side和posSide),如果没有交易信号则返回null
     */
    public TradingOrder generateTradingOrder(List<BigDecimal> historicalPrices) {
        PositionType signal = analyze(historicalPrices);
    public TradingOrder generateTradingOrder(List<BigDecimal> historicalPrices,String operation) {
        PositionType signal =  null;
        if ( operation == OperationType.open.name()){
            signal = analyzeOpen(historicalPrices);
        }else  if ( operation == OperationType.close.name()){
            signal = analyzeClose(historicalPrices);
        }
        // 根据信号和当前持仓状态生成交易指令
        if (signal == PositionType.LONG_BUY) {
            // 开多:买入开多(side 填写 buy; posSide 填写 long )
@@ -206,13 +240,18 @@
        // 4. 波动率过滤(必须在合理范围内)
        boolean volatilityFilter = isVolatilityInRange(volatility);
        
        if (macdPositive && volatilityFilter && isMacdFavorable) {
            log.info("多头信号形成, MACD有利状态: {}, 柱状线为正: {}, 波动率过滤: {}",
                    isMacdFavorable, macdPositive, volatilityFilter);
        }
        // 5. 底背离检查(增强多头信号可靠性)
        boolean isBottomDivergence = MACDCalculator.isBottomDivergence(closePrices, macdResult);
        
        // 所有条件必须同时满足
        return macdPositive && volatilityFilter && isMacdFavorable;
        boolean result = macdPositive && volatilityFilter && (isMacdFavorable || isBottomDivergence);
        if (result) {
            log.info("多头信号形成, MACD有利状态: {}, 柱状线为正: {}, 波动率过滤: {}, 底背离: {}",
                    isMacdFavorable, macdPositive, volatilityFilter, isBottomDivergence);
        }
        return result;
    }
    /**
@@ -233,13 +272,18 @@
        // 4. 波动率过滤(必须在合理范围内)
        boolean volatilityFilter = isVolatilityInRange(volatility);
        
        if (macdNegative && volatilityFilter && isMacdFavorable) {
            log.info("空头信号形成, MACD有利状态: {}, 柱状线为负: {}, 波动率过滤: {}",
                    isMacdFavorable, macdNegative, volatilityFilter);
        }
        // 5. 顶背离检查(增强空头信号可靠性)
        boolean isTopDivergence = MACDCalculator.isTopDivergence(closePrices, macdResult);
        
        // 所有条件必须同时满足
        return macdNegative && volatilityFilter && isMacdFavorable;
        boolean result = macdNegative && volatilityFilter && (isMacdFavorable || isTopDivergence);
        if (result) {
            log.info("空头信号形成, MACD有利状态: {}, 柱状线为负: {}, 波动率过滤: {}, 顶背离: {}",
                    isMacdFavorable, macdNegative, volatilityFilter, isTopDivergence);
        }
        return result;
    }
    
    /**
@@ -312,14 +356,14 @@
        // 金叉判断:DIF从下往上穿过DEA
        boolean isGoldenCross = prevPrev.getDif().compareTo(prevPrev.getDea()) <= 0 && 
                              previous.getDif().compareTo(previous.getDea()) > 0;
        // 柱状线扩张判断:连续正值且绝对值增大
        boolean isExpanding = latest.getMacdHist().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;
        // 金叉柱状线扩张满足
        return isGoldenCross && isExpanding;
    }
    
    /**
@@ -344,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();
@@ -367,13 +411,13 @@
        boolean isDeathCross = prevPrev.getDif().compareTo(prevPrev.getDea()) >= 0 && 
                             previous.getDif().compareTo(previous.getDea()) < 0;
        
        // 柱状线收缩判断:连续负值且绝对值减小
        boolean isContracting = latest.getMacdHist().compareTo(BigDecimal.ZERO) < 0 &&
                              previous.getMacdHist().compareTo(BigDecimal.ZERO) < 0 &&
                              previous.getMacdHist().abs().compareTo(latest.getMacdHist().abs()) > 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 || isContracting;
        // 死叉且柱状线扩张
        return isDeathCross && isExpanding;
    }
    
    /**
@@ -439,22 +483,4 @@
                volatility.compareTo(maxVolatility) <= 0;
    }
    /**
     * 获取开仓价格
     *
     * @return 开仓价格
     */
    public BigDecimal getEntryPrice() {
        return entryPrice;
    }
    /**
     * 获取开仓时间戳
     *
     * @return 开仓时间戳
     */
    public long getEntryTime() {
        return entryTime;
    }
}