Administrator
7 hours ago 3bcc6918c362a7837f792ef91018a1fe043096ef
src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -15,6 +15,10 @@
import java.util.Collections;
import java.util.List;
import com.xcong.excoin.modules.gateApi.wsHandler.handler.CandlestickChannelHandler;
import com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionClosesChannelHandler;
import com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionsChannelHandler;
/**
 * Gate 网格交易服务 — 策略核心。
 *
@@ -108,10 +112,10 @@
    /** 空仓止盈队列,降序排列(大→小),仓位推送时消费 */
    private final List<BigDecimal> shortTakeProfitQueue = Collections.synchronizedList(new ArrayList<>());
    /** 当前多仓限价单 ID,用于取消旧单 */
    private volatile String currentLongOrderId;
    /** 当前空仓限价单 ID,用于取消旧单 */
    private volatile String currentShortOrderId;
    /** 当前多仓条件单 ID 集合,用于取消旧单 */
    private final List<String> currentLongOrderIds = Collections.synchronizedList(new ArrayList<>());
    /** 当前空仓条件单 ID 集合,用于取消旧单 */
    private final List<String> currentShortOrderIds = Collections.synchronizedList(new ArrayList<>());
    /** 基底空头入场价 */
    private BigDecimal shortBaseEntryPrice;
@@ -296,8 +300,8 @@
        longPriceQueue.clear();
        longTakeProfitQueue.clear();
        shortTakeProfitQueue.clear();
        currentLongOrderId = null;
        currentShortOrderId = null;
        currentLongOrderIds.clear();
        currentShortOrderIds.clear();
        log.info("[Gate] 网格策略已启动");
    }
@@ -515,11 +519,11 @@
            executor.placeConditionalEntryOrder(longPriceQueue.get(0),
                    FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
                    orderId -> { currentLongOrderId = orderId; log.info("[Gate] 初始条件多单已挂, id:{}, trigger:{}", orderId, longPriceQueue.get(0)); },
                    orderId -> { currentLongOrderIds.add(orderId); log.info("[Gate] 初始条件多单已挂, id:{}, trigger:{}", orderId, longPriceQueue.get(0)); },
                    null);
            executor.placeConditionalEntryOrder(shortPriceQueue.get(0),
                    FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
                    orderId -> { currentShortOrderId = orderId; log.info("[Gate] 初始条件空单已挂, id:{}, trigger:{}", orderId, shortPriceQueue.get(0)); },
                    orderId -> { currentShortOrderIds.add(orderId); log.info("[Gate] 初始条件空单已挂, id:{}, trigger:{}", orderId, shortPriceQueue.get(0)); },
                    null);
            state = StrategyState.ACTIVE;
@@ -642,27 +646,34 @@
        if (!isMarginSafe()) {
            log.warn("[Gate] 保证金超限,跳过挂条件单");
        } else {
            String oldLongId = currentLongOrderId;
            executor.cancelConditionalOrder(oldLongId);
            synchronized (currentLongOrderIds) {
                for (String id : currentLongOrderIds) {
                    executor.cancelConditionalOrder(id);
                }
                currentLongOrderIds.clear();
            }
            executor.placeConditionalEntryOrder(newShortFirst,
                    FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
                    orderId -> { currentShortOrderId = orderId; log.info("[Gate] 新条件空单, id:{}, trigger:{}", orderId, newShortFirst); },
                    orderId -> { currentShortOrderIds.add(orderId); log.info("[Gate] 新条件空单, id:{}, trigger:{}", orderId, newShortFirst); },
                    null);
            executor.placeConditionalEntryOrder(newLongFirst,
                    FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
                    orderId -> { currentLongOrderId = orderId; log.info("[Gate] 新条件多单, id:{}, trigger:{}", orderId, newLongFirst); },
                    orderId -> { currentLongOrderIds.add(orderId); log.info("[Gate] 新条件多单, id:{}, trigger:{}", orderId, newLongFirst); },
                    null);
            if (newShortFirst.compareTo(shortEntryPrice) > 0
                    && newShortFirst.compareTo(longEntryPrice) < 0) {
                BigDecimal reverseLongTp = newShortFirst.add(step).setScale(1, RoundingMode.HALF_UP);
                longTakeProfitQueue.add(reverseLongTp);
                longTakeProfitQueue.sort(BigDecimal::compareTo);
                executor.placeConditionalEntryOrder(newShortFirst,
                        FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
                        orderId -> { currentLongOrderIds.add(orderId); },
                        null);
                log.info("[Gate] 反向条件多单已挂, trigger:{}, size:{}, 止盈:{}", newShortFirst, config.getQuantity(), reverseLongTp);
            }
        }
        if (isMarginSafe()
                && shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
                && longEntryPrice.compareTo(BigDecimal.ZERO) > 0
                && longEntryPrice.compareTo(shortEntryPrice) > 0
                && currentPrice.compareTo(shortEntryPrice) > 0
                && currentPrice.compareTo(longEntryPrice) < 0) {
            executor.openLong(config.getQuantity(), null, null);
            log.info("[Gate] 额外反向开多, 当前价:{} 在[{},{}]之间", currentPrice, shortEntryPrice, longEntryPrice);
        }
    }
    /**
@@ -742,27 +753,34 @@
        if (!isMarginSafe()) {
            log.warn("[Gate] 保证金超限,跳过挂条件单");
        } else {
            String oldShortId = currentShortOrderId;
            executor.cancelConditionalOrder(oldShortId);
            synchronized (currentShortOrderIds) {
                for (String id : currentShortOrderIds) {
                    executor.cancelConditionalOrder(id);
                }
                currentShortOrderIds.clear();
            }
            executor.placeConditionalEntryOrder(newLongFirst,
                    FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
                    orderId -> { currentLongOrderId = orderId; log.info("[Gate] 新条件多单, id:{}, trigger:{}", orderId, newLongFirst); },
                    orderId -> { currentLongOrderIds.add(orderId); log.info("[Gate] 新条件多单, id:{}, trigger:{}", orderId, newLongFirst); },
                    null);
            executor.placeConditionalEntryOrder(newShortFirst,
                    FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
                    orderId -> { currentShortOrderId = orderId; log.info("[Gate] 新条件空单, id:{}, trigger:{}", orderId, newShortFirst); },
                    orderId -> { currentShortOrderIds.add(orderId); log.info("[Gate] 新条件空单, id:{}, trigger:{}", orderId, newShortFirst); },
                    null);
            if (newLongFirst.compareTo(shortEntryPrice) > 0
                    && newLongFirst.compareTo(longEntryPrice) < 0) {
                BigDecimal reverseShortTp = newLongFirst.subtract(step).setScale(1, RoundingMode.HALF_UP);
                shortTakeProfitQueue.add(reverseShortTp);
                shortTakeProfitQueue.sort((a, b) -> b.compareTo(a));
                executor.placeConditionalEntryOrder(newLongFirst,
                        FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
                        orderId -> { currentShortOrderIds.add(orderId); },
                        null);
                log.info("[Gate] 反向条件空单已挂, trigger:{}, size:{}, 止盈:{}", newLongFirst, negate(config.getQuantity()), reverseShortTp);
            }
        }
        if (isMarginSafe()
                && shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
                && longEntryPrice.compareTo(BigDecimal.ZERO) > 0
                && longEntryPrice.compareTo(shortEntryPrice) > 0
                && currentPrice.compareTo(shortEntryPrice) > 0
                && currentPrice.compareTo(longEntryPrice) < 0) {
            executor.openShort(negate(config.getQuantity()), null, null);
            log.info("[Gate] 额外反向开空, 当前价:{} 在[{},{}]之间", currentPrice, shortEntryPrice, longEntryPrice);
        }
    }
    // ---- 保证金安全阀 ----