| | |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | |
| | | calculateIndicators(prices, high, low, close); |
| | | |
| | | // 检查是否为震荡市场,如果是,则执行区间交易策略 |
| | | if (isRangeMarket()) { |
| | | if (isRangeMarket(prices)) { |
| | | log.info("当前市场为震荡行情,执行区间交易策略"); |
| | | return generateRangeTradingSignal(currentPrice, volume, hasLongPosition, hasShortPosition); |
| | | } |
| | |
| | | } |
| | | |
| | | // 开空信号 |
| | | if (shouldOpenShort(currentPrice, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) { |
| | | if (shouldOpenShort(currentPrice, prices, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) { |
| | | log.info("生成卖出信号"); |
| | | return SignalType.SELL; |
| | | } |
| | |
| | | |
| | | // 创建临时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; |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | // 创建临时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倍,以过滤无量反弹/回调的假信号 |
| | |
| | | |
| | | /** |
| | | * 检查是否为震荡市场 |
| | | * @param prices 价格数据列表 |
| | | * @return 是否为震荡市场 |
| | | */ |
| | | private boolean isRangeMarket() { |
| | | // 高级MA线收敛 + RSI(40-60) + 布林带收窄 |
| | | private boolean isRangeMarket(List<BigDecimal> prices) { |
| | | // 强化的震荡市场判断条件 |
| | | |
| | | // 1. 高级MA三线收敛(小于2%) |
| | | boolean isMaConverged = advancedMA.calculatePercent().compareTo(new BigDecimal(2)) < 0; |
| | | |
| | | // 2. RSI中性区间(40-60) |
| | | boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(40)) > 0 && |
| | | rsi.getRsi().compareTo(new BigDecimal(60)) < 0; |
| | | |
| | | // 3. BOLL带宽收窄(小于0.05) |
| | | boolean isBollNarrow = boll.calculateBandWidth().compareTo(new BigDecimal(0.05)) < 0; |
| | | |
| | | return isMaConverged && isRsiNeutral && isBollNarrow; |
| | | |
| | | // 4. MACD柱状图趋近于0(多空力量平衡) |
| | | boolean isMacdBalanced = macd.getMacdBar().abs().compareTo(new BigDecimal(0.01)) < 0; |
| | | |
| | | // 5. KDJ在中间区域波动(30-70) |
| | | boolean isKdjNeutral = kdj.getK().compareTo(new BigDecimal(30)) > 0 && |
| | | kdj.getK().compareTo(new BigDecimal(70)) < 0 && |
| | | kdj.getD().compareTo(new BigDecimal(30)) > 0 && |
| | | kdj.getD().compareTo(new BigDecimal(70)) < 0 && |
| | | kdj.getJ().compareTo(new BigDecimal(30)) > 0 && |
| | | kdj.getJ().compareTo(new BigDecimal(70)) < 0; |
| | | |
| | | // 6. 价格波动范围较小(最近20根K线最高价与最低价的比值小于1.05) |
| | | boolean isPriceVolatilityLow = calculatePriceVolatility(prices).compareTo(new BigDecimal(1.05)) < 0; |
| | | |
| | | // 综合判断:需要满足大部分条件 |
| | | return isMaConverged && isRsiNeutral && isBollNarrow && |
| | | (isMacdBalanced || isKdjNeutral || isPriceVolatilityLow); |
| | | } |
| | | |
| | | /** |
| | | * 计算价格波动率(最近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); |
| | | } |
| | | |
| | | |
| | |
| | | * @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; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * 根据用户要求检查是否应该开多仓位 |
| | | * 条件:MA金叉 + MACD金叉 + KDJ金叉 + RSI中性 + 价格高于BOLL中轨 + 多周期确认 + 成交量验证 |
| | | * 根据优化建议检查是否应该开多仓位 |
| | | * 使用主次结合法: |
| | | * - 主信号(趋势):MA多头排列 + MACD金叉 |
| | | * - 辅信号(入场点):价格回调至BOLL中轨附近获得支撑,且出现KDJ金叉或RSI从低位回升至50以上 |
| | | * @param currentPrice 当前价格 |
| | | * @param prices 价格数据 |
| | | * @param volume 成交量列表 |
| | |
| | | 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); |
| | | // 量价背离检测 |
| | |
| | | // 多周期确认 |
| | | 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分钟价格数据 |
| | |
| | | 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分钟价格数据 |
| | |
| | | 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); |
| | | } |
| | | |
| | | /** |