package com.xcong.excoin.modules.okxNewPrice.indicator.strategy; import com.xcong.excoin.modules.okxNewPrice.indicator.AdvancedMA; import com.xcong.excoin.modules.okxNewPrice.indicator.BOLL; import com.xcong.excoin.modules.okxNewPrice.indicator.KDJ; import com.xcong.excoin.modules.okxNewPrice.indicator.MACD; import com.xcong.excoin.modules.okxNewPrice.indicator.RSI; import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.CoinEnums; import com.xcong.excoin.modules.okxNewPrice.okxWs.enums.OrderParamEnums; import com.xcong.excoin.modules.okxNewPrice.okxWs.param.TradeRequestParam; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; /** * 核心技术指标策略实现类 * 整合三重EMA交叉系统、波动率自适应布林带、MACD能量柱分级策略等核心指标 */ @Slf4j public class CoreTechnicalStrategy extends AbstractTechnicalIndicatorStrategy { private static final int MACD_HISTOGRAM_PERIOD = 5; // MACD能量柱计算周期 private static final BigDecimal VOLUME_MULTIPLIER = new BigDecimal(3); // 成交量放大倍数 private static final BigDecimal GLUE_THRESHOLD = new BigDecimal(2); // 三线粘合度阈值(%) private final AdvancedMA advancedMA; private final BOLL boll; private final MACD macd; private final RSI rsi; private final KDJ kdj; private List macdHistogramHistory; // MACD能量柱历史 private BigDecimal prevEma9; private BigDecimal prevEma21; private BigDecimal prevEma55; private BigDecimal prevDif; private BigDecimal prevDea; private BigDecimal prevK; private BigDecimal prevD; private BigDecimal prevJ; public CoreTechnicalStrategy() { super(); this.strategyName = "核心技术指标策略"; this.advancedMA = new AdvancedMA(); this.boll = new BOLL(); this.macd = new MACD(); this.rsi = new RSI(); this.kdj = new KDJ(); this.macdHistogramHistory = new ArrayList<>(); this.prevEma9 = BigDecimal.ZERO; this.prevEma21 = BigDecimal.ZERO; this.prevEma55 = BigDecimal.ZERO; this.prevDif = BigDecimal.ZERO; this.prevDea = BigDecimal.ZERO; this.prevK = new BigDecimal(50); this.prevD = new BigDecimal(50); this.prevJ = new BigDecimal(50); } @Override public void initialize() { super.initialize(); macdHistogramHistory.clear(); // 初始化技术指标 advancedMA.setPrevEma9(null); advancedMA.setPrevEma21(null); advancedMA.setPrevEma55(null); macd.setDif(BigDecimal.ZERO); macd.setDea(BigDecimal.ZERO); macd.setMacdBar(BigDecimal.ZERO); macd.setPrevFastEMA(null); macd.setPrevSlowEMA(null); macd.setPrevDea(null); rsi.setRsi(BigDecimal.ZERO); rsi.setPrevAvgGain(BigDecimal.ZERO); rsi.setPrevAvgLoss(BigDecimal.ZERO); kdj.setK(new BigDecimal(50)); kdj.setD(new BigDecimal(50)); kdj.setJ(new BigDecimal(50)); kdj.setPrevK(new BigDecimal(50)); kdj.setPrevD(new BigDecimal(50)); boll.setMid(BigDecimal.ZERO); boll.setUpper(BigDecimal.ZERO); boll.setLower(BigDecimal.ZERO); prevEma9 = BigDecimal.ZERO; prevEma21 = BigDecimal.ZERO; prevEma55 = BigDecimal.ZERO; prevDif = BigDecimal.ZERO; prevDea = BigDecimal.ZERO; prevK = new BigDecimal(50); prevD = new BigDecimal(50); prevJ = new BigDecimal(50); log.info("核心技术指标策略初始化完成"); } @Override public TradeRequestParam getSignal(String accountName, String markPx, String posSide) { if (!initialized || priceHistory.isEmpty()) { log.warn("策略未初始化或价格历史为空"); return createTradeRequestParam(accountName, markPx, posSide, TradeSignal.NO_SIGNAL); } try { BigDecimal currentPrice = new BigDecimal(markPx); // 计算所有技术指标 calculateIndicators(currentPrice); // 生成交易信号 TradeRequestParam param = analyzeSignal(accountName, markPx, posSide, currentPrice); // 更新历史指标值 updateHistoricalIndicatorValues(); return param; } catch (Exception e) { log.error("计算交易信号时发生异常", e); return createTradeRequestParam(accountName, markPx, posSide, TradeSignal.NO_SIGNAL); } } /** * 计算所有技术指标 */ private void calculateIndicators(BigDecimal currentPrice) { // 计算三重EMA交叉系统 advancedMA.calculateTripleEMA(priceHistory); // 计算MACD macd.calculate(priceHistory); // 维护MACD能量柱历史 updateMacdHistogramHistory(); // 计算RSI rsi.calculate(priceHistory); // 计算KDJ kdj.calculate(priceHistory); // 计算波动率自适应布林带 calculateAdaptiveBollingerBands(); } /** * 计算波动率自适应布林带 */ private void calculateAdaptiveBollingerBands() { // 动态调整布林带的标准差倍数 BigDecimal atr = calculateATR(priceHistory, 14); // 根据ATR动态计算标准差倍数 BigDecimal stdDevMultiplier; if (atr.compareTo(new BigDecimal(0.5)) < 0) { stdDevMultiplier = new BigDecimal(2); } else if (atr.compareTo(new BigDecimal(1)) < 0) { stdDevMultiplier = new BigDecimal(2.5); } else { stdDevMultiplier = new BigDecimal(3); } boll.setK(stdDevMultiplier); boll.calculate(priceHistory); log.debug("ATR: {}, 布林带标准差倍数: {}", atr, stdDevMultiplier); } /** * 计算ATR (平均真实范围) */ private BigDecimal calculateATR(List prices, int period) { if (prices == null || prices.size() < period + 1) { return new BigDecimal(0.5); // 默认值 } List trList = new ArrayList<>(); for (int i = 1; i < prices.size(); i++) { BigDecimal high = prices.get(i); BigDecimal low = prices.get(i); BigDecimal prevClose = prices.get(i - 1); BigDecimal tr1 = high.subtract(low); BigDecimal tr2 = high.subtract(prevClose).abs(); BigDecimal tr3 = prevClose.subtract(low).abs(); trList.add(tr1.max(tr2).max(tr3)); } // 计算ATR BigDecimal sum = trList.stream().reduce(BigDecimal.ZERO, BigDecimal::add); return sum.divide(new BigDecimal(trList.size()), 8, RoundingMode.HALF_UP); } /** * 更新MACD能量柱历史 */ private void updateMacdHistogramHistory() { macdHistogramHistory.add(macd.getMacdBar()); // 限制历史记录数量 if (macdHistogramHistory.size() > MACD_HISTOGRAM_PERIOD) { macdHistogramHistory = macdHistogramHistory.subList( macdHistogramHistory.size() - MACD_HISTOGRAM_PERIOD, macdHistogramHistory.size()); } } /** * 计算MACD能量柱面积指标(累计过去5根柱体积分) */ private BigDecimal calculateMacdHistogramArea() { return macdHistogramHistory.stream() .reduce(BigDecimal.ZERO, BigDecimal::add) .abs(); // 使用绝对值表示面积 } /** * 分析技术指标生成交易信号 */ private TradeRequestParam analyzeSignal(String accountName, String markPx, String posSide, BigDecimal currentPrice) { TradeRequestParam param = createTradeRequestParam(accountName, markPx, posSide, TradeSignal.NO_SIGNAL); param.setTradeType(OrderParamEnums.TRADE_YES.getValue()); param.setInstId(CoinEnums.HE_YUE.getCode()); param.setTdMode(CoinEnums.CROSS.getCode()); param.setOrdType(CoinEnums.ORDTYPE_MARKET.getCode()); // 检查冷静期 String outStr = getAccountConfig(accountName, CoinEnums.OUT.name()); if (OrderParamEnums.OUT_YES.getValue().equals(outStr)) { log.error("冷静中,不允许下单......"); param.setTradeType(OrderParamEnums.TRADE_NO.getValue()); return param; } // 检查震荡行情 if (advancedMA.isUpAndDown()) { log.info("处于震荡行情(三线粘合度<{}%),暂停交易", GLUE_THRESHOLD); param.setTradeType(OrderParamEnums.TRADE_NO.getValue()); return param; } TradeSignal signal = TradeSignal.NO_SIGNAL; // 分析多空信号 signal = analyzeCoreSignal(currentPrice, posSide); log.info("账户: {}, 价格: {}, 方向: {}, 生成信号: {}", accountName, markPx, posSide, signal.getName()); // 设置信号参数 setSignalParameters(param, signal); return param; } /** * 分析核心技术指标信号 */ private TradeSignal analyzeCoreSignal(BigDecimal currentPrice, String posSide) { // 计算MACD能量柱面积 BigDecimal macdArea = calculateMacdHistogramArea(); BigDecimal prevMacdArea = calculateMacdHistogramAreaPrevious(); // 多头入场条件:当前柱体>0且面积增速>前周期20% if (isBullishEntry(macdArea, prevMacdArea)) { // 如果当前没有仓位或仓位为空头,则开多 if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) { return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_LONG : TradeSignal.CLOSE_SHORT; } // 如果当前已经是多头仓位,则保持观望 return TradeSignal.NO_SIGNAL; } // 空头入场条件:当前柱体<0且面积增速>前周期20% if (isBearishEntry(macdArea, prevMacdArea)) { // 如果当前没有仓位或仓位为多头,则开空 if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) { return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_SHORT : TradeSignal.CLOSE_LONG; } // 如果当前已经是空头仓位,则保持观望 return TradeSignal.NO_SIGNAL; } // 突破上轨+成交量放大3倍=做空信号 if (isBollingerUpperBreak(currentPrice) && isVolumeIncreased()) { // 如果当前没有仓位或仓位为多头,则开空 if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) { return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_SHORT : TradeSignal.CLOSE_LONG; } // 如果当前已经是空头仓位,则保持观望 return TradeSignal.NO_SIGNAL; } // 触及下轨+期货资金费率转正=做多信号 if (isBollingerLowerTouch(currentPrice) && isFundingRatePositive()) { // 如果当前没有仓位或仓位为空头,则开多 if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) { return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_LONG : TradeSignal.CLOSE_SHORT; } // 如果当前已经是多头仓位,则保持观望 return TradeSignal.NO_SIGNAL; } // 空头反转:柱体顶背离+RSI>70区域死叉 if (isBearishReversal(currentPrice)) { // 如果当前没有仓位或仓位为多头,则开空或平多 if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_LONG.getCode().equals(posSide)) { return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_SHORT : TradeSignal.CLOSE_LONG; } // 如果当前已经是空头仓位,则保持观望 return TradeSignal.NO_SIGNAL; } // 多头反转:柱体底背离+RSI<30区域金叉 if (isBullishReversal(currentPrice)) { // 如果当前没有仓位或仓位为空头,则开多或平空 if (posSide == null || posSide.isEmpty() || CoinEnums.POSSIDE_SHORT.getCode().equals(posSide)) { return posSide == null || posSide.isEmpty() ? TradeSignal.OPEN_LONG : TradeSignal.CLOSE_SHORT; } // 如果当前已经是多头仓位,则保持观望 return TradeSignal.NO_SIGNAL; } return TradeSignal.NO_SIGNAL; } /** * 多头入场条件判断 */ private boolean isBullishEntry(BigDecimal currentArea, BigDecimal prevArea) { // 当前柱体>0 boolean currentBarPositive = macd.getMacdBar().compareTo(BigDecimal.ZERO) > 0; // 面积增速>前周期20% boolean areaGrowth = prevArea != null && prevArea.compareTo(BigDecimal.ZERO) > 0 && currentArea.divide(prevArea, 8, RoundingMode.HALF_UP) .compareTo(new BigDecimal(1.2)) > 0; // 三重EMA多头排列 boolean emaBullish = advancedMA.isBullish(); return currentBarPositive && areaGrowth && emaBullish; } /** * 空头入场条件判断 */ private boolean isBearishEntry(BigDecimal currentArea, BigDecimal prevArea) { // 当前柱体<0 boolean currentBarNegative = macd.getMacdBar().compareTo(BigDecimal.ZERO) < 0; // 面积增速>前周期20% boolean areaGrowth = prevArea != null && prevArea.compareTo(BigDecimal.ZERO) > 0 && currentArea.divide(prevArea, 8, RoundingMode.HALF_UP) .compareTo(new BigDecimal(1.2)) > 0; // 三重EMA空头排列 boolean emaBearish = advancedMA.isBearish(); return currentBarNegative && areaGrowth && emaBearish; } /** * 突破上轨判断 */ private boolean isBollingerUpperBreak(BigDecimal currentPrice) { return currentPrice.compareTo(boll.getUpper()) > 0; } /** * 触及下轨判断 */ private boolean isBollingerLowerTouch(BigDecimal currentPrice) { return currentPrice.compareTo(boll.getLower()) < 0; } /** * 成交量放大判断(模拟) */ private boolean isVolumeIncreased() { // 这里使用价格波动率模拟成交量 return calculateVolatility(priceHistory, 5) .compareTo(calculateVolatility(priceHistory, 20).multiply(VOLUME_MULTIPLIER)) > 0; } /** * 期货资金费率转正判断(模拟) */ private boolean isFundingRatePositive() { // 这里使用MACD柱状图模拟资金费率 return macd.getMacdBar().compareTo(BigDecimal.ZERO) > 0; } /** * 计算价格波动率 */ private BigDecimal calculateVolatility(List prices, int period) { if (prices.size() < period) { return BigDecimal.ZERO; } List returns = new ArrayList<>(); for (int i = 1; i < prices.size(); i++) { BigDecimal current = prices.get(i); BigDecimal previous = prices.get(i - 1); returns.add(current.divide(previous, 8, RoundingMode.HALF_UP).subtract(BigDecimal.ONE)); } return calculateStandardDeviation(returns); } /** * 计算标准差 */ private BigDecimal calculateStandardDeviation(List values) { if (values.isEmpty()) { return BigDecimal.ZERO; } // 计算平均值 BigDecimal sum = values.stream().reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal mean = sum.divide(new BigDecimal(values.size()), 8, RoundingMode.HALF_UP); // 计算方差 BigDecimal variance = values.stream() .map(val -> val.subtract(mean).pow(2)) .reduce(BigDecimal.ZERO, BigDecimal::add) .divide(new BigDecimal(values.size()), 8, RoundingMode.HALF_UP); // 计算标准差 return sqrt(variance); } /** * 计算平方根 */ private BigDecimal sqrt(BigDecimal value) { return new BigDecimal(Math.sqrt(value.doubleValue())); } /** * 空头反转判断 */ private boolean isBearishReversal(BigDecimal currentPrice) { // 柱体顶背离 boolean topDivergence = isMacdTopDivergence(currentPrice); // RSI>70区域死叉 boolean rsiOverbought = rsi.getRsi().compareTo(new BigDecimal(70)) > 0; boolean kdjDeathCross = kdj.isDeathCross(); return topDivergence && rsiOverbought && kdjDeathCross; } /** * 多头反转判断 */ private boolean isBullishReversal(BigDecimal currentPrice) { // 柱体底背离 boolean bottomDivergence = isMacdBottomDivergence(currentPrice); // RSI<30区域金叉 boolean rsiOversold = rsi.getRsi().compareTo(new BigDecimal(30)) < 0; boolean kdjGoldenCross = kdj.isGoldenCross(); return bottomDivergence && rsiOversold && kdjGoldenCross; } /** * 判断MACD顶背离 */ private boolean isMacdTopDivergence(BigDecimal currentPrice) { // 简化的顶背离判断:价格创新高但MACD未创新高 if (priceHistory.size() < 2) { return false; } BigDecimal previousPrice = priceHistory.get(priceHistory.size() - 2); return currentPrice.compareTo(previousPrice) > 0 && macd.getMacdBar().compareTo(prevDea) < 0; } /** * 判断MACD底背离 */ private boolean isMacdBottomDivergence(BigDecimal currentPrice) { // 简化的底背离判断:价格创新低但MACD未创新低 if (priceHistory.size() < 2) { return false; } BigDecimal previousPrice = priceHistory.get(priceHistory.size() - 2); return currentPrice.compareTo(previousPrice) < 0 && macd.getMacdBar().compareTo(prevDea) > 0; } /** * 计算前一期MACD能量柱面积 */ private BigDecimal calculateMacdHistogramAreaPrevious() { if (macdHistogramHistory.size() < 2) { return BigDecimal.ZERO; } List prevHistory = macdHistogramHistory.subList( 0, macdHistogramHistory.size() - 1); return prevHistory.stream() .reduce(BigDecimal.ZERO, BigDecimal::add) .abs(); } /** * 设置信号参数 */ private void setSignalParameters(TradeRequestParam param, TradeSignal signal) { String side = null; switch (signal) { case BUY: side = CoinEnums.SIDE_BUY.getCode(); param.setPosSide(CoinEnums.POSSIDE_LONG.getCode()); break; case SELL: side = CoinEnums.SIDE_SELL.getCode(); param.setPosSide(CoinEnums.POSSIDE_SHORT.getCode()); break; case OPEN_LONG: side = CoinEnums.SIDE_BUY.getCode(); param.setPosSide(CoinEnums.POSSIDE_LONG.getCode()); break; case CLOSE_LONG: side = CoinEnums.SIDE_SELL.getCode(); break; case OPEN_SHORT: side = CoinEnums.SIDE_SELL.getCode(); param.setPosSide(CoinEnums.POSSIDE_SHORT.getCode()); break; case CLOSE_SHORT: side = CoinEnums.SIDE_BUY.getCode(); break; case STOP_LOSS: // 止损操作 side = CoinEnums.POSSIDE_LONG.getCode().equals(param.getPosSide()) ? CoinEnums.SIDE_SELL.getCode() : CoinEnums.SIDE_BUY.getCode(); break; default: param.setTradeType(OrderParamEnums.TRADE_NO.getValue()); return; } param.setSide(side); log.info("设置交易方向: {}, 仓位方向: {}", side, param.getPosSide()); } /** * 更新历史指标值 */ private void updateHistoricalIndicatorValues() { prevEma9 = advancedMA.getEma9(); prevEma21 = advancedMA.getEma21(); prevEma55 = advancedMA.getEma55(); prevDif = macd.getDif(); prevDea = macd.getDea(); prevK = kdj.getK(); prevD = kdj.getD(); prevJ = kdj.getJ(); } /** * 获取账户配置 */ private String getAccountConfig(String accountName, String key) { // 模拟获取账户配置 return OrderParamEnums.OUT_NO.getValue(); } }