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 bullishSignal = BullishSignalDetector.isBullishSignalFormed(macdResult, closePrices); */ public class BullishSignalDetector { public static boolean isBullishSignalFormed(MACDResult macdResult, List closePrices) { List macdData = macdResult.getMacdData(); int startIdx = macdResult.getStartIndex(); // 校验MACD数据和收盘价长度合法性 if (closePrices.size() < 34 || macdData.size() < 2 || startIdx + macdData.size() > closePrices.size()) { return false; } int currentMacdIndex = macdData.size() - 1; int currentCloseIndex = startIdx + currentMacdIndex; // 1. 金叉判断 boolean isGoldenCross = isGoldenCross(macdData, currentMacdIndex); // 2. MACD柱动量增强 boolean isMacdHistExpanding = isMacdHistExpanding(macdData, currentMacdIndex); // 3. 价格突破前15周期高点 boolean isPriceBreakout = isPriceBreakout(closePrices, currentCloseIndex, 15); return isGoldenCross && isMacdHistExpanding && isPriceBreakout; } private static boolean isGoldenCross(List macdData, int currentMacdIndex) { if (currentMacdIndex < 1 || currentMacdIndex >= macdData.size()) { return false; } PriceData current = macdData.get(currentMacdIndex); PriceData previous = macdData.get(currentMacdIndex - 1); return previous.getDif().compareTo(previous.getDea()) <= 0 && current.getDif().compareTo(current.getDea()) > 0; } private static boolean isMacdHistExpanding(List macdData, int currentMacdIndex) { if (currentMacdIndex < 2 || currentMacdIndex >= macdData.size()) { return false; } BigDecimal currentHist = macdData.get(currentMacdIndex).getMacdHist(); BigDecimal prevHist = macdData.get(currentMacdIndex - 1).getMacdHist(); BigDecimal prevPrevHist = macdData.get(currentMacdIndex - 2).getMacdHist(); boolean isPositive = currentHist.compareTo(BigDecimal.ZERO) > 0; boolean isExpanding = prevPrevHist.compareTo(prevHist) <= 0 && prevHist.compareTo(currentHist) < 0; return isPositive && isExpanding; } private static boolean isPriceBreakout(List closePrices, int currentCloseIndex, int period) { if (currentCloseIndex < period || period <= 0) { return false; } int startSearchIdx = Math.max(currentCloseIndex - period, 0); BigDecimal maxPreviousPrice = closePrices.get(startSearchIdx); for (int i = startSearchIdx + 1; i < currentCloseIndex; i++) { if (i >= closePrices.size()) { break; } BigDecimal price = closePrices.get(i); if (price.compareTo(maxPreviousPrice) > 0) { maxPreviousPrice = price; } } return closePrices.get(currentCloseIndex).compareTo(maxPreviousPrice) > 0; } }