From 4884ebffeed775d63dbf7bb7d0ece8182f10c344 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Fri, 26 Dec 2025 18:19:46 +0800
Subject: [PATCH] fix(okxNewPrice): 解决交易订单为空时的空指针异常

---
 src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/BearishSignalDetector.java |  132 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 132 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/BearishSignalDetector.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/BearishSignalDetector.java
new file mode 100644
index 0000000..c537e84
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/BearishSignalDetector.java
@@ -0,0 +1,132 @@
+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;
+    }
+
+}
\ No newline at end of file

--
Gitblit v1.9.1