From 54c41b98114c82feb091b83bcaaaae839abb65db Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Sun, 04 Jan 2026 13:15:09 +0800
Subject: [PATCH] feat(MacdMaStrategy): 添加MACD计算结果日志输出

---
 src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/IndicatorBase.java |  109 ++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 88 insertions(+), 21 deletions(-)

diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/IndicatorBase.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/IndicatorBase.java
index 6872bfd..a3b80b7 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/IndicatorBase.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/IndicatorBase.java
@@ -6,15 +6,31 @@
 import java.util.List;
 
 /**
- * 技术指标基础类,提供通用计算方法
+ * Technical indicators base class, provides common calculation methods
+ * 
+ * Indicator combination strategy:
+ * 1. Trend judgment (MA/AdvancedMA/MACD): Determine the overall trend direction of prices
+ * 2. Momentum confirmation (RSI/KDJ): Confirm the strength and sustainability of the current trend
+ * 3. Volatility reference (BOLL): Determine reasonable price volatility range and breakthrough timing
+ * 
+ * Long/Short direction selection logic:
+ * - Long signal: MA bullish arrangement + MACD golden cross + RSI(30-70) + BOLL price between upper and middle band
+ * - Short signal: MA bearish arrangement + MACD death cross + RSI(30-70) + BOLL price between lower and middle band
+ * - Consolidation signal: AdvancedMA three-line convergence + RSI(40-60) + BOLL bandwidth narrowing
+ * 
+ * Open and close position strategies:
+ * - Open long: MA golden cross + MACD golden cross + KDJ golden cross + RSI(30-70) + price breaks through BOLL middle band
+ * - Open short: MA death cross + MACD death cross + KDJ death cross + RSI(30-70) + price breaks below BOLL middle band
+ * - Close long: MA death cross + MACD death cross + RSI overbought(>70) + price breaks below BOLL middle band
+ * - Close short: MA golden cross + MACD golden cross + RSI oversold(<30) + price breaks through BOLL middle band
  */
 public abstract class IndicatorBase {
 
     /**
-     * 计算移动平均值
-     * @param prices 价格列表
-     * @param period 周期
-     * @return 移动平均值
+     * Calculate moving average
+     * @param prices Price list
+     * @param period Period
+     * @return Moving average value
      */
     protected BigDecimal calculateMA(List<BigDecimal> prices, int period) {
         if (prices == null || prices.size() < period) {
@@ -28,11 +44,11 @@
     }
 
     /**
-     * 计算指数移动平均值
-     * @param prices 价格列表
-     * @param period 周期
-     * @param prevEMA 前一个EMA值
-     * @return 指数移动平均值
+     * Calculate exponential moving average
+     * @param prices Price list
+     * @param period Period
+     * @param prevEMA Previous EMA value
+     * @return Exponential moving average value
      */
     protected BigDecimal calculateEMA(List<BigDecimal> prices, int period, BigDecimal prevEMA) {
         if (prices == null || prices.size() == 0) {
@@ -47,10 +63,10 @@
     }
 
     /**
-     * 计算标准差
-     * @param prices 价格列表
-     * @param period 周期
-     * @return 标准差
+     * Calculate standard deviation
+     * @param prices Price list
+     * @param period Period
+     * @return Standard deviation
      */
     protected BigDecimal calculateStdDev(List<BigDecimal> prices, int period) {
         if (prices == null || prices.size() < period) {
@@ -67,9 +83,9 @@
     }
 
     /**
-     * 计算平方根(简化实现)
-     * @param value 输入值
-     * @return 平方根
+     * Calculate square root (simplified implementation)
+     * @param value Input value
+     * @return Square root
      */
     protected BigDecimal sqrt(BigDecimal value) {
         if (value.compareTo(BigDecimal.ZERO) < 0) {
@@ -79,10 +95,10 @@
     }
 
     /**
-     * 获取最近的价格数据
-     * @param prices 所有价格数据
-     * @param period 周期
-     * @return 最近period个价格数据
+     * Get recent price data
+     * @param prices All price data
+     * @param period Period
+     * @return Recent period price data
      */
     protected List<BigDecimal> getRecentPrices(List<BigDecimal> prices, int period) {
         if (prices == null || prices.size() == 0) {
@@ -91,4 +107,55 @@
         int startIndex = Math.max(0, prices.size() - period);
         return prices.subList(startIndex, prices.size());
     }
+
+    /**
+     * Calculate ATR (Average True Range)
+     * @param high High price list
+     * @param low Low price list
+     * @param close Close price list
+     * @param period Period
+     * @return ATR value
+     */
+    protected BigDecimal calculateATR(List<BigDecimal> high, List<BigDecimal> low, List<BigDecimal> close, int period) {
+        if (high == null || low == null || close == null || 
+            high.size() < period || low.size() < period || close.size() < period) {
+            return BigDecimal.ZERO;
+        }
+
+        List<BigDecimal> trList = new ArrayList<>();
+        for (int i = 1; i < high.size(); i++) {
+            BigDecimal trueRange = calculateTrueRange(high.get(i), low.get(i), close.get(i - 1));
+            trList.add(trueRange);
+        }
+
+        // Use simple moving average to calculate ATR
+        return calculateMA(trList, Math.min(period, trList.size()));
+    }
+
+    /**
+     * Calculate True Range
+     * @param high Current high price
+     * @param low Current low price
+     * @param prevClose Previous close price
+     * @return True range
+     */
+    protected BigDecimal calculateTrueRange(BigDecimal high, BigDecimal low, BigDecimal prevClose) {
+        BigDecimal h1 = high.subtract(low);
+        BigDecimal h2 = high.subtract(prevClose).abs();
+        BigDecimal h3 = low.subtract(prevClose).abs();
+        return h1.max(h2).max(h3);
+    }
+
+    /**
+     * Calculate normalized volatility (based on ATR)
+     * @param close Close price list
+     * @param atr ATR value
+     * @return Normalized volatility (percentage)
+     */
+    protected BigDecimal normalizeVolatility(List<BigDecimal> close, BigDecimal atr) {
+        if (close == null || close.size() == 0 || atr.compareTo(BigDecimal.ZERO) == 0) {
+            return BigDecimal.ZERO;
+        }
+        return atr.divide(close.get(close.size() - 1), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
+    }
 }

--
Gitblit v1.9.1