package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy; import java.math.BigDecimal; import java.util.List; /** * 示例用法 * // 计算MACD(获取包含起始索引的结果) * MACDCalculator.MACDResult macdResult = MACDCalculator.calculateMACD(closePrices, 12, 26, 9); * * // 检测做空信号 * boolean bearishSignal = BearishSignalDetector.isBearishSignalFormed(macdResult, closePrices); */ public class BearishSignalDetector { /** * 判断是否形成做空信号 * * @param macdResult 包含MACD数据和有效起始索引的结果对象 * @param closePrices 收盘价列表 * @return 是否形成信号 */ public static boolean isBearishSignalFormed(MACDResult macdResult, List closePrices) { List macdData = macdResult.getMacdData(); int startIdx = macdResult.getStartIndex(); // 校验数据长度(至少需要两个有效DIF点) if (macdData.size() < 2 || closePrices.size() < startIdx + macdData.size()) { return false; } int currentMacdIndex = macdData.size() - 1; int currentCloseIndex = startIdx + currentMacdIndex; // 1. 判断顶背离 boolean isTopDivergence = isTopDivergence(macdData, closePrices, currentMacdIndex, startIdx); // 2. 判断死叉 boolean isDeathCross = isDeathCross(macdData, currentMacdIndex); return isTopDivergence && isDeathCross; } /** * 判断顶背离(需确保earlierHigh在recentHigh之前) */ private static boolean isTopDivergence(List macdData, List closePrices, int currentMacdIndex, int startIdx) { // 计算对应closePrices的索引 int currentCloseIndex = startIdx + currentMacdIndex; if (currentCloseIndex < 10 || macdData.size() < 5) { return false; } // 寻找最近的价格高点(至少在当前点的前2根K线范围内) int recentHighCloseIndex = findRecentHighWithRetrace(closePrices, currentCloseIndex - 5, currentCloseIndex); if (recentHighCloseIndex == -1) { return false; } // 寻找更早的高点(确保在recentHigh之前) int earlierHighCloseIndex = findRecentHighWithRetrace(closePrices, startIdx, recentHighCloseIndex - 1); if (earlierHighCloseIndex == -1) { return false; } // 转换为macdData的索引 int recentHighMacdIndex = recentHighCloseIndex - startIdx; int earlierHighMacdIndex = earlierHighCloseIndex - startIdx; // 判断价格创新高但DIF走低 BigDecimal recentHighPrice = closePrices.get(recentHighCloseIndex); BigDecimal earlierHighPrice = closePrices.get(earlierHighCloseIndex); boolean isPriceHigher = recentHighPrice.compareTo(earlierHighPrice) > 0; BigDecimal recentDif = macdData.get(recentHighMacdIndex).getDif(); BigDecimal earlierDif = macdData.get(earlierHighMacdIndex).getDif(); boolean isDifLower = recentDif.compareTo(earlierDif) < 0; return isPriceHigher && isDifLower; } /** * 寻找有效的高点(高点后需有至少1根K线下跌) */ private static int findRecentHighWithRetrace(List prices, int startIndex, int endIndex) { if (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; } /** * 判断是否形成死叉(DIF下穿DEA) * * @param macdData MACD计算结果数据列表 * @param currentIndex 当前数据点索引 * @return 是否形成死叉 */ private static boolean isDeathCross(List macdData, int currentIndex) { if (currentIndex < 1) { return false; } PriceData current = macdData.get(currentIndex); PriceData previous = macdData.get(currentIndex - 1); // 前一期DIF >= DEA,当前期DIF < DEA return previous.getDif().compareTo(previous.getDea()) >= 0 && current.getDif().compareTo(current.getDea()) < 0; } }