From b2efc99a201ed8a815640c7d6b757eecd82ee629 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Wed, 24 Dec 2025 12:57:01 +0800
Subject: [PATCH] refactor(trading): 优化交易策略算法和指标判断逻辑
---
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/TradingStrategy.java | 343 +++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 263 insertions(+), 80 deletions(-)
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/TradingStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/TradingStrategy.java
index 5c9a04d..0b8cae4 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/TradingStrategy.java
+++ b/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,60 @@
/**
* 检查是否为震荡市场
+ * @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);
}
@@ -368,38 +475,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 +525,10 @@
}
/**
- * 根据用户要求检查是否应该开多仓位
- * 条件:MA金叉 + MACD金叉 + KDJ金叉 + RSI中性 + 价格高于BOLL中轨 + 多周期确认 + 成交量验证
+ * 根据优化建议检查是否应该开多仓位
+ * 使用主次结合法:
+ * - 主信号(趋势):MA多头排列 + MACD金叉
+ * - 辅信号(入场点):价格回调至BOLL中轨附近获得支撑,且出现KDJ金叉或RSI从低位回升至50以上
* @param currentPrice 当前价格
* @param prices 价格数据
* @param volume 成交量列表
@@ -422,17 +541,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 +582,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 +663,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 +699,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);
}
/**
--
Gitblit v1.9.1