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.
|
|
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(); }}
|