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/EMACalculator.java | 89 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 89 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/EMACalculator.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/EMACalculator.java
new file mode 100644
index 0000000..d1e0a1d
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/indicator/macdAndMatrategy/EMACalculator.java
@@ -0,0 +1,89 @@
+/**
+ * 指数移动平均线(EMA)计算器
+ * <p>
+ * EMA(Exponential Moving Average)是一种加权移动平均线,对近期价格赋予更高权重,
+ * 对远期价格赋予较低权重,能够更敏感地反映价格变化趋势。
+ * 本计算器提供了EMA的多种计算方式,支持使用SMA作为初始值或使用第一个价格作为初始值。
+ */
+package com.xcong.excoin.modules.okxNewPrice.indicator.macdAndMatrategy;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 指数移动平均线(EMA)计算器
+ *
+ * <p>计算公式:EMA(today) = Price(today) * k + EMA(yesterday) * (1 - k)</p>
+ * <p>其中:k = 2 / (period + 1),period为EMA的周期</p>
+ */
+public class EMACalculator {
+ /**
+ * 计算价格序列的指数移动平均线(EMA)
+ *
+ * @param prices 价格序列,使用BigDecimal确保计算精度
+ * @param period EMA计算周期
+ * @param initialSMA 是否使用SMA(简单移动平均线)作为初始值
+ * @return 计算得到的EMA序列,与输入价格序列一一对应
+ * @throws IllegalArgumentException 当输入参数无效时抛出异常
+ */
+ public static List<BigDecimal> calculateEMA(List<BigDecimal> prices, int period, boolean initialSMA) {
+ if (prices == null || prices.isEmpty() || period <= 0) {
+ throw new IllegalArgumentException("Invalid input parameters.");
+ }
+ if (initialSMA && prices.size() < period) {
+ throw new IllegalArgumentException("Prices list too short for initial SMA.");
+ }
+
+ // 计算权重因子k = 2 / (period + 1)
+ BigDecimal alpha = BigDecimal.valueOf(2.0).divide(BigDecimal.valueOf(period + 1), 10, RoundingMode.HALF_UP);
+ List<BigDecimal> ema = new ArrayList<>();
+
+ if (initialSMA) {
+ // 使用SMA作为初始EMA值(前period个价格的平均值)
+ BigDecimal sum = BigDecimal.ZERO;
+ for (int i = 0; i < period; i++) {
+ sum = sum.add(prices.get(i));
+ }
+ BigDecimal sma = sum.divide(BigDecimal.valueOf(period), 10, RoundingMode.HALF_UP);
+ ema.add(sma);
+
+ // 从第period+1个数据点开始计算后续EMA值
+ for (int i = period; i < prices.size(); i++) {
+ BigDecimal price = prices.get(i);
+ BigDecimal prevEMA = ema.get(ema.size() - 1);
+ // EMA计算公式:Price(today) * alpha + EMA(yesterday) * (1 - alpha)
+ BigDecimal emaToday = price.multiply(alpha)
+ .add(prevEMA.multiply(BigDecimal.ONE.subtract(alpha)))
+ .setScale(10, RoundingMode.HALF_UP);
+ ema.add(emaToday);
+ }
+ } else {
+ // 使用第一个价格作为初始EMA值,并从第二个数据点开始计算
+ ema.add(prices.get(0));
+ for (int i = 1; i < prices.size(); i++) {
+ BigDecimal price = prices.get(i);
+ BigDecimal prevEMA = ema.get(ema.size() - 1);
+ // EMA计算公式:Price(today) * alpha + EMA(yesterday) * (1 - alpha)
+ BigDecimal emaToday = price.multiply(alpha)
+ .add(prevEMA.multiply(BigDecimal.ONE.subtract(alpha)))
+ .setScale(10, RoundingMode.HALF_UP);
+ ema.add(emaToday);
+ }
+ }
+
+ return ema;
+ }
+
+ /**
+ * 计算价格序列的指数移动平均线(EMA),默认使用SMA作为初始值
+ *
+ * @param prices 价格序列
+ * @param period EMA计算周期
+ * @return 计算得到的EMA序列
+ */
+ public static List<BigDecimal> calculateEMA(List<BigDecimal> prices, int period) {
+ return calculateEMA(prices, period, true);
+ }
+}
\ No newline at end of file
--
Gitblit v1.9.1