package com.xcong.excoin.modules.okxNewPrice.indicator; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; /** * 交易策略实现 * 展示如何为ETH合约交易(开仓/平仓)组合所有指标 */ @Slf4j public class TradingStrategy extends IndicatorBase { @Getter @Setter @AllArgsConstructor @NoArgsConstructor public static class StrategyConfig { private int maShortPeriod = 5; // 短期移动平均周期 private int maLongPeriod = 20; // 长期移动平均周期 private int rsiPeriod = 14; // RSI指标周期 private int kdjPeriod = 9; // KDJ指标周期 private int bollPeriod = 20; // 布林带周期 private double bollK = 2.0; // 布林带标准差倍数 private int atrPeriod = 14; // ATR计算周期 private boolean enableDynamicParams = true; // 是否启用动态参数优化 private boolean enableMultiTimeframeConfirm = true; // 是否启用多周期确认 private int volumeMaPeriod = 20; // 成交量移动平均周期 private boolean enableVolumeConfirm = true; // 是否启用成交量验证 // 风险控制参数 private BigDecimal baseLeverage = new BigDecimal(3); // 基础杠杆倍数 private int volatilityThresholdPeriod = 30; // 波动率阈值计算周期(用于动态杠杆) private boolean enableDynamicLeverage = true; // 是否启用动态杠杆 private boolean enableThreeStepProfitTaking = true; // 是否启用三段式止盈 private boolean enableBlackSwanFilter = true; // 是否启用黑天鹅事件过滤 } public enum Direction { LONG, // 做多方向信号 SHORT, // 做空方向信号 RANGING // 震荡市场 } public enum SignalType { NONE, // 无信号 BUY, // 开多信号 SELL, // 开空信号 CLOSE_BUY, // 平多信号 CLOSE_SELL // 平空信号 } private final StrategyConfig config; private final MA ma; private final AdvancedMA advancedMA; private final BOLL boll; private final KDJ kdj; private final MACD macd; private final RSI rsi; public TradingStrategy() { this(new StrategyConfig()); } public TradingStrategy(StrategyConfig config) { this.config = config; this.ma = new MA(); this.advancedMA = new AdvancedMA(); this.boll = new BOLL(config.getBollPeriod(), config.getBollK()); this.kdj = new KDJ(config.getKdjPeriod()); this.macd = new MACD(); this.rsi = new RSI(config.getRsiPeriod()); } /** * 计算所有指标并生成交易信号 * @param prices 价格数据 * @param high 最高价列表 * @param low 最低价列表 * @param close 收盘价列表 * @param volume 成交量列表 * @param currentPrice 当前价格 * @param hasLongPosition 是否当前持有做多仓位 * @param hasShortPosition 是否当前持有做空仓位 * @param fiveMinPrices 5分钟价格数据(多周期确认) * @param oneHourPrices 1小时价格数据(多周期确认) * @param fourHourPrices 4小时价格数据(多周期确认) * @param fundingRate 当前资金费率(用于黑天鹅过滤) * @param hasLargeTransfer 是否有大额转账(用于黑天鹅过滤) * @param hasUpcomingEvent 是否有即将到来的重大事件(用于黑天鹅过滤) * @return 交易信号 */ public SignalType generateSignal(List prices, List high, List low, List close, List volume, BigDecimal currentPrice, boolean hasLongPosition, boolean hasShortPosition, List fiveMinPrices, List oneHourPrices, List fourHourPrices, BigDecimal fundingRate, boolean hasLargeTransfer, boolean hasUpcomingEvent) { // 计算所有指标 calculateIndicators(prices, high, low, close); // 检查是否为震荡市场,如果是,则执行区间交易策略 if (isRangeMarket(prices)) { log.info("当前市场为震荡行情,执行区间交易策略"); return generateRangeTradingSignal(currentPrice, volume, hasLongPosition, hasShortPosition); } // 黑天鹅事件过滤 if (blackSwanFilter(fundingRate, hasLargeTransfer, hasUpcomingEvent)) { log.info("黑天鹅事件过滤触发,不产生信号"); return SignalType.NONE; } // 开多信号 if (shouldOpenLong(currentPrice, prices, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) { log.info("生成买入信号"); return SignalType.BUY; } // 开空信号 if (shouldOpenShort(currentPrice, prices, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) { log.info("生成卖出信号"); return SignalType.SELL; } // 平多信号 if (shouldCloseLong(currentPrice, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && hasLongPosition) { log.info("生成平多信号"); return SignalType.CLOSE_BUY; } // 平空信号 if (shouldCloseShort(currentPrice, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && hasShortPosition) { log.info("生成平空信号"); return SignalType.CLOSE_SELL; } log.info("未生成信号"); return SignalType.NONE; } /** * 多周期确认辅助方法(看涨) * @param fiveMinPrices 5分钟价格数据 * @param oneHourPrices 1小时价格数据 * @param fourHourPrices 4小时价格数据 * @return 是否有足够的多周期确认 */ private boolean multiTimeframeConfirm(List fiveMinPrices, List oneHourPrices, List fourHourPrices) { if (!config.isEnableMultiTimeframeConfirm()) { return true; // 如果未启用多周期确认,则默认返回true } int confirmCount = 0; // 检查5分钟周期 if (hasBullishTrend(fiveMinPrices)) { confirmCount++; } // 检查1小时周期 if (hasBullishTrend(oneHourPrices)) { confirmCount++; } // 检查4小时周期 if (hasBullishTrend(fourHourPrices)) { confirmCount++; } // 至少需要2个周期确认 return confirmCount >= 2; } /** * 多周期确认辅助方法(看跌) * @param fiveMinPrices 5分钟价格数据 * @param oneHourPrices 1小时价格数据 * @param fourHourPrices 4小时价格数据 * @return 是否有足够的多周期确认 */ private boolean multiTimeframeBearishConfirm(List fiveMinPrices, List oneHourPrices, List fourHourPrices) { if (!config.isEnableMultiTimeframeConfirm()) { return true; // 如果未启用多周期确认,则默认返回true } int confirmCount = 0; // 检查5分钟周期 if (hasBearishTrend(fiveMinPrices)) { confirmCount++; } // 检查1小时周期 if (hasBearishTrend(oneHourPrices)) { confirmCount++; } // 检查4小时周期 if (hasBearishTrend(fourHourPrices)) { confirmCount++; } // 至少需要2个周期确认 return confirmCount >= 2; } /** * 检查指定周期是否有看涨趋势 * @param prices 价格数据 * @return 是否有看涨趋势 */ private boolean hasBullishTrend(List prices) { if (prices == null || prices.size() < 20) { return false; // 数据不足 } // 创建临时MA指标用于判断趋势 MA tempMA = new MA(); MACD tempMACD = new MACD(); // 计算指标 tempMA.calculate(prices); tempMACD.calculate(prices); // 优化后的多头趋势判断: // 1. MA多头排列:短期MA > 中期MA > 长期MA // 2. 所有均线向上发散 // 3. MACD趋势:DIFF线在DEA线之上 boolean isMaBullish = tempMA.getEma5().compareTo(tempMA.getEma10()) > 0 && tempMA.getEma10().compareTo(tempMA.getEma20()) > 0; // 判断均线向上发散(简单方法:近期均线斜率为正) boolean isMaDivergingUp = calculateMaSlope(prices, 5) > 0 && calculateMaSlope(prices, 10) > 0 && calculateMaSlope(prices, 20) > 0; // MACD趋势判断 boolean isMacdBullish = tempMACD.getDif().compareTo(tempMACD.getDea()) > 0; return isMaBullish && isMaDivergingUp && isMacdBullish; } /** * 检查指定周期是否有看跌趋势 * @param prices 价格数据 * @return 是否有看跌趋势 */ private boolean hasBearishTrend(List prices) { if (prices == null || prices.size() < 20) { return false; // 数据不足 } // 创建临时MA指标用于判断趋势 MA tempMA = new MA(); MACD tempMACD = new MACD(); // 计算指标 tempMA.calculate(prices); tempMACD.calculate(prices); // 优化后的空头趋势判断: // 1. MA空头排列:短期MA < 中期MA < 长期MA // 2. 所有均线向下发散 // 3. MACD趋势:DIFF线在DEA线之下 boolean isMaBearish = tempMA.getEma5().compareTo(tempMA.getEma10()) < 0 && tempMA.getEma10().compareTo(tempMA.getEma20()) < 0; // 判断均线向下发散(简单方法:近期均线斜率为负) boolean isMaDivergingDown = calculateMaSlope(prices, 5) < 0 && calculateMaSlope(prices, 10) < 0 && calculateMaSlope(prices, 20) < 0; // MACD趋势判断 boolean isMacdBearish = tempMACD.getDif().compareTo(tempMACD.getDea()) < 0; return isMaBearish && isMaDivergingDown && isMacdBearish; } /** * 计算均线斜率 * @param prices 价格数据 * @param period 均线周期 * @return 均线斜率(正数表示向上,负数表示向下) */ private double calculateMaSlope(List prices, int period) { if (prices == null || prices.size() < period * 2) { return 0; // 数据不足 } // 获取最近两个周期的均线值 int endIndex = prices.size() - 1; int startIndex = endIndex - period + 1; // 计算当前周期的均线 BigDecimal currentMa = calculateMA(prices.subList(startIndex, endIndex + 1), period); // 计算前一个周期的均线 int prevStartIndex = startIndex - period; BigDecimal prevMa = calculateMA(prices.subList(prevStartIndex, startIndex), period); // 计算斜率(简单差值法) return currentMa.subtract(prevMa).doubleValue(); } /** * 成交量验证辅助方法 * 增强版:当前成交量需大于20周期均量的1.2倍,以过滤无量反弹/回调的假信号 * @param volume 成交量列表 * @return 是否通过成交量验证 */ private boolean volumeConfirm(List volume) { if (!config.isEnableVolumeConfirm() || volume == null || volume.size() < config.getVolumeMaPeriod()) { return true; // 如果未启用成交量验证或数据不足,则默认返回true } // 计算成交量移动平均 BigDecimal volumeMA = calculateMA(volume, config.getVolumeMaPeriod()); BigDecimal currentVolume = volume.get(volume.size() - 1); // 增强验证:成交量需要大于1.2倍均线 return currentVolume.compareTo(volumeMA.multiply(new BigDecimal("1.2"))) > 0; } /** * 量价背离检测 * 检测价格上涨/下跌但成交量萎缩的情况,或价格和成交量趋势不一致 * @param prices 价格列表 * @param volume 成交量列表 * @return 是否存在量价背离 */ private boolean hasPriceVolumeDivergence(List prices, List volume) { if (!config.isEnableVolumeConfirm() || prices == null || volume == null || prices.size() < 3 || volume.size() < 3) { return false; // 如果未启用成交量验证或数据不足,则默认返回false } // 获取最近3个周期的价格和成交量 BigDecimal currentPrice = prices.get(prices.size() - 1); BigDecimal prevPrice1 = prices.get(prices.size() - 2); BigDecimal prevPrice2 = prices.get(prices.size() - 3); BigDecimal currentVolume = volume.get(volume.size() - 1); BigDecimal prevVolume1 = volume.get(volume.size() - 2); BigDecimal prevVolume2 = volume.get(volume.size() - 3); // 计算价格趋势 boolean priceTrendUp = currentPrice.compareTo(prevPrice1) > 0 && prevPrice1.compareTo(prevPrice2) > 0; boolean priceTrendDown = currentPrice.compareTo(prevPrice1) < 0 && prevPrice1.compareTo(prevPrice2) < 0; // 计算成交量趋势 boolean volumeTrendUp = currentVolume.compareTo(prevVolume1) > 0 && prevVolume1.compareTo(prevVolume2) > 0; boolean volumeTrendDown = currentVolume.compareTo(prevVolume1) < 0 && prevVolume1.compareTo(prevVolume2) < 0; // 检测量价背离 // 价格上涨但成交量萎缩 boolean bullishDivergence = priceTrendUp && volumeTrendDown; // 价格下跌但成交量萎缩(通常是强势信号,不视为背离) // 价格下跌但成交量放大(可能是恐慌性抛售,视为背离) boolean bearishDivergence = priceTrendDown && volumeTrendUp; return bullishDivergence || bearishDivergence; } /** * 计算所有指标 * @param prices 价格数据 * @param high 最高价列表 * @param low 最低价列表 * @param close 收盘价列表 */ private void calculateIndicators(List prices, List high, List low, List close) { // 计算ATR和波动率 BigDecimal atr = calculateATR(high, low, close, config.getAtrPeriod()); BigDecimal volatility = normalizeVolatility(close, atr); // 使用动态参数计算指标 if (config.isEnableDynamicParams()) { log.info("使用动态参数计算指标,波动率: {}", volatility); ma.calculate(prices, volatility); macd.calculate(prices, volatility); } else { ma.calculate(prices); macd.calculate(prices); } // 其他指标计算 advancedMA.calculateTripleEMA(prices); boll.calculate(prices); kdj.calculate(prices); rsi.calculate(prices); } /** * 检查是否为震荡市场 * @param prices 价格数据列表 * @return 是否为震荡市场 */ private boolean isRangeMarket(List prices) { // 优化的震荡市场判断条件,放宽标准以减少RANGING信号频率 // 1. 高级MA三线收敛(小于3%,放宽条件) boolean isMaConverged = advancedMA.calculatePercent().compareTo(new BigDecimal(3)) < 0; // 2. RSI中性区间(35-65,放宽条件) boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(35)) > 0 && rsi.getRsi().compareTo(new BigDecimal(65)) < 0; // 3. BOLL带宽收窄(小于0.06,放宽条件) boolean isBollNarrow = boll.calculateBandWidth().compareTo(new BigDecimal(0.06)) < 0; // 4. MACD柱状图趋近于0(多空力量平衡,放宽条件) boolean isMacdBalanced = macd.getMacdBar().abs().compareTo(new BigDecimal(0.02)) < 0; // 5. KDJ在中间区域波动(25-75,放宽条件) boolean isKdjNeutral = kdj.getK().compareTo(new BigDecimal(25)) > 0 && kdj.getK().compareTo(new BigDecimal(75)) < 0 && kdj.getD().compareTo(new BigDecimal(25)) > 0 && kdj.getD().compareTo(new BigDecimal(75)) < 0 && kdj.getJ().compareTo(new BigDecimal(20)) > 0 && kdj.getJ().compareTo(new BigDecimal(80)) < 0; // 6. 价格波动范围较小(最近20根K线最高价与最低价的比值小于1.06,放宽条件) boolean isPriceVolatilityLow = calculatePriceVolatility(prices).compareTo(new BigDecimal(1.06)) < 0; // 综合判断:只需要满足部分条件即可,增加趋势信号的机会 int rangeConditionsMet = 0; if (isMaConverged) { rangeConditionsMet++; } if (isRsiNeutral) { rangeConditionsMet++; } if (isBollNarrow) { rangeConditionsMet++; } if (isMacdBalanced) { rangeConditionsMet++; } if (isKdjNeutral) { rangeConditionsMet++; } if (isPriceVolatilityLow) { rangeConditionsMet++; } // 只有满足4个或以上条件才判定为震荡市场 return rangeConditionsMet >= 4; } /** * 计算价格波动率(最近20根K线最高价与最低价的比值) * @param prices 价格数据列表 * @return 价格波动率 */ private BigDecimal calculatePriceVolatility(List prices) { if (prices == null || prices.isEmpty()) { return BigDecimal.ONE; } List recentPrices = prices.subList(Math.max(0, prices.size() - 20), prices.size()); if (recentPrices.isEmpty()) { return BigDecimal.ONE; } BigDecimal highest = recentPrices.stream().max(BigDecimal::compareTo).orElse(BigDecimal.ONE); BigDecimal lowest = recentPrices.stream().min(BigDecimal::compareTo).orElse(BigDecimal.ONE); return highest.divide(lowest, 10, RoundingMode.HALF_UP); } /** * 根据15分钟时间框架指标确定市场方向(做多/做空/震荡) * @param prices 价格数据列表 * @param high 最高价列表 * @param low 最低价列表 * @param close 收盘价列表 * @param currentPrice 当前价格 * @return 市场方向 */ public Direction getDirection(List prices, List high, List low, List close, BigDecimal currentPrice) { // 计算所有指标 calculateIndicators(prices, high, low, close); // 检查是否为震荡市场 if (isRangeMarket(prices)) { return Direction.RANGING; } // 优化后的多头趋势条件: // 1. MA多头排列(短期MA > 中期MA > 长期MA) // 2. MACD趋势(DIFF在DEA之上,代表多头趋势) // 3. 价格在BOLL中轨上方 // 4. RSI(50-65) 为健康多头区间 boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 && ma.getEma10().compareTo(ma.getEma20()) > 0; boolean isMacdBullish = macd.getDif().compareTo(macd.getDea()) > 0; boolean isPriceAboveBollMid = currentPrice.compareTo(boll.getMid()) > 0; boolean isRsiBullish = rsi.getRsi().compareTo(new BigDecimal(50)) > 0 && rsi.getRsi().compareTo(new BigDecimal(65)) < 0; // 检查多头信号(MA多头 + MACD金叉 + 价格在BOLL中轨上方 + RSI(50-65)) if (isMaBullish && isMacdBullish && isPriceAboveBollMid && isRsiBullish) { return Direction.LONG; } // 优化后的空头趋势条件: // 1. MA空头排列(短期MA < 中期MA < 长期MA) // 2. MACD趋势(DIFF在DEA之下,代表空头趋势) // 3. 价格在BOLL中轨下方 // 4. RSI(35-50) 为健康空头区间 boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 && ma.getEma10().compareTo(ma.getEma20()) < 0; boolean isMacdBearish = macd.getDif().compareTo(macd.getDea()) < 0; boolean isPriceBelowBollMid = currentPrice.compareTo(boll.getMid()) < 0; boolean isRsiBearish = rsi.getRsi().compareTo(new BigDecimal(35)) > 0 && rsi.getRsi().compareTo(new BigDecimal(50)) < 0; // 检查空头信号(MA空头 + MACD死叉 + 价格在BOLL中轨下方 + RSI(35-50)) if (isMaBearish && isMacdBearish && isPriceBelowBollMid && isRsiBearish) { return Direction.SHORT; } // 如果没有明确方向,默认为震荡 return Direction.RANGING; } /** * 根据优化建议检查是否应该开多仓位 * 使用主次结合法: * - 主信号(趋势):MA多头排列 + MACD金叉 * - 辅信号(入场点):价格回调至BOLL中轨附近获得支撑,且出现KDJ金叉或RSI从低位回升至50以上 * @param currentPrice 当前价格 * @param prices 价格数据 * @param volume 成交量列表 * @param fiveMinPrices 5分钟价格数据 * @param oneHourPrices 1小时价格数据 * @param fourHourPrices 4小时价格数据 * @return 是否应该开多 */ private boolean shouldOpenLong(BigDecimal currentPrice, List prices, List volume, List fiveMinPrices, List oneHourPrices, List fourHourPrices) { // 主信号:趋势判断 // MA多头排列(短期MA > 中期MA > 长期MA) boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 && ma.getEma10().compareTo(ma.getEma20()) > 0; // MACD趋势(DIFF在DEA之上) boolean isMacdBullish = macd.getDif().compareTo(macd.getDea()) > 0; // 如果主信号不满足,直接返回false if (!(isMaBullish && isMacdBullish)) { return false; } // 辅信号:入场点判断 // 价格在BOLL中轨上方,且未触及上轨(避免追高) boolean isPriceInSafeZone = currentPrice.compareTo(boll.getMid()) > 0 && currentPrice.compareTo(boll.getUpper()) < 0; // 价格靠近BOLL中轨 boolean isPriceNearBollMid = currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(0.98))) > 0 && currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(1.02))) < 0; // RSI:健康区间30-70,刚从50中线向上 boolean isRsiHealthy = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 && rsi.getRsi().compareTo(new BigDecimal(70)) < 0; boolean isRsiAboveMid = rsi.getRsi().compareTo(new BigDecimal(50)) > 0; // KDJ:金叉或超卖区域 boolean isKdjGoldenCross = kdj.isGoldenCross(); boolean isKdjOversold = kdj.getJ().compareTo(new BigDecimal(15)) < 0; // 入场点条件:价格在安全区域或靠近中轨,且动量健康 boolean isEntryPointValid = (isPriceInSafeZone || isPriceNearBollMid) && (isRsiHealthy && isRsiAboveMid) && (isKdjGoldenCross || isKdjOversold); // 成交量验证 boolean isVolumeConfirmed = volumeConfirm(volume); // 量价背离检测 boolean isPriceVolumeDivergence = hasPriceVolumeDivergence(prices, volume); // 多周期确认 boolean isMultiTimeframeConfirmed = multiTimeframeConfirm(fiveMinPrices, oneHourPrices, fourHourPrices); return isEntryPointValid && isVolumeConfirmed && !isPriceVolumeDivergence && isMultiTimeframeConfirmed; } /** * 根据优化建议检查是否应该开空仓位 * 使用主次结合法: * - 主信号(趋势):MA空头排列 + MACD死叉 * - 辅信号(入场点):价格反弹至BOLL中轨附近遇阻,且出现KDJ死叉或RSI从高位回落至50以下 * @param currentPrice 当前价格 * @param prices 价格数据 * @param volume 成交量列表 * @param fiveMinPrices 5分钟价格数据 * @param oneHourPrices 1小时价格数据 * @param fourHourPrices 4小时价格数据 * @return 是否应该开空 */ private boolean shouldOpenShort(BigDecimal currentPrice, List prices, List volume, List fiveMinPrices, List oneHourPrices, List fourHourPrices) { // 主信号:趋势判断 // MA空头排列(短期MA < 中期MA < 长期MA) boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 && ma.getEma10().compareTo(ma.getEma20()) < 0; // MACD趋势(DIFF在DEA之下) boolean isMacdBearish = macd.getDif().compareTo(macd.getDea()) < 0; // 如果主信号不满足,直接返回false if (!(isMaBearish && isMacdBearish)) { return false; } // 辅信号:入场点判断 // 价格在BOLL中轨下方,且未触及下轨(避免追空) boolean isPriceInSafeZone = currentPrice.compareTo(boll.getMid()) < 0 && currentPrice.compareTo(boll.getLower()) > 0; // 价格靠近BOLL中轨 boolean isPriceNearBollMid = currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(0.98))) > 0 && currentPrice.compareTo(boll.getMid().multiply(new BigDecimal(1.02))) < 0; // RSI:健康区间30-70,刚从50中线向下 boolean isRsiHealthy = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 && rsi.getRsi().compareTo(new BigDecimal(70)) < 0; boolean isRsiBelowMid = rsi.getRsi().compareTo(new BigDecimal(50)) < 0; // KDJ:死叉或超买区域 boolean isKdjDeathCross = kdj.isDeathCross(); boolean isKdjOverbought = kdj.getJ().compareTo(new BigDecimal(85)) > 0; // 入场点条件:价格在安全区域或靠近中轨,且动量健康 boolean isEntryPointValid = (isPriceInSafeZone || isPriceNearBollMid) && (isRsiHealthy && isRsiBelowMid) && (isKdjDeathCross || isKdjOverbought); // 成交量验证 boolean isVolumeConfirmed = volumeConfirm(volume); // 量价背离检测 boolean isPriceVolumeDivergence = hasPriceVolumeDivergence(prices, volume); // 多周期确认(看跌) boolean isMultiTimeframeConfirmed = multiTimeframeBearishConfirm(fiveMinPrices, oneHourPrices, fourHourPrices); return isEntryPointValid && isVolumeConfirmed && !isPriceVolumeDivergence && isMultiTimeframeConfirmed; } /** * 根据优化建议检查是否应该平多仓位 * 采用分层止盈止损策略: * - 保护止损:价格跌破BOLL中轨 * - 跟踪止损:价格有效跌破移动平均线 * - 最终平仓:趋势反转信号(MA空头排列 + MACD死叉) * @param currentPrice 当前价格 * @param volume 成交量列表 * @param fiveMinPrices 5分钟价格数据 * @param oneHourPrices 1小时价格数据 * @param fourHourPrices 4小时价格数据 * @return 是否应该平多 */ private boolean shouldCloseLong(BigDecimal currentPrice, List volume, List fiveMinPrices, List oneHourPrices, List fourHourPrices) { // 保护止损:价格跌破BOLL中轨(关键支撑位) boolean isStopLossTriggered = currentPrice.compareTo(boll.getMid()) < 0; // 跟踪止损:价格有效跌破短期均线(5EMA) boolean isTrailingStopTriggered = currentPrice.compareTo(ma.getEma5()) < 0; // 趋势反转信号:MA空头排列 + MACD死叉 boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 && ma.getEma10().compareTo(ma.getEma20()) < 0; boolean isMacdBearish = macd.getDif().compareTo(macd.getDea()) < 0; boolean isTrendReversed = isMaBearish && isMacdBearish; // 多周期确认(看跌) boolean isMultiTimeframeConfirmed = multiTimeframeBearishConfirm(fiveMinPrices, oneHourPrices, fourHourPrices); // 平多条件:保护止损触发 或 跟踪止损触发 或 (趋势反转且多周期确认) return isStopLossTriggered || isTrailingStopTriggered || (isTrendReversed && isMultiTimeframeConfirmed); } /** * 根据优化建议检查是否应该平空仓位 * 采用分层止盈止损策略: * - 保护止损:价格突破BOLL中轨 * - 跟踪止损:价格有效突破移动平均线 * - 最终平仓:趋势反转信号(MA多头排列 + MACD金叉) * @param currentPrice 当前价格 * @param volume 成交量列表 * @param fiveMinPrices 5分钟价格数据 * @param oneHourPrices 1小时价格数据 * @param fourHourPrices 4小时价格数据 * @return 是否应该平空 */ private boolean shouldCloseShort(BigDecimal currentPrice, List volume, List fiveMinPrices, List oneHourPrices, List fourHourPrices) { // 保护止损:价格突破BOLL中轨(关键阻力位) boolean isStopLossTriggered = currentPrice.compareTo(boll.getMid()) > 0; // 跟踪止损:价格有效突破短期均线(5EMA) boolean isTrailingStopTriggered = currentPrice.compareTo(ma.getEma5()) > 0; // 趋势反转信号:MA多头排列 + MACD金叉 boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 && ma.getEma10().compareTo(ma.getEma20()) > 0; boolean isMacdBullish = macd.getDif().compareTo(macd.getDea()) > 0; boolean isTrendReversed = isMaBullish && isMacdBullish; // 多周期确认(看涨) boolean isMultiTimeframeConfirmed = multiTimeframeConfirm(fiveMinPrices, oneHourPrices, fourHourPrices); // 平空条件:保护止损触发 或 跟踪止损触发 或 (趋势反转且多周期确认) return isStopLossTriggered || isTrailingStopTriggered || (isTrendReversed && isMultiTimeframeConfirmed); } /** * 获取所有指标的当前状态 * @return 指标状态字符串 */ public String getIndicatorStatus() { return String.format("MA5: %s, MA20: %s, ", ma.getEma5(), ma.getEma20()) + String.format("MACD-DIF: %s, MACD-DEA: %s, MACD-BAR: %s, ", macd.getDif(), macd.getDea(), macd.getMacdBar()) + String.format("KDJ-K: %s, KDJ-D: %s, KDJ-J: %s, ", kdj.getK(), kdj.getD(), kdj.getJ()) + String.format("RSI: %s, ", rsi.getRsi()) + String.format("BOLL-MID: %s, BOLL-UP: %s, BOLL-DN: %s, ", boll.getMid(), boll.getUpper(), boll.getLower()) + String.format("AdvancedMA-Bullish: %s, Bearish: %s, Percent: %s", advancedMA.isBullish(), advancedMA.isBearish(), advancedMA.calculatePercent()); } /** * 生成区间交易信号 * 在震荡行情下,使用BOLL通道作为区间边界,结合KDJ指标生成交易信号 * @param currentPrice 当前价格 * @param volume 成交量列表 * @param hasLongPosition 是否当前持有做多仓位 * @param hasShortPosition 是否当前持有做空仓位 * @return 交易信号 */ private SignalType generateRangeTradingSignal(BigDecimal currentPrice, List volume, boolean hasLongPosition, boolean hasShortPosition) { // 区间交易策略逻辑: // 1. 价格触及BOLL下轨且KDJ超卖 → 买入信号 // 2. 价格触及BOLL上轨且KDJ超买 → 卖出信号 // 3. 价格回归BOLL中轨 → 平仓信号 // 检查KDJ极端超买超卖情况 boolean isKdjJExtremeOverbought = kdj.getJ().compareTo(new BigDecimal("100")) > 0; boolean isKdjJExtremeOversold = kdj.getJ().compareTo(new BigDecimal("10")) < 0; // 价格触及BOLL下轨(基础条件) boolean isPriceNearBollLower = currentPrice.compareTo(boll.getLower()) >= 0 && currentPrice.compareTo(boll.getLower().multiply(new BigDecimal("1.01"))) <= 0; // 价格触及BOLL上轨(基础条件) boolean isPriceNearBollUpper = currentPrice.compareTo(boll.getUpper()) <= 0 && currentPrice.compareTo(boll.getUpper().multiply(new BigDecimal("0.99"))) >= 0; // 当KDJ-J极度超买/超卖时,放宽BOLL边界要求 if (isKdjJExtremeOverbought) { isPriceNearBollUpper = currentPrice.compareTo(boll.getUpper().multiply(new BigDecimal("0.985"))) >= 0; } if (isKdjJExtremeOversold) { isPriceNearBollLower = currentPrice.compareTo(boll.getLower().multiply(new BigDecimal("1.015"))) <= 0; } // 价格回归BOLL中轨附近 boolean isPriceNearBollMid = currentPrice.compareTo(boll.getMid().multiply(new BigDecimal("0.998"))) >= 0 && currentPrice.compareTo(boll.getMid().multiply(new BigDecimal("1.002"))) <= 0; // KDJ超卖(使用调整后的阈值) boolean isKdjOversold = kdj.getJ().compareTo(new BigDecimal(15)) < 0; // KDJ超买(使用调整后的阈值) boolean isKdjOverbought = kdj.getJ().compareTo(new BigDecimal(85)) > 0; // RSI超卖(<30) boolean isRsiOversold = rsi.getRsi().compareTo(new BigDecimal(30)) < 0; // RSI超买(>70) boolean isRsiOverbought = rsi.getRsi().compareTo(new BigDecimal(70)) > 0; // 成交量验证(当前成交量大于20周期均值的1.1倍) boolean isVolumeValid = volumeConfirm(volume) && volume.get(volume.size() - 1).compareTo(calculateMA(volume, config.getVolumeMaPeriod()).multiply(new BigDecimal("1.1"))) > 0; // 开多逻辑:价格触及BOLL下轨且KDJ超卖且RSI超卖且有成交量支持 if (isPriceNearBollLower && isKdjOversold && isRsiOversold && isVolumeValid && !hasLongPosition && !hasShortPosition) { log.info("区间交易:价格触及BOLL下轨({}), KDJ-J值({})超卖,RSI({})超卖,生成买入信号", boll.getLower(), kdj.getJ(), rsi.getRsi()); return SignalType.BUY; } // 开空逻辑:价格触及BOLL上轨且KDJ超买且RSI超买且有成交量支持 if (isPriceNearBollUpper && isKdjOverbought && isRsiOverbought && isVolumeValid && !hasLongPosition && !hasShortPosition) { log.info("区间交易:价格触及BOLL上轨({}), KDJ-J值({})超买,RSI({})超买,生成卖出信号", boll.getUpper(), kdj.getJ(), rsi.getRsi()); return SignalType.SELL; } // 平多逻辑:价格回归BOLL中轨 if (isPriceNearBollMid && hasLongPosition) { log.info("区间交易:价格回归BOLL中轨({}),生成平多信号", boll.getMid()); return SignalType.CLOSE_BUY; } // 平空逻辑:价格回归BOLL中轨 if (isPriceNearBollMid && hasShortPosition) { log.info("区间交易:价格回归BOLL中轨({}),生成平空信号", boll.getMid()); return SignalType.CLOSE_SELL; } return SignalType.NONE; } /** * 计算动态杠杆倍数 * 杠杆倍数 = 基础杠杆 * (波动率阈值/当前波动率) * @param high 最高价列表 * @param low 最低价列表 * @param close 收盘价列表 * @return 动态杠杆倍数 */ public BigDecimal calculateDynamicLeverage(List high, List low, List close) { if (!config.isEnableDynamicLeverage()) { return config.getBaseLeverage(); } // 计算当前ATR和波动率 BigDecimal currentAtr = calculateATR(high, low, close, config.getAtrPeriod()); BigDecimal currentVolatility = normalizeVolatility(close, currentAtr); // 计算30日ATR移动中位数作为波动率阈值 BigDecimal volatilityThreshold = calculateVolatilityThreshold(high, low, close); // 动态计算杠杆倍数 BigDecimal leverage = config.getBaseLeverage().multiply(volatilityThreshold).divide(currentVolatility, 2, BigDecimal.ROUND_HALF_UP); // 限制杠杆范围在1x-10x之间 leverage = leverage.min(new BigDecimal(10)).max(BigDecimal.ONE); log.info("动态杠杆计算 - 基础杠杆: {}, 波动率阈值: {}, 当前波动率: {}, 计算杠杆: {}", config.getBaseLeverage(), volatilityThreshold, currentVolatility, leverage); return leverage; } /** * 计算波动率阈值(30日ATR移动中位数) * @param high 最高价列表 * @param low 最低价列表 * @param close 收盘价列表 * @return 波动率阈值 */ private BigDecimal calculateVolatilityThreshold(List high, List low, List close) { if (high == null || low == null || close == null || close.size() < config.getVolatilityThresholdPeriod()) { return new BigDecimal(5); // 默认阈值 } List volatilityList = new ArrayList<>(); for (int i = close.size() - config.getVolatilityThresholdPeriod(); i < close.size(); i++) { List recentHigh = high.subList(Math.max(0, i - config.getAtrPeriod()), i + 1); List recentLow = low.subList(Math.max(0, i - config.getAtrPeriod()), i + 1); List recentClose = close.subList(Math.max(0, i - config.getAtrPeriod()), i + 1); BigDecimal atr = calculateATR(recentHigh, recentLow, recentClose, config.getAtrPeriod()); BigDecimal volatility = normalizeVolatility(recentClose, atr); volatilityList.add(volatility); } // 计算中位数 volatilityList.sort(BigDecimal::compareTo); int midIndex = volatilityList.size() / 2; return volatilityList.get(midIndex); } /** * 三段式止盈策略 * 第一目标:BOLL上轨(30%仓位) * 第二目标:斐波那契161.8%(50%仓位) * 第三目标:趋势线破位(20%仓位) * @param entryPrice 入场价格 * @param currentPrice 当前价格 * @param direction 交易方向 * @param positionSize 当前仓位大小 * @return 止盈信号和应该平仓的仓位比例 */ public ProfitTakingResult calculateThreeStepProfitTaking(BigDecimal entryPrice, BigDecimal currentPrice, Direction direction, BigDecimal positionSize) { if (!config.isEnableThreeStepProfitTaking()) { return new ProfitTakingResult(SignalType.NONE, BigDecimal.ZERO); } // 计算三个止盈目标 BigDecimal firstTarget = calculateFirstProfitTarget(entryPrice, currentPrice, direction); BigDecimal secondTarget = calculateSecondProfitTarget(entryPrice, direction); BigDecimal thirdTarget = calculateThirdProfitTarget(currentPrice, direction); // 判断当前价格是否达到目标 if (direction == Direction.LONG) { if (currentPrice.compareTo(thirdTarget) >= 0) { // 达到第三目标,平全部仓位 return new ProfitTakingResult(SignalType.CLOSE_BUY, positionSize); } else if (currentPrice.compareTo(secondTarget) >= 0) { // 达到第二目标,平50%仓位 return new ProfitTakingResult(SignalType.CLOSE_BUY, positionSize.multiply(new BigDecimal("0.5"))); } else if (currentPrice.compareTo(firstTarget) >= 0) { // 达到第一目标,平30%仓位 return new ProfitTakingResult(SignalType.CLOSE_BUY, positionSize.multiply(new BigDecimal("0.3"))); } } else if (direction == Direction.SHORT) { if (currentPrice.compareTo(thirdTarget) <= 0) { // 达到第三目标,平全部仓位 return new ProfitTakingResult(SignalType.CLOSE_SELL, positionSize); } else if (currentPrice.compareTo(secondTarget) <= 0) { // 达到第二目标,平50%仓位 return new ProfitTakingResult(SignalType.CLOSE_SELL, positionSize.multiply(new BigDecimal("0.5"))); } else if (currentPrice.compareTo(firstTarget) <= 0) { // 达到第一目标,平30%仓位 return new ProfitTakingResult(SignalType.CLOSE_SELL, positionSize.multiply(new BigDecimal("0.3"))); } } return new ProfitTakingResult(SignalType.NONE, BigDecimal.ZERO); } /** * 计算第一止盈目标:BOLL上轨 */ private BigDecimal calculateFirstProfitTarget(BigDecimal entryPrice, BigDecimal currentPrice, Direction direction) { return direction == Direction.LONG ? boll.getUpper() : boll.getLower(); } /** * 计算第二止盈目标:斐波那契161.8% */ private BigDecimal calculateSecondProfitTarget(BigDecimal entryPrice, Direction direction) { BigDecimal fibonacciRatio = new BigDecimal("1.618"); if (direction == Direction.LONG) { return entryPrice.multiply(BigDecimal.ONE.add(fibonacciRatio.divide(new BigDecimal(100)))); } else { return entryPrice.multiply(BigDecimal.ONE.subtract(fibonacciRatio.divide(new BigDecimal(100)))); } } /** * 计算第三止盈目标:简单趋势线破位(这里简化为MA5下穿MA20) */ private BigDecimal calculateThirdProfitTarget(BigDecimal currentPrice, Direction direction) { // 这里使用简化的趋势线破位判断 // 实际应用中可以使用更复杂的趋势线计算 return direction == Direction.LONG ? ma.getEma20() : ma.getEma20(); } /** * 黑天鹅事件过滤 * 规避重大事件前后30分钟、链上大额转账、异常资金费率 * @param fundingRate 当前资金费率 * @param hasLargeTransfer 是否有大额转账 * @param hasUpcomingEvent 是否有即将到来的重大事件 * @return 是否应该规避交易 */ public boolean blackSwanFilter(BigDecimal fundingRate, boolean hasLargeTransfer, boolean hasUpcomingEvent) { if (!config.isEnableBlackSwanFilter()) { return false; } // 资金费率绝对值大于0.2% boolean isAbnormalFundingRate = fundingRate != null && fundingRate.abs().compareTo(new BigDecimal("0.002")) > 0; // 大额转账监控(这里简化为外部传入) // 重大事件监控(这里简化为外部传入) boolean shouldAvoid = isAbnormalFundingRate || hasLargeTransfer || hasUpcomingEvent; if (shouldAvoid) { log.info("黑天鹅事件过滤触发 - 资金费率异常: {}, 大额转账: {}, 即将发生重大事件: {}", isAbnormalFundingRate, hasLargeTransfer, hasUpcomingEvent); } return shouldAvoid; } /** * 止盈结果类 */ public static class ProfitTakingResult { private SignalType signal; private BigDecimal closePositionSize; public ProfitTakingResult(SignalType signal, BigDecimal closePositionSize) { this.signal = signal; this.closePositionSize = closePositionSize; } public SignalType getSignal() { return signal; } public BigDecimal getClosePositionSize() { return closePositionSize; } } }