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.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()) { log.debug("当前市场为震荡行情,不产生信号"); return SignalType.NONE; } // 黑天鹅事件过滤 if (blackSwanFilter(fundingRate, hasLargeTransfer, hasUpcomingEvent)) { log.debug("黑天鹅事件过滤触发,不产生信号"); return SignalType.NONE; } // 开多信号 if (shouldOpenLong(currentPrice, prices, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) { log.debug("生成买入信号"); return SignalType.BUY; } // 开空信号 if (shouldOpenShort(currentPrice, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && !hasLongPosition && !hasShortPosition) { log.debug("生成卖出信号"); return SignalType.SELL; } // 平多信号 if (shouldCloseLong(currentPrice, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && hasLongPosition) { log.debug("生成平多信号"); return SignalType.CLOSE_BUY; } // 平空信号 if (shouldCloseShort(currentPrice, volume, fiveMinPrices, oneHourPrices, fourHourPrices) && hasShortPosition) { log.debug("生成平空信号"); return SignalType.CLOSE_SELL; } log.debug("未生成信号"); 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(); tempMA.calculate(prices); // 简单的趋势判断:短期MA > 长期MA return tempMA.getEma5().compareTo(tempMA.getEma20()) > 0; } /** * 检查指定周期是否有看跌趋势 * @param prices 价格数据 * @return 是否有看跌趋势 */ private boolean hasBearishTrend(List prices) { if (prices == null || prices.size() < 20) { return false; // 数据不足 } // 创建临时MA指标用于判断趋势 MA tempMA = new MA(); tempMA.calculate(prices); // 简单的趋势判断:短期MA < 长期MA return tempMA.getEma5().compareTo(tempMA.getEma20()) < 0; } /** * 成交量验证辅助方法 * @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); // 成交量需要大于均线 return currentVolume.compareTo(volumeMA) > 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.debug("使用动态参数计算指标,波动率: {}", 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); } /** * 检查是否为震荡市场 * @return 是否为震荡市场 */ private boolean isRangeMarket() { // 高级MA线收敛 + RSI(40-60) + 布林带收窄 boolean isMaConverged = advancedMA.calculatePercent().compareTo(new BigDecimal(2)) < 0; boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(40)) > 0 && rsi.getRsi().compareTo(new BigDecimal(60)) < 0; boolean isBollNarrow = boll.calculateBandWidth().compareTo(new BigDecimal(0.05)) < 0; return isMaConverged && isRsiNeutral && isBollNarrow; } /** * 根据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()) { return Direction.RANGING; } // 检查做多方向条件:MA多头排列 + MACD金叉 + RSI中性(30-70) + BOLL价格在上轨和中轨之间 boolean isMaBullish = ma.getEma5().compareTo(ma.getEma10()) > 0 && ma.getEma10().compareTo(ma.getEma20()) > 0; boolean isMacdGoldenCross = macd.getDif().compareTo(macd.getDea()) > 0; boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 && rsi.getRsi().compareTo(new BigDecimal(70)) < 0; boolean isPriceInUpperMid = currentPrice.compareTo(boll.getMid()) > 0 && currentPrice.compareTo(boll.getUpper()) < 0; if (isMaBullish && isMacdGoldenCross && isRsiNeutral && isPriceInUpperMid) { return Direction.LONG; } // 检查做空方向条件:MA空头排列 + MACD死叉 + RSI中性(30-70) + BOLL价格在下轨和中轨之间 boolean isMaBearish = ma.getEma5().compareTo(ma.getEma10()) < 0 && ma.getEma10().compareTo(ma.getEma20()) < 0; boolean isMacdDeathCross = macd.getDif().compareTo(macd.getDea()) < 0; boolean isPriceInLowerMid = currentPrice.compareTo(boll.getLower()) > 0 && currentPrice.compareTo(boll.getMid()) < 0; if (isMaBearish && isMacdDeathCross && isRsiNeutral && isPriceInLowerMid) { return Direction.SHORT; } // 如果没有明确方向,默认为震荡 return Direction.RANGING; } /** * 根据用户要求检查是否应该开多仓位 * 条件:MA金叉 + MACD金叉 + KDJ金叉 + RSI中性 + 价格高于BOLL中轨 + 多周期确认 + 成交量验证 * @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金叉 (5EMA > 20EMA) boolean isMaGoldenCross = ma.getEma5().compareTo(ma.getEma20()) > 0; // MACD金叉 (DIF > DEA) boolean isMacdGoldenCross = macd.getDif().compareTo(macd.getDea()) > 0; // KDJ金叉 (K线上穿D线) boolean isKdjGoldenCross = kdj.isGoldenCross(); // RSI中性 (30-70) boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 && rsi.getRsi().compareTo(new BigDecimal(70)) < 0; // 价格高于BOLL中轨 boolean isPriceAboveBollMid = currentPrice.compareTo(boll.getMid()) > 0; // 成交量验证 boolean isVolumeConfirmed = volumeConfirm(volume); // 量价背离检测 boolean isPriceVolumeDivergence = hasPriceVolumeDivergence(prices, volume); // 多周期确认 boolean isMultiTimeframeConfirmed = multiTimeframeConfirm(fiveMinPrices, oneHourPrices, fourHourPrices); return isMaGoldenCross && isMacdGoldenCross && isKdjGoldenCross && isRsiNeutral && isPriceAboveBollMid && isVolumeConfirmed && !isPriceVolumeDivergence && isMultiTimeframeConfirmed; } /** * 根据用户要求检查是否应该开空仓位 * 条件:MA死叉 + MACD死叉 + KDJ死叉 + RSI中性 + 价格低于BOLL中轨 + 多周期确认 + 成交量验证 * @param currentPrice 当前价格 * @param volume 成交量列表 * @param fiveMinPrices 5分钟价格数据 * @param oneHourPrices 1小时价格数据 * @param fourHourPrices 4小时价格数据 * @return 是否应该开空 */ private boolean shouldOpenShort(BigDecimal currentPrice, List volume, List fiveMinPrices, List oneHourPrices, List fourHourPrices) { // MA死叉 (5EMA < 20EMA) boolean isMaDeathCross = ma.getEma5().compareTo(ma.getEma20()) < 0; // MACD死叉 (DIF < DEA) boolean isMacdDeathCross = macd.getDif().compareTo(macd.getDea()) < 0; // KDJ死叉 (K线下穿D线) boolean isKdjDeathCross = kdj.isDeathCross(); // RSI中性 (30-70) boolean isRsiNeutral = rsi.getRsi().compareTo(new BigDecimal(30)) > 0 && rsi.getRsi().compareTo(new BigDecimal(70)) < 0; // 价格低于BOLL中轨 boolean isPriceBelowBollMid = currentPrice.compareTo(boll.getMid()) < 0; // 成交量验证 boolean isVolumeConfirmed = volumeConfirm(volume); // 多周期确认(看跌) boolean isMultiTimeframeConfirmed = multiTimeframeBearishConfirm(fiveMinPrices, oneHourPrices, fourHourPrices); return isMaDeathCross && isMacdDeathCross && isKdjDeathCross && isRsiNeutral && isPriceBelowBollMid && isVolumeConfirmed && isMultiTimeframeConfirmed; } /** * 根据用户要求检查是否应该平多仓位 * 条件:MA死叉 + MACD死叉 + RSI超买 + 价格低于BOLL中轨 + 多周期确认 * @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) { // MA死叉 (5EMA < 20EMA) boolean isMaDeathCross = ma.getEma5().compareTo(ma.getEma20()) < 0; // MACD死叉 (DIF < DEA) boolean isMacdDeathCross = macd.getDif().compareTo(macd.getDea()) < 0; // RSI超买 (>70) boolean isRsiOverbought = rsi.isOverbought(); // 价格低于BOLL中轨 boolean isPriceBelowBollMid = currentPrice.compareTo(boll.getMid()) < 0; // 多周期确认(看跌) boolean isMultiTimeframeConfirmed = multiTimeframeBearishConfirm(fiveMinPrices, oneHourPrices, fourHourPrices); return isMaDeathCross && isMacdDeathCross && isRsiOverbought && isPriceBelowBollMid && isMultiTimeframeConfirmed; } /** * 根据用户要求检查是否应该平空仓位 * 条件:MA金叉 + MACD金叉 + RSI超卖 + 价格高于BOLL中轨 + 多周期确认 * @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) { // MA金叉 (5EMA > 20EMA) boolean isMaGoldenCross = ma.getEma5().compareTo(ma.getEma20()) > 0; // MACD金叉 (DIF > DEA) boolean isMacdGoldenCross = macd.getDif().compareTo(macd.getDea()) > 0; // RSI超卖 (<30) boolean isRsiOversold = rsi.isOversold(); // 价格高于BOLL中轨 boolean isPriceAboveBollMid = currentPrice.compareTo(boll.getMid()) > 0; // 多周期确认(看涨) boolean isMultiTimeframeConfirmed = multiTimeframeConfirm(fiveMinPrices, oneHourPrices, fourHourPrices); return isMaGoldenCross && isMacdGoldenCross && isRsiOversold && isPriceAboveBollMid && 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()); } /** * 计算动态杠杆倍数 * 杠杆倍数 = 基础杠杆 * (波动率阈值/当前波动率) * @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.debug("动态杠杆计算 - 基础杠杆: {}, 波动率阈值: {}, 当前波动率: {}, 计算杠杆: {}", 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.debug("黑天鹅事件过滤触发 - 资金费率异常: {}, 大额转账: {}, 即将发生重大事件: {}", 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; } } }