You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.9 KiB

package com.deepchart.utils;
import com.deepchart.entity.KDJData;
import com.deepchart.entity.StockDailyData;
import java.util.*;
/**
* KD指标分析工具类
*/
public class KDUtil {
private static final int N = 9; // 默认周期长度
private static final double SMOOTH_K = 1.0 / 3; // K 平滑系数
private static final double SMOOTH_D = 1.0 / 3; // D 平滑系数
private static List<KDJData> calculateKD(List<StockDailyData> dataList) {
if (dataList == null || dataList.size() < N) {
throw new IllegalArgumentException("数据不足,至少需要" + N + "条记录");
}
List<KDJData> kdList = new ArrayList<>();
Deque<Double> highs = new ArrayDeque<>(N);
Deque<Double> lows = new ArrayDeque<>(N);
Double prevK = null;
Double prevD = null;
for (int i = 0; i < dataList.size(); i++) {
StockDailyData data = dataList.get(i);
highs.offerLast(data.getHighPrice());
lows.offerLast(data.getLowPrice());
if (highs.size() > N) {
highs.pollFirst();
lows.pollFirst();
}
if (i >= N - 1) {
double hhv = Collections.max(highs);
double llv = Collections.min(lows);
double rsv = ((data.getClosePrice() - llv) / (hhv - llv)) * 100;
double kValue = (prevK == null ? rsv : prevK * (1 - SMOOTH_K) + rsv * SMOOTH_K);
double dValue = (prevD == null ? kValue : prevD * (1 - SMOOTH_D) + kValue * SMOOTH_D);
kdList.add(new KDJData(data.getDate(), rsv, kValue, dValue, 0));
prevK = kValue;
prevD = dValue;
} else {
kdList.add(new KDJData(data.getDate(), 0, 0, 0, 0)); // 占位符
}
}
return kdList;
}
public static String generateReport(List<StockDailyData> stockDataList) {
List<KDJData> kdList = calculateKD(stockDataList);
StringBuilder report = new StringBuilder();
report.append("📈 股票KD指标分析报告\n");
report.append("=======================\n");
if (kdList.isEmpty()) {
report.append("❌ 数据不足,无法生成分析。\n");
return report.toString();
}
KDJData latest = kdList.get(kdList.size() - 1);
KDJData previous = kdList.size() >= 2 ? kdList.get(kdList.size() - 2) : null;
double k = latest.getK();
double d = latest.getD();
// 判断超买或超卖
if (k > 80 && d > 80) {
report.append("🔴 当前处于【超买】状态,注意回调风险。\n");
} else if (k < 20 && d < 20) {
report.append("🟢 当前处于【超卖】状态,关注反弹机会。\n");
} else {
report.append("🟡 当前处于中性区域,暂无明显买卖信号。\n");
}
// 判断金叉/死叉
if (previous != null) {
boolean isGoldenCross = previous.getK() <= previous.getD() && k > d;
boolean isDeathCross = previous.getK() >= previous.getD() && k < d;
if (isGoldenCross && d < 30) {
report.append("✨ 出现金叉(K线上穿D线),特别是在低位,是潜在买入信号。\n");
} else if (isDeathCross && d > 70) {
report.append("⚠️ 出现死叉(K线下穿D线),尤其是在高位,建议谨慎卖出。\n");
}
}
// 多空趋势判断
if (k > 50 && d > 50 && k > d) {
report.append("⬆️ 当前为多头趋势,可考虑持股观望。\n");
} else if (k < 50 && d < 50 && k < d) {
report.append("⬇️ 当前为空头趋势,宜控制仓位。\n");
} else {
report.append("🔄 当前为震荡行情,短线操作更适宜。\n");
}
return report.toString();
}
}