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<BigDecimal> closePrices) {
|
List<PriceData> 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<PriceData> macdData, List<BigDecimal> 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<BigDecimal> 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<PriceData> 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;
|
}
|
|
}
|