From 36c1ee6acf1e2185924ca3fc817c8641d44c4d39 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Tue, 06 Jan 2026 14:29:24 +0800
Subject: [PATCH] fix(strategy): 修复MACD策略日志输出和网格止损逻辑
---
src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java | 90 ++++++++++++++++++++++++++------------------
1 files changed, 53 insertions(+), 37 deletions(-)
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java
index 8ce6ba2..f5ebaf3 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/MacdMaStrategy.java
@@ -1,22 +1,29 @@
/**
* MACD和MA组合交易策略实现类
- * 基于15分钟K线数据生成交易信号并确定持仓方向
+ * 基于多时间粒度K线数据生成交易信号并确定持仓方向
*
* 该策略综合考虑了EMA指标、MACD指标、价格突破信号和波动率因素,
* 形成了一套完整的开仓、平仓和持仓管理机制。
+ * 支持1分钟(K线)和日线(K线)级别的数据输入,数据顺序要求从新到旧排列。
*/
package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
* MACD和MA组合交易策略实现
* <p>
* 该策略利用EMA交叉、MACD指标、价格突破信号和波动率过滤,
- * 为15分钟K线级别交易提供综合决策支持。
+ * 为多时间粒度K线级别交易提供综合决策支持。
+ * <p>
+ * 数据输入要求:
+ * - historicalPrices1M:1分钟K线收盘价列表,顺序从新到旧
+ * - historicalPrices1D:日线K线收盘价列表,顺序从新到旧
*/
@Slf4j
public class MacdMaStrategy {
@@ -82,7 +89,7 @@
* 止损比例=1%, 止盈比例=2%
*/
public MacdMaStrategy() {
- this(5, 10, 9, 20, new BigDecimal("0.01"), new BigDecimal("0.02"));
+ this(12, 26, 9, 20, new BigDecimal("0.01"), new BigDecimal("0.02"));
}
/**
@@ -127,8 +134,8 @@
/**
* 分析历史价格数据并生成交易指令
*
- * @param historicalPrices 历史价格序列
- * @param historical1DayPrices 日线历史价格序列
+ * @param historicalPrices 历史价格序列(1分钟K线收盘价),顺序从新到旧
+ * @param historical1DayPrices 日线历史价格序列,顺序从新到旧
* @param operation 操作类型(open/close)
* @return 交易指令(包含side和posSide),如果没有交易信号则返回null
*/
@@ -148,9 +155,9 @@
/**
* 分析最新价格数据并生成开仓信号
*
- * @param closePrices 收盘价序列
- * @param close1DPrices 日线收盘价序列
- * @return 生成的交易信号(LONG、SHORT或NONE)
+ * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
+ * @param close1DPrices 日线K线收盘价序列,顺序从新到旧
+ * @return 生成的交易信号(LONG_BUY、SHORT_SELL或NONE)
*/
public PositionType analyzeOpen(List<BigDecimal> closePrices, List<BigDecimal> close1DPrices) {
// 数据检查:确保有足够的数据点进行计算(需要足够数据计算200日EMA)
@@ -162,17 +169,17 @@
// 计算MACD指标
MACDResult macdResult = MACDCalculator.calculateMACD(
closePrices, shortPeriod, longPeriod, signalPeriod);
- log.info("MACD计算结果:{}", macdResult.getMacdData().get(macdResult.getMacdData().size() - 1));
+ log.info("MACD计算结果:{}", macdResult.getMacdData().get(0));
// 多头开仓条件检查
if (isLongEntryCondition(macdResult, closePrices, close1DPrices)) {
- log.info("多头开仓信号,价格:{}", closePrices.get(closePrices.size() - 1));
+ log.info("多头开仓信号,价格:{}", closePrices.get(0));
return PositionType.LONG_BUY;
}
// 空头开仓条件检查
if (isShortEntryCondition(macdResult, closePrices, close1DPrices)) {
- log.info("空头开仓信号,价格:{}", closePrices.get(closePrices.size() - 1));
+ log.info("空头开仓信号,价格:{}", closePrices.get(0));
return PositionType.SHORT_SELL;
}
@@ -183,8 +190,8 @@
/**
* 分析最新价格数据并生成平仓信号
*
- * @param closePrices 收盘价序列
- * @param close1DPrices 日线收盘价序列
+ * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
+ * @param close1DPrices 日线K线收盘价序列,顺序从新到旧
* @return 生成的交易信号(LONG_SELL、SHORT_BUY或NONE)
*/
public PositionType analyzeClose(List<BigDecimal> closePrices, List<BigDecimal> close1DPrices) {
@@ -199,7 +206,7 @@
closePrices, shortPeriod, longPeriod, signalPeriod);
// 最新收盘价
- BigDecimal latestPrice = closePrices.get(closePrices.size() - 1);
+ BigDecimal latestPrice = closePrices.get(0);
if (isLongExitCondition(macdResult, latestPrice)) {
log.info("多头平仓信号,价格:{}", latestPrice);
@@ -253,15 +260,19 @@
* 多头开仓条件检查
*
* @param macdResult MACD计算结果
- * @param closePrices 收盘价序列
- * @param close1DPrices 日线收盘价序列
+ * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
+ * @param close1DPrices 日线K线收盘价序列,顺序从新到旧
* @return 是否满足多头开仓条件
*/
private boolean isLongEntryCondition(MACDResult macdResult, List<BigDecimal> closePrices, List<BigDecimal> close1DPrices) {
// 1. 计算200日EMA(趋势过滤)
- List<BigDecimal> trendEma = EMACalculator.calculateEMA(close1DPrices, trendPeriod, true);
+ // 复制并反转日线数据,确保从旧到新计算EMA
+ List<BigDecimal> reversed1DPrices = new ArrayList<>(close1DPrices);
+ Collections.reverse(reversed1DPrices);
+ List<BigDecimal> trendEma = EMACalculator.calculateEMA(reversed1DPrices, trendPeriod, true);
BigDecimal latestTrendEma = trendEma.get(trendEma.size() - 1);
- BigDecimal latestPrice = closePrices.get(closePrices.size() - 1);
+ BigDecimal latestPrice = closePrices.get(0);
+ log.info( "200日EMA:{}, 最新价格:{}", latestTrendEma, latestPrice);
// 2. 价格必须位于200日EMA上方(多头趋势确认)
boolean isAboveTrend = latestPrice.compareTo(latestTrendEma) > 0;
@@ -286,15 +297,20 @@
* 空头开仓条件检查
*
* @param macdResult MACD计算结果
- * @param closePrices 收盘价序列
- * @param close1DPrices 日线收盘价序列
+ * @param closePrices 1分钟K线收盘价序列,顺序从新到旧
+ * @param close1DPrices 日线K线收盘价序列,顺序从新到旧
* @return 是否满足空头开仓条件
*/
private boolean isShortEntryCondition(MACDResult macdResult, List<BigDecimal> closePrices, List<BigDecimal> close1DPrices) {
// 1. 计算200日EMA(趋势过滤)
- List<BigDecimal> trendEma = EMACalculator.calculateEMA(close1DPrices, trendPeriod, true);
+ // 复制并反转日线数据,确保从旧到新计算EMA
+ List<BigDecimal> reversed1DPrices = new ArrayList<>(close1DPrices);
+ Collections.reverse(reversed1DPrices);
+ List<BigDecimal> trendEma = EMACalculator.calculateEMA(reversed1DPrices, trendPeriod, true);
BigDecimal latestTrendEma = trendEma.get(trendEma.size() - 1);
- BigDecimal latestPrice = closePrices.get(closePrices.size() - 1);
+ BigDecimal latestPrice = closePrices.get(0);
+
+ log.info( "200日EMA:{}, 最新价格:{}", latestTrendEma, latestPrice);
// 2. 价格必须位于200日EMA下方(空头趋势确认)
boolean isBelowTrend = latestPrice.compareTo(latestTrendEma) < 0;
@@ -328,8 +344,8 @@
// 多头平仓条件:MACD柱状线动量减弱(由正转弱)
List<PriceData> macdData = macdResult.getMacdData();
if (macdData.size() >= 2) {
- PriceData latest = macdData.get(macdData.size() - 1);
- PriceData previous = macdData.get(macdData.size() - 2);
+ PriceData latest = macdData.get(0); // 最新数据
+ PriceData previous = macdData.get(1); // 前一个数据
// 柱状线由正转弱:前一根为正,当前绝对值减小
boolean momentumWeakening = previous.getMacdHist().compareTo(BigDecimal.ZERO) >= 0 &&
@@ -351,8 +367,8 @@
// 空头平仓条件:MACD柱状线动量减弱(由负转弱)
List<PriceData> macdData = macdResult.getMacdData();
if (macdData.size() >= 2) {
- PriceData latest = macdData.get(macdData.size() - 1);
- PriceData previous = macdData.get(macdData.size() - 2);
+ PriceData latest = macdData.get(0); // 最新数据
+ PriceData previous = macdData.get(1); // 前一个数据
// 柱状线由负转弱:前一根为负,当前绝对值减小
boolean momentumWeakening = previous.getMacdHist().compareTo(BigDecimal.ZERO) <= 0 &&
@@ -380,11 +396,11 @@
return false;
}
- PriceData latest = macdData.get(macdData.size() - 1);
- PriceData previous = macdData.get(macdData.size() - 2);
+ PriceData latest = macdData.get(0);
+ PriceData previous = macdData.get(1);
// 金叉判断:DIF从下往上穿过DEA
- return previous.getDif().compareTo(previous.getDea()) <= 0 &&
+ return previous.getDif().compareTo(previous.getDea()) < 0 &&
latest.getDif().compareTo(latest.getDea()) > 0;
}
@@ -402,11 +418,11 @@
return false;
}
- PriceData latest = macdData.get(macdData.size() - 1);
- PriceData previous = macdData.get(macdData.size() - 2);
+ PriceData latest = macdData.get(0);
+ PriceData previous = macdData.get(1);
// 死叉判断:DIF从上往下穿过DEA
- return previous.getDif().compareTo(previous.getDea()) >= 0 &&
+ return previous.getDif().compareTo(previous.getDea()) > 0 &&
latest.getDif().compareTo(latest.getDea()) < 0;
}
@@ -424,8 +440,8 @@
return false;
}
- PriceData latest = macdData.get(macdData.size() - 1);
- PriceData previous = macdData.get(macdData.size() - 2);
+ PriceData latest = macdData.get(0); // 最新数据
+ PriceData previous = macdData.get(1); // 前一个数据
// 柱状线由负转正:前一根为负,当前为正
return previous.getMacdHist().compareTo(BigDecimal.ZERO) <= 0 &&
@@ -446,12 +462,12 @@
return false;
}
- PriceData latest = macdData.get(macdData.size() - 1);
- PriceData previous = macdData.get(macdData.size() - 2);
+ PriceData latest = macdData.get(0); // 最新数据
+ PriceData previous = macdData.get(1); // 前一个数据
// 柱状线由正转负:前一根为正,当前为负
return previous.getMacdHist().compareTo(BigDecimal.ZERO) >= 0 &&
latest.getMacdHist().compareTo(BigDecimal.ZERO) < 0;
}
-}
+}
\ No newline at end of file
--
Gitblit v1.9.1