Administrator
2025-12-29 d802aae20f21f05e15c8ba8e9e2148fc7b6a0028
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/TradingStrategy.java
@@ -7,6 +7,7 @@
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
@@ -110,7 +111,7 @@
        calculateIndicators(prices, high, low, close);
        // 检查是否为震荡市场,如果是,则执行区间交易策略
        if (isRangeMarket()) {
        if (isRangeMarket(prices)) {
            log.info("当前市场为震荡行情,执行区间交易策略");
            return generateRangeTradingSignal(currentPrice, volume, hasLongPosition, hasShortPosition);
        }
@@ -128,7 +129,7 @@
        }
        // 开空信号
        if (shouldOpenShort(currentPrice, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) {
        if (shouldOpenShort(currentPrice, prices, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) {
            log.info("生成卖出信号");
            return SignalType.SELL;
        }
@@ -231,10 +232,28 @@
        // 创建临时MA指标用于判断趋势
        MA tempMA = new MA();
        MACD tempMACD = new MACD();
        // 计算指标
        tempMA.calculate(prices);
        tempMACD.calculate(prices);
        // 简单的趋势判断:短期MA > 长期MA
        return tempMA.getEma5().compareTo(tempMA.getEma20()) > 0;
        // 优化后的多头趋势判断:
        // 1. MA多头排列:短期MA > 中期MA > 长期MA
        // 2. 所有均线向上发散
        // 3. MACD趋势:DIFF线在DEA线之上
        boolean isMaBullish = tempMA.getEma5().compareTo(tempMA.getEma10()) > 0 &&
                             tempMA.getEma10().compareTo(tempMA.getEma20()) > 0;
        // 判断均线向上发散(简单方法:近期均线斜率为正)
        boolean isMaDivergingUp = calculateMaSlope(prices, 5) > 0 &&
                                 calculateMaSlope(prices, 10) > 0 &&
                                 calculateMaSlope(prices, 20) > 0;
        // MACD趋势判断
        boolean isMacdBullish = tempMACD.getDif().compareTo(tempMACD.getDea()) > 0;
        return isMaBullish && isMaDivergingUp && isMacdBullish;
    }
    /**
@@ -249,12 +268,56 @@
        // 创建临时MA指标用于判断趋势
        MA tempMA = new MA();
        MACD tempMACD = new MACD();
        // 计算指标
        tempMA.calculate(prices);
        tempMACD.calculate(prices);
        // 简单的趋势判断:短期MA < 长期MA
        return tempMA.getEma5().compareTo(tempMA.getEma20()) < 0;
        // 优化后的空头趋势判断:
        // 1. MA空头排列:短期MA < 中期MA < 长期MA
        // 2. 所有均线向下发散
        // 3. MACD趋势:DIFF线在DEA线之下
        boolean isMaBearish = tempMA.getEma5().compareTo(tempMA.getEma10()) < 0 &&
                             tempMA.getEma10().compareTo(tempMA.getEma20()) < 0;
        // 判断均线向下发散(简单方法:近期均线斜率为负)
        boolean isMaDivergingDown = calculateMaSlope(prices, 5) < 0 &&
                                   calculateMaSlope(prices, 10) < 0 &&
                                   calculateMaSlope(prices, 20) < 0;
        // MACD趋势判断
        boolean isMacdBearish = tempMACD.getDif().compareTo(tempMACD.getDea()) < 0;
        return isMaBearish && isMaDivergingDown && isMacdBearish;
    }
    /**
     * 计算均线斜率
     * @param prices 价格数据
     * @param period 均线周期
     * @return 均线斜率(正数表示向上,负数表示向下)
     */
    private double calculateMaSlope(List<BigDecimal> prices, int period) {
        if (prices == null || prices.size() < period * 2) {
            return 0; // 数据不足
        }
        // 获取最近两个周期的均线值
        int endIndex = prices.size() - 1;
        int startIndex = endIndex - period + 1;
        // 计算当前周期的均线
        BigDecimal currentMa = calculateMA(prices.subList(startIndex, endIndex + 1), period);
        // 计算前一个周期的均线
        int prevStartIndex = startIndex - period;
        BigDecimal prevMa = calculateMA(prices.subList(prevStartIndex, startIndex), period);
        // 计算斜率(简单差值法)
        return currentMa.subtract(prevMa).doubleValue();
    }
    /**
     * 成交量验证辅助方法
     * 增强版:当前成交量需大于20周期均量的1.2倍,以过滤无量反弹/回调的假信号
@@ -345,16 +408,80 @@
    /**
     * 检查是否为震荡市场
     * @param prices 价格数据列表
     * @return 是否为震荡市场
     */
    private boolean isRangeMarket() {
        // 高级MA线收敛 + RSI(40-60) + 布林带收窄
        boolean isMaConverged = advancedMA.calculatePercent().compareTo(new BigDecimal(2)) < 0;
        boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(40)) > 0 &&
                              rsi.getRsi().compareTo(new BigDecimal(60)) < 0;
        boolean isBollNarrow = boll.calculateBandWidth().compareTo(new BigDecimal(0.05)) < 0;
        return isMaConverged && isRsiNeutral && isBollNarrow;
    private boolean isRangeMarket(List<BigDecimal> prices) {
        // 优化的震荡市场判断条件,放宽标准以减少RANGING信号频率
        // 1. 高级MA三线收敛(小于3%,放宽条件)
        boolean isMaConverged = advancedMA.calculatePercent().compareTo(new BigDecimal(3)) < 0;
        // 2. RSI中性区间(35-65,放宽条件)
        boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(35)) > 0 &&
                              rsi.getRsi().compareTo(new BigDecimal(65)) < 0;
        // 3. BOLL带宽收窄(小于0.06,放宽条件)
        boolean isBollNarrow = boll.calculateBandWidth().compareTo(new BigDecimal(0.06)) < 0;
        // 4. MACD柱状图趋近于0(多空力量平衡,放宽条件)
        boolean isMacdBalanced = macd.getMacdBar().abs().compareTo(new BigDecimal(0.02)) < 0;
        // 5. KDJ在中间区域波动(25-75,放宽条件)
        boolean isKdjNeutral = kdj.getK().compareTo(new BigDecimal(25)) > 0 &&
                             kdj.getK().compareTo(new BigDecimal(75)) < 0 &&
                             kdj.getD().compareTo(new BigDecimal(25)) > 0 &&
                             kdj.getD().compareTo(new BigDecimal(75)) < 0 &&
                             kdj.getJ().compareTo(new BigDecimal(20)) > 0 &&
                             kdj.getJ().compareTo(new BigDecimal(80)) < 0;
        // 6. 价格波动范围较小(最近20根K线最高价与最低价的比值小于1.06,放宽条件)
        boolean isPriceVolatilityLow = calculatePriceVolatility(prices).compareTo(new BigDecimal(1.06)) < 0;
        // 综合判断:只需要满足部分条件即可,增加趋势信号的机会
        int rangeConditionsMet = 0;
        if (isMaConverged) {
            rangeConditionsMet++;
        }
        if (isRsiNeutral) {
            rangeConditionsMet++;
        }
        if (isBollNarrow) {
            rangeConditionsMet++;
        }
        if (isMacdBalanced) {
            rangeConditionsMet++;
        }
        if (isKdjNeutral) {
            rangeConditionsMet++;
        }
        if (isPriceVolatilityLow) {
            rangeConditionsMet++;
        }
        // 只有满足4个或以上条件才判定为震荡市场
        return rangeConditionsMet >= 4;
    }
    /**
     * 计算价格波动率(最近20根K线最高价与最低价的比值)
     * @param prices 价格数据列表
     * @return 价格波动率
     */
    private BigDecimal calculatePriceVolatility(List<BigDecimal> prices) {
        if (prices == null || prices.isEmpty()) {
            return BigDecimal.ONE;
        }
        List<BigDecimal> recentPrices = prices.subList(Math.max(0, prices.size() - 20), prices.size());
        if (recentPrices.isEmpty()) {
            return BigDecimal.ONE;
        }
        BigDecimal highest = recentPrices.stream().max(BigDecimal::compareTo).orElse(BigDecimal.ONE);
        BigDecimal lowest = recentPrices.stream().min(BigDecimal::compareTo).orElse(BigDecimal.ONE);
        return highest.divide(lowest, 10, RoundingMode.HALF_UP);
    }
@@ -368,38 +495,48 @@
     * @param currentPrice 当前价格
     * @return 市场方向
     */
    public Direction getDirection(List<BigDecimal> prices, List<BigDecimal> high,
    public Direction getDirection(List<BigDecimal> prices, List<BigDecimal> high,
                                List<BigDecimal> low, List<BigDecimal> close,
                                BigDecimal currentPrice) {
        // 计算所有指标
        calculateIndicators(prices, high, low, close);
        // 检查是否为震荡市场
        if (isRangeMarket()) {
        if (isRangeMarket(prices)) {
            return Direction.RANGING;
        }
        // 检查做多方向条件:MA多头排列 + MACD金叉 + RSI中性(30-70) + BOLL价格在上轨和中轨之间
        // 优化后的多头趋势条件:
        // 1. MA多头排列(短期MA > 中期MA > 长期MA)
        // 2. MACD趋势(DIFF在DEA之上,代表多头趋势)
        // 3. 价格在BOLL中轨上方
        // 4. RSI(50-65) 为健康多头区间
        boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 &&
                              ma.getEma10().compareTo(ma.getEma20()) > 0;
        boolean isMacdGoldenCross = macd.getDif().compareTo(macd.getDea()) > 0;
        boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 &&
                              rsi.getRsi().compareTo(new BigDecimal(70)) < 0;
        boolean isPriceInUpperMid = currentPrice.compareTo(boll.getMid()) > 0 &&
                                   currentPrice.compareTo(boll.getUpper()) < 0;
        if (isMaBullish && isMacdGoldenCross && isRsiNeutral && isPriceInUpperMid) {
        boolean isMacdBullish = macd.getDif().compareTo(macd.getDea()) > 0;
        boolean isPriceAboveBollMid = currentPrice.compareTo(boll.getMid()) > 0;
        boolean isRsiBullish = rsi.getRsi().compareTo(new BigDecimal(50)) > 0 &&
                              rsi.getRsi().compareTo(new BigDecimal(65)) < 0;
        // 检查多头信号(MA多头 + MACD金叉 + 价格在BOLL中轨上方 + RSI(50-65))
        if (isMaBullish && isMacdBullish && isPriceAboveBollMid && isRsiBullish) {
            return Direction.LONG;
        }
        // 检查做空方向条件:MA空头排列 + MACD死叉 + RSI中性(30-70) + BOLL价格在下轨和中轨之间
        // 优化后的空头趋势条件:
        // 1. MA空头排列(短期MA < 中期MA < 长期MA)
        // 2. MACD趋势(DIFF在DEA之下,代表空头趋势)
        // 3. 价格在BOLL中轨下方
        // 4. RSI(35-50) 为健康空头区间
        boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 &&
                              ma.getEma10().compareTo(ma.getEma20()) < 0;
        boolean isMacdDeathCross = macd.getDif().compareTo(macd.getDea()) < 0;
        boolean isPriceInLowerMid = currentPrice.compareTo(boll.getLower()) > 0 &&
                                   currentPrice.compareTo(boll.getMid()) < 0;
        if (isMaBearish && isMacdDeathCross && isRsiNeutral && isPriceInLowerMid) {
        boolean isMacdBearish = macd.getDif().compareTo(macd.getDea()) < 0;
        boolean isPriceBelowBollMid = currentPrice.compareTo(boll.getMid()) < 0;
        boolean isRsiBearish = rsi.getRsi().compareTo(new BigDecimal(35)) > 0 &&
                              rsi.getRsi().compareTo(new BigDecimal(50)) < 0;
        // 检查空头信号(MA空头 + MACD死叉 + 价格在BOLL中轨下方 + RSI(35-50))
        if (isMaBearish && isMacdBearish && isPriceBelowBollMid && isRsiBearish) {
            return Direction.SHORT;
        }
@@ -408,8 +545,10 @@
    }
    /**
     * 根据用户要求检查是否应该开多仓位
     * 条件:MA金叉 + MACD金叉 + KDJ金叉 + RSI中性 + 价格高于BOLL中轨 + 多周期确认 + 成交量验证
     * 根据优化建议检查是否应该开多仓位
     * 使用主次结合法:
     * - 主信号(趋势):MA多头排列 + MACD金叉
     * - 辅信号(入场点):价格回调至BOLL中轨附近获得支撑,且出现KDJ金叉或RSI从低位回升至50以上
     * @param currentPrice 当前价格
     * @param prices 价格数据
     * @param volume 成交量列表
@@ -422,17 +561,40 @@
                                  List<BigDecimal> fiveMinPrices,
                                  List<BigDecimal> oneHourPrices,
                                  List<BigDecimal> fourHourPrices) {
        // MA金叉 (5EMA > 20EMA)
        boolean isMaGoldenCross = ma.getEma5().compareTo(ma.getEma20()) > 0;
        // MACD金叉 (DIF > DEA)
        boolean isMacdGoldenCross = macd.getDif().compareTo(macd.getDea()) > 0;
        // KDJ金叉 (K线上穿D线)
        boolean isKdjGoldenCross = kdj.isGoldenCross();
        // RSI中性 (30-70)
        boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 &&
        // 主信号:趋势判断
        // MA多头排列(短期MA > 中期MA > 长期MA)
        boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 &&
                             ma.getEma10().compareTo(ma.getEma20()) > 0;
        // MACD趋势(DIFF在DEA之上)
        boolean isMacdBullish = macd.getDif().compareTo(macd.getDea()) > 0;
        // 如果主信号不满足,直接返回false
        if (!(isMaBullish && isMacdBullish)) {
            return false;
        }
        // 辅信号:入场点判断
        // 价格在BOLL中轨上方,且未触及上轨(避免追高)
        boolean isPriceInSafeZone = currentPrice.compareTo(boll.getMid()) > 0 &&
                                   currentPrice.compareTo(boll.getUpper()) < 0;
        // 价格靠近BOLL中轨
        boolean isPriceNearBollMid = currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(0.98))) > 0 &&
                                    currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(1.02))) < 0;
        // RSI:健康区间30-70,刚从50中线向上
        boolean isRsiHealthy = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 &&
                              rsi.getRsi().compareTo(new BigDecimal(70)) < 0;
        // 价格高于BOLL中轨
        boolean isPriceAboveBollMid = currentPrice.compareTo(boll.getMid()) > 0;
        boolean isRsiAboveMid = rsi.getRsi().compareTo(new BigDecimal(50)) > 0;
        // KDJ:金叉或超卖区域
        boolean isKdjGoldenCross = kdj.isGoldenCross();
        boolean isKdjOversold = kdj.getJ().compareTo(new BigDecimal(15)) < 0;
        // 入场点条件:价格在安全区域或靠近中轨,且动量健康
        boolean isEntryPointValid = (isPriceInSafeZone || isPriceNearBollMid) &&
                                   (isRsiHealthy && isRsiAboveMid) &&
                                   (isKdjGoldenCross || isKdjOversold);
        // 成交量验证
        boolean isVolumeConfirmed = volumeConfirm(volume);
        // 量价背离检测
@@ -440,48 +602,76 @@
        // 多周期确认
        boolean isMultiTimeframeConfirmed = multiTimeframeConfirm(fiveMinPrices, oneHourPrices, fourHourPrices);
        return isMaGoldenCross && isMacdGoldenCross && isKdjGoldenCross &&
               isRsiNeutral && isPriceAboveBollMid && isVolumeConfirmed &&
               !isPriceVolumeDivergence && isMultiTimeframeConfirmed;
        return isEntryPointValid && isVolumeConfirmed && !isPriceVolumeDivergence && isMultiTimeframeConfirmed;
    }
    /**
     * 根据用户要求检查是否应该开空仓位
     * 条件:MA死叉 + MACD死叉 + KDJ死叉 + RSI中性 + 价格低于BOLL中轨 + 多周期确认 + 成交量验证
     * 根据优化建议检查是否应该开空仓位
     * 使用主次结合法:
     * - 主信号(趋势):MA空头排列 + MACD死叉
     * - 辅信号(入场点):价格反弹至BOLL中轨附近遇阻,且出现KDJ死叉或RSI从高位回落至50以下
     * @param currentPrice 当前价格
     * @param prices 价格数据
     * @param volume 成交量列表
     * @param fiveMinPrices 5分钟价格数据
     * @param oneHourPrices 1小时价格数据
     * @param fourHourPrices 4小时价格数据
     * @return 是否应该开空
     */
    private boolean shouldOpenShort(BigDecimal currentPrice, List<BigDecimal> volume,
    private boolean shouldOpenShort(BigDecimal currentPrice, List<BigDecimal> prices, List<BigDecimal> volume,
                                   List<BigDecimal> fiveMinPrices,
                                   List<BigDecimal> oneHourPrices,
                                   List<BigDecimal> fourHourPrices) {
        // MA死叉 (5EMA < 20EMA)
        boolean isMaDeathCross = ma.getEma5().compareTo(ma.getEma20()) < 0;
        // MACD死叉 (DIF < DEA)
        boolean isMacdDeathCross = macd.getDif().compareTo(macd.getDea()) < 0;
        // KDJ死叉 (K线下穿D线)
        boolean isKdjDeathCross = kdj.isDeathCross();
        // RSI中性 (30-70)
        boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 &&
        // 主信号:趋势判断
        // MA空头排列(短期MA < 中期MA < 长期MA)
        boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 &&
                             ma.getEma10().compareTo(ma.getEma20()) < 0;
        // MACD趋势(DIFF在DEA之下)
        boolean isMacdBearish = macd.getDif().compareTo(macd.getDea()) < 0;
        // 如果主信号不满足,直接返回false
        if (!(isMaBearish && isMacdBearish)) {
            return false;
        }
        // 辅信号:入场点判断
        // 价格在BOLL中轨下方,且未触及下轨(避免追空)
        boolean isPriceInSafeZone = currentPrice.compareTo(boll.getMid()) < 0 &&
                                   currentPrice.compareTo(boll.getLower()) > 0;
        // 价格靠近BOLL中轨
        boolean isPriceNearBollMid = currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(0.98))) > 0 &&
                                    currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(1.02))) < 0;
        // RSI:健康区间30-70,刚从50中线向下
        boolean isRsiHealthy = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 &&
                              rsi.getRsi().compareTo(new BigDecimal(70)) < 0;
        // 价格低于BOLL中轨
        boolean isPriceBelowBollMid = currentPrice.compareTo(boll.getMid()) < 0;
        boolean isRsiBelowMid = rsi.getRsi().compareTo(new BigDecimal(50)) < 0;
        // KDJ:死叉或超买区域
        boolean isKdjDeathCross = kdj.isDeathCross();
        boolean isKdjOverbought = kdj.getJ().compareTo(new BigDecimal(85)) > 0;
        // 入场点条件:价格在安全区域或靠近中轨,且动量健康
        boolean isEntryPointValid = (isPriceInSafeZone || isPriceNearBollMid) &&
                                   (isRsiHealthy && isRsiBelowMid) &&
                                   (isKdjDeathCross || isKdjOverbought);
        // 成交量验证
        boolean isVolumeConfirmed = volumeConfirm(volume);
        // 量价背离检测
        boolean isPriceVolumeDivergence = hasPriceVolumeDivergence(prices, volume);
        // 多周期确认(看跌)
        boolean isMultiTimeframeConfirmed = multiTimeframeBearishConfirm(fiveMinPrices, oneHourPrices, fourHourPrices);
        return isMaDeathCross && isMacdDeathCross && isKdjDeathCross &&
               isRsiNeutral && isPriceBelowBollMid && isVolumeConfirmed && isMultiTimeframeConfirmed;
        return isEntryPointValid && isVolumeConfirmed && !isPriceVolumeDivergence && isMultiTimeframeConfirmed;
    }
    /**
     * 根据用户要求检查是否应该平多仓位
     * 条件:MA死叉 + MACD死叉 + RSI超买 + 价格低于BOLL中轨 + 多周期确认
     * 根据优化建议检查是否应该平多仓位
     * 采用分层止盈止损策略:
     * - 保护止损:价格跌破BOLL中轨
     * - 跟踪止损:价格有效跌破移动平均线
     * - 最终平仓:趋势反转信号(MA空头排列 + MACD死叉)
     * @param currentPrice 当前价格
     * @param volume 成交量列表
     * @param fiveMinPrices 5分钟价格数据
@@ -493,23 +683,31 @@
                                   List<BigDecimal> fiveMinPrices,
                                   List<BigDecimal> oneHourPrices,
                                   List<BigDecimal> fourHourPrices) {
        // MA死叉 (5EMA < 20EMA)
        boolean isMaDeathCross = ma.getEma5().compareTo(ma.getEma20()) < 0;
        // MACD死叉 (DIF < DEA)
        boolean isMacdDeathCross = macd.getDif().compareTo(macd.getDea()) < 0;
        // RSI超买 (>70)
        boolean isRsiOverbought = rsi.isOverbought();
        // 价格低于BOLL中轨
        boolean isPriceBelowBollMid = currentPrice.compareTo(boll.getMid()) < 0;
        // 保护止损:价格跌破BOLL中轨(关键支撑位)
        boolean isStopLossTriggered = currentPrice.compareTo(boll.getMid()) < 0;
        // 跟踪止损:价格有效跌破短期均线(5EMA)
        boolean isTrailingStopTriggered = currentPrice.compareTo(ma.getEma5()) < 0;
        // 趋势反转信号:MA空头排列 + MACD死叉
        boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 &&
                             ma.getEma10().compareTo(ma.getEma20()) < 0;
        boolean isMacdBearish = macd.getDif().compareTo(macd.getDea()) < 0;
        boolean isTrendReversed = isMaBearish && isMacdBearish;
        // 多周期确认(看跌)
        boolean isMultiTimeframeConfirmed = multiTimeframeBearishConfirm(fiveMinPrices, oneHourPrices, fourHourPrices);
        return isMaDeathCross && isMacdDeathCross && isRsiOverbought && isPriceBelowBollMid && isMultiTimeframeConfirmed;
        // 平多条件:保护止损触发 或 跟踪止损触发 或 (趋势反转且多周期确认)
        return isStopLossTriggered || isTrailingStopTriggered || (isTrendReversed && isMultiTimeframeConfirmed);
    }
    /**
     * 根据用户要求检查是否应该平空仓位
     * 条件:MA金叉 + MACD金叉 + RSI超卖 + 价格高于BOLL中轨 + 多周期确认
     * 根据优化建议检查是否应该平空仓位
     * 采用分层止盈止损策略:
     * - 保护止损:价格突破BOLL中轨
     * - 跟踪止损:价格有效突破移动平均线
     * - 最终平仓:趋势反转信号(MA多头排列 + MACD金叉)
     * @param currentPrice 当前价格
     * @param volume 成交量列表
     * @param fiveMinPrices 5分钟价格数据
@@ -521,18 +719,23 @@
                                    List<BigDecimal> fiveMinPrices,
                                    List<BigDecimal> oneHourPrices,
                                    List<BigDecimal> fourHourPrices) {
        // MA金叉 (5EMA > 20EMA)
        boolean isMaGoldenCross = ma.getEma5().compareTo(ma.getEma20()) > 0;
        // MACD金叉 (DIF > DEA)
        boolean isMacdGoldenCross = macd.getDif().compareTo(macd.getDea()) > 0;
        // RSI超卖 (<30)
        boolean isRsiOversold = rsi.isOversold();
        // 价格高于BOLL中轨
        boolean isPriceAboveBollMid = currentPrice.compareTo(boll.getMid()) > 0;
        // 保护止损:价格突破BOLL中轨(关键阻力位)
        boolean isStopLossTriggered = currentPrice.compareTo(boll.getMid()) > 0;
        // 跟踪止损:价格有效突破短期均线(5EMA)
        boolean isTrailingStopTriggered = currentPrice.compareTo(ma.getEma5()) > 0;
        // 趋势反转信号:MA多头排列 + MACD金叉
        boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 &&
                             ma.getEma10().compareTo(ma.getEma20()) > 0;
        boolean isMacdBullish = macd.getDif().compareTo(macd.getDea()) > 0;
        boolean isTrendReversed = isMaBullish && isMacdBullish;
        // 多周期确认(看涨)
        boolean isMultiTimeframeConfirmed = multiTimeframeConfirm(fiveMinPrices, oneHourPrices, fourHourPrices);
        return isMaGoldenCross && isMacdGoldenCross && isRsiOversold && isPriceAboveBollMid && isMultiTimeframeConfirmed;
        // 平空条件:保护止损触发 或 跟踪止损触发 或 (趋势反转且多周期确认)
        return isStopLossTriggered || isTrailingStopTriggered || (isTrendReversed && isMultiTimeframeConfirmed);
    }
    /**
@@ -565,13 +768,25 @@
        // 2. 价格触及BOLL上轨且KDJ超买 → 卖出信号
        // 3. 价格回归BOLL中轨 → 平仓信号
        
        // 价格触及BOLL下轨
        boolean isPriceNearBollLower = currentPrice.compareTo(boll.getLower()) >= 0 &&
                                      currentPrice.compareTo(boll.getLower().multiply(new BigDecimal("1.005"))) <= 0;
        // 检查KDJ极端超买超卖情况
        boolean isKdjJExtremeOverbought = kdj.getJ().compareTo(new BigDecimal("100")) > 0;
        boolean isKdjJExtremeOversold = kdj.getJ().compareTo(new BigDecimal("10")) < 0;
        
        // 价格触及BOLL上轨
        // 价格触及BOLL下轨(基础条件)
        boolean isPriceNearBollLower = currentPrice.compareTo(boll.getLower()) >= 0 &&
                                      currentPrice.compareTo(boll.getLower().multiply(new BigDecimal("1.01"))) <= 0;
        // 价格触及BOLL上轨(基础条件)
        boolean isPriceNearBollUpper = currentPrice.compareTo(boll.getUpper()) <= 0 && 
                                      currentPrice.compareTo(boll.getUpper().multiply(new BigDecimal("0.995"))) >= 0;
                                      currentPrice.compareTo(boll.getUpper().multiply(new BigDecimal("0.99"))) >= 0;
        // 当KDJ-J极度超买/超卖时,放宽BOLL边界要求
        if (isKdjJExtremeOverbought) {
            isPriceNearBollUpper = currentPrice.compareTo(boll.getUpper().multiply(new BigDecimal("0.985"))) >= 0;
        }
        if (isKdjJExtremeOversold) {
            isPriceNearBollLower = currentPrice.compareTo(boll.getLower().multiply(new BigDecimal("1.015"))) <= 0;
        }
        
        // 价格回归BOLL中轨附近
        boolean isPriceNearBollMid = currentPrice.compareTo(boll.getMid().multiply(new BigDecimal("0.998"))) >= 0 && 
@@ -583,19 +798,25 @@
        // KDJ超买(使用调整后的阈值)
        boolean isKdjOverbought = kdj.getJ().compareTo(new BigDecimal(85)) > 0;
        
        // 成交量验证(当前成交量大于20周期均值的1.2倍)
        boolean isVolumeValid = volumeConfirm(volume) &&
                               volume.get(volume.size() - 1).compareTo(calculateMA(volume, config.getVolumeMaPeriod()).multiply(new BigDecimal("1.2"))) > 0;
        // RSI超卖(<30)
        boolean isRsiOversold = rsi.getRsi().compareTo(new BigDecimal(30)) < 0;
        
        // 开多逻辑:价格触及BOLL下轨且KDJ超卖且有成交量支持
        if (isPriceNearBollLower && isKdjOversold && isVolumeValid && !hasLongPosition && !hasShortPosition) {
            log.info("区间交易:价格触及BOLL下轨({}), KDJ-J值({})超卖,生成买入信号", boll.getLower(), kdj.getJ());
        // RSI超买(>70)
        boolean isRsiOverbought = rsi.getRsi().compareTo(new BigDecimal(70)) > 0;
        // 成交量验证(当前成交量大于20周期均值的1.1倍)
        boolean isVolumeValid = volumeConfirm(volume) &&
                               volume.get(volume.size() - 1).compareTo(calculateMA(volume, config.getVolumeMaPeriod()).multiply(new BigDecimal("1.1"))) > 0;
        // 开多逻辑:价格触及BOLL下轨且KDJ超卖且RSI超卖且有成交量支持
        if (isPriceNearBollLower && isKdjOversold && isRsiOversold && isVolumeValid && !hasLongPosition && !hasShortPosition) {
            log.info("区间交易:价格触及BOLL下轨({}), KDJ-J值({})超卖,RSI({})超卖,生成买入信号", boll.getLower(), kdj.getJ(), rsi.getRsi());
            return SignalType.BUY;
        }
        
        // 开空逻辑:价格触及BOLL上轨且KDJ超买且有成交量支持
        if (isPriceNearBollUpper && isKdjOverbought && isVolumeValid && !hasLongPosition && !hasShortPosition) {
            log.info("区间交易:价格触及BOLL上轨({}), KDJ-J值({})超买,生成卖出信号", boll.getUpper(), kdj.getJ());
        // 开空逻辑:价格触及BOLL上轨且KDJ超买且RSI超买且有成交量支持
        if (isPriceNearBollUpper && isKdjOverbought && isRsiOverbought && isVolumeValid && !hasLongPosition && !hasShortPosition) {
            log.info("区间交易:价格触及BOLL上轨({}), KDJ-J值({})超买,RSI({})超买,生成卖出信号", boll.getUpper(), kdj.getJ(), rsi.getRsi());
            return SignalType.SELL;
        }