From f55640b503ec7d40c72f7943b9227ae60452e1c9 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Mon, 18 May 2026 16:40:11 +0800
Subject: [PATCH] 第二个版本

---
 src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java       |  642 +++++++++++++++++++++++------
 src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java                |  372 ++++++++++++++++
 src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java                |  222 ++++++++++
 src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java |   42 
 src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java                 |   32 +
 src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java          |    7 
 6 files changed, 1,161 insertions(+), 156 deletions(-)

diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
index 094eaab..7153f7a 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
@@ -1,6 +1,8 @@
 package com.xcong.excoin.modules.gateApi;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Gate 模块统一配置。
@@ -92,6 +94,12 @@
     private final PnLPriceMode unrealizedPnlPriceMode;
     /** 网格绝对步长(shortBaseEntryPrice × gridRate),运行时由队列生成逻辑设置 */
     private BigDecimal step;
+    /** 网格元素列表,由队列初始化时同步填充,包含完整的多空仓挂单状态 */
+    private volatile List<GridElement> gridElements = new ArrayList<>();
+    /** 基座多头挂单参数,在基座成交后由 tryGenerateQueues 填充 */
+    private TraderParam baseLongTraderParam;
+    /** 基座空头挂单参数,在基座成交后由 tryGenerateQueues 填充 */
+    private TraderParam baseShortTraderParam;
 
     private GateConfig(Builder builder) {
         this.apiKey = builder.apiKey;
@@ -195,6 +203,28 @@
     /** 设置网格绝对步长(由 generateShortQueue 在运行时计算并注入) */
     public void setStep(BigDecimal step) { this.step = step; }
 
+    // ==================== 网格元素列表 ====================
+
+    /** @return 网格元素列表(队列初始化后填充),线程不安全,仅由策略线程单线程写入 */
+    public List<GridElement> getGridElements() { return gridElements; }
+    /** 设置网格元素列表(由队列生成逻辑写入),同时重建全局 ID 索引 */
+    public void setGridElements(List<GridElement> gridElements) {
+        this.gridElements = gridElements;
+        GridElement.rebuildIndex(gridElements);
+    }
+
+    // ==================== 基座挂单参数 ====================
+
+    /** @return 基座多头挂单参数 */
+    public TraderParam getBaseLongTraderParam() { return baseLongTraderParam; }
+    /** 设置基座多头挂单参数(由 tryGenerateQueues 在基座成交后填充) */
+    public void setBaseLongTraderParam(TraderParam baseLongTraderParam) { this.baseLongTraderParam = baseLongTraderParam; }
+
+    /** @return 基座空头挂单参数 */
+    public TraderParam getBaseShortTraderParam() { return baseShortTraderParam; }
+    /** 设置基座空头挂单参数(由 tryGenerateQueues 在基座成交后填充) */
+    public void setBaseShortTraderParam(TraderParam baseShortTraderParam) { this.baseShortTraderParam = baseShortTraderParam; }
+
     // ==================== 环境 ====================
 
     /** @return 是否为生产环境(true=实盘生产网 / false=模拟盘测试网) */
@@ -240,7 +270,7 @@
         /** 补仓最大重试次数,默认 3 */
         private int reopenMaxRetries = 3;
         /** 网格队列容量,默认 50 */
-        private int gridQueueSize = 50;
+        private int gridQueueSize = 300;
         /** 保证金占初始本金比例上限,默认 0.2(20%) */
         private BigDecimal marginRatioLimit = new BigDecimal("0.2");
         /** 合约乘数,默认 0.001 */
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
index 409f59c..6ffb218 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -360,15 +360,23 @@
             return;
         }
 
+        //初始化0位置的开仓,并且用空的开仓价格,作为价格基准来划分网格
         if (state == StrategyState.WAITING_KLINE) {
             state = StrategyState.OPENING;
             log.info("[Gate] 首根K线到达,开基底仓位...");
             executor.openLong(config.getQuantity(), (orderId) -> {
-                log.info("[Gate] 基底多单已提交{}", orderId);
+                TraderParam baseLongTp = TraderParam.builder()
+                        .entryOrderId(orderId)
+                        .build();
+                config.setBaseLongTraderParam(baseLongTp);
             }, null);
             executor.openShort(negate(config.getQuantity()), (orderId) -> {
-                log.info("[Gate] 基底空单已提交{}",orderId);
+                TraderParam baseShortTp = TraderParam.builder()
+                        .entryOrderId(orderId)
+                        .build();
+                config.setBaseShortTraderParam(baseShortTp);
             }, null);
+
             return;
         }
 
@@ -422,32 +430,12 @@
                     baseLongOpened = true;
                     log.info("[Gate] 基底多成交价: {}", longBaseEntryPrice);
                     tryGenerateQueues();
-                } else if(size.compareTo(longPositionSize) < 0){
-                    if (entryPrice.compareTo(shortEntryPrice) > 0
-                            && entryPrice.compareTo(longEntryPrice) < 0
-                            && shortPositionSize.compareTo(new BigDecimal("3")) < 0) {
-
-                        BigDecimal reverseShortTp = entryPrice.subtract(config.getStep()).setScale(1, RoundingMode.HALF_UP);
-                        executor.openShort(negate(config.getQuantity()),
-                                orderId -> { currentShortOrderIds.put(orderId, reverseShortTp);},
-                               null);
-                        log.info("[Gate] 反向条件空单已挂, trigger:{}, size:{}, 止盈:{}", entryPrice, negate(config.getQuantity()), reverseShortTp);
-                    }
-                } else {
+                }else {
                     longPositionSize = size;
                 }
             } else {
                 longActive = false;
                 longPositionSize = BigDecimal.ZERO;
-            }
-            synchronized (currentLongOrderIds) {
-                if (currentLongOrderIds.size() > 5) {
-                    Iterator<String> it = currentLongOrderIds.keySet().iterator();
-                    for (int i = 0, remove = currentLongOrderIds.size() - 5; i < remove; i++) {
-                        it.next();
-                        it.remove();
-                    }
-                }
             }
         } else if (Position.ModeEnum.DUAL_SHORT == mode) {
             if (hasPosition) {
@@ -459,32 +447,12 @@
                     baseShortOpened = true;
                     log.info("[Gate] 基底空成交价: {}", shortBaseEntryPrice);
                     tryGenerateQueues();
-                } else if(size.abs().compareTo(shortPositionSize) < 0){
-                    if (entryPrice.compareTo(shortEntryPrice) > 0
-                            && entryPrice.compareTo(longEntryPrice) < 0
-                            && longPositionSize.compareTo(new BigDecimal("3")) < 0) {
-
-                        BigDecimal reverseLongTp = entryPrice.add(config.getStep()).setScale(1, RoundingMode.HALF_UP);
-                        executor.openLong(config.getQuantity(),
-                                orderId -> { currentLongOrderIds.put(orderId, reverseLongTp);},
-                                null);
-                        log.info("[Gate] 反向条件多单已挂, trigger:{}, size:{}, 止盈:{}", entryPrice, negate(config.getQuantity()), reverseLongTp);
-                    }
-                } else {
+                }else {
                     shortPositionSize = size.abs();
                 }
             } else {
                 shortActive = false;
                 shortPositionSize = BigDecimal.ZERO;
-            }
-            synchronized (currentShortOrderIds) {
-                if (currentShortOrderIds.size() > 5) {
-                    Iterator<String> it = currentShortOrderIds.keySet().iterator();
-                    for (int i = 0, remove = currentShortOrderIds.size() - 5; i < remove; i++) {
-                        it.next();
-                        it.remove();
-                    }
-                }
             }
         }
     }
@@ -536,18 +504,84 @@
         if (!"finished".equals(status) || !"filled".equals(finishAs)) {
             return;
         }
-        BigDecimal longTp = currentLongOrderIds.remove(orderId);
-        if (longTp != null) {
-            executor.placeTakeProfit(longTp,
-                    FuturesPriceTrigger.RuleEnum.NUMBER_1, ORDER_TYPE_CLOSE_LONG, negate(config.getQuantity()));
-            log.info("[Gate] 多单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, longTp, negate(config.getQuantity()));
-            return;
+
+        /**
+         * 匹配止盈单止盈
+         */
+        GridElement byLongTakeProfitOrderId = GridElement.findByLongTakeProfitOrderId(orderId);
+        if (byLongTakeProfitOrderId != null){
+            longTakeProfitTraderIdParam(
+                    byLongTakeProfitOrderId,
+                    null,
+                    false
+            );
+            longEntryTraderIdParam(
+                    byLongTakeProfitOrderId,
+                    null,
+                    false
+            );
         }
-        BigDecimal shortTp = currentShortOrderIds.remove(orderId);
-        if (shortTp != null) {
-            executor.placeTakeProfit(shortTp,
-                    FuturesPriceTrigger.RuleEnum.NUMBER_2, ORDER_TYPE_CLOSE_SHORT, config.getQuantity());
-            log.info("[Gate] 空单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, shortTp, config.getQuantity());
+        GridElement byShortTakeProfitOrderId = GridElement.findByShortTakeProfitOrderId(orderId);
+        if (byShortTakeProfitOrderId != null){
+            shortTakeProfitTraderIdParam(
+                    byLongTakeProfitOrderId,
+                    null,
+                    false
+            );
+            shortEntryTraderIdParam(
+                    byLongTakeProfitOrderId,
+                    null,
+                    false
+            );
+        }
+
+        /**
+         * 匹配挂单
+         */
+        GridElement longGridElement = GridElement.findByLongOrderId(orderId);
+        if (longGridElement != null) {
+            if (longGridElement.isHasLongOrder()){
+                if (longGridElement.getLongTakeProfitOrderId() == null){
+                    BigDecimal longTp = longGridElement.getLongTraderParam().getTakeProfitPrice();
+                    if (longTp != null) {
+                        executor.placeTakeProfit(longTp,
+                                FuturesPriceTrigger.RuleEnum.NUMBER_1,
+                                ORDER_TYPE_CLOSE_LONG,
+                                negate(config.getQuantity()),
+                                (profitId) -> {
+                                    longTakeProfitTraderIdParam(
+                                            longGridElement,
+                                            profitId,
+                                            true
+                                    );
+                                });
+                        log.info("[Gate] 多单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, longTp, negate(config.getQuantity()));
+                        return;
+                    }
+                }
+            }
+        }
+        GridElement shortGridElement = GridElement.findByShortOrderId(orderId);
+        if (shortGridElement != null) {
+            if (shortGridElement.isHasShortOrder()){
+                if (shortGridElement.getShortTakeProfitOrderId() == null){
+                    BigDecimal shortTp = shortGridElement.getShortTraderParam().getTakeProfitPrice();
+                    if (shortTp != null) {
+                        executor.placeTakeProfit(shortTp,
+                                FuturesPriceTrigger.RuleEnum.NUMBER_2,
+                                ORDER_TYPE_CLOSE_SHORT,
+                                config.getQuantity(),
+                                (profitId) -> {
+                                    shortTakeProfitTraderIdParam(
+                                            shortGridElement,
+                                            profitId,
+                                            true
+                                    );
+                                });
+                        log.info("[Gate] 空单成交匹配止盈, orderId:{}, 止盈价:{}, size:{}", orderId, shortTp, config.getQuantity());
+                    }
+                }
+            }
         }
     }
 
@@ -567,33 +601,135 @@
      */
     private void tryGenerateQueues() {
         if (baseLongOpened && baseShortOpened) {
+            //初始化空仓队列
             generateShortQueue();
+            //初始化多仓队列
             generateLongQueue();
+            //初始化网格数据
+            updateGridElements();
 
-            BigDecimal step = config.getStep();
+            /**
+             * 挂初始位置多空仓条件单
+             * 0位置的多单止盈
+             * 0位置的空单止盈
+             */
+            GridElement baseGridElement = GridElement.findById(0);
+            TraderParam baseLongTraderParam = config.getBaseLongTraderParam();
+            baseGridElement.setLongOrderId(baseLongTraderParam.getEntryOrderId());
+            //0位置的网格的多单止盈
+            BigDecimal upTakeProfitPrice = baseGridElement.getLongTraderParam().getTakeProfitPrice();
+            executor.placeTakeProfit(
+                    upTakeProfitPrice,
+                    FuturesPriceTrigger.RuleEnum.NUMBER_1,
+                    ORDER_TYPE_CLOSE_LONG,
+                    negate(config.getQuantity()),
+                    profitId -> {
+                        longTakeProfitTraderIdParam(
+                                baseGridElement,
+                                profitId,
+                                true
+                        );
+                    }
+            );
+            //0位置的网格的空单止盈
+            TraderParam baseShortTraderParam = config.getBaseShortTraderParam();
+            baseGridElement.setShortOrderId(baseShortTraderParam.getEntryOrderId());
+            BigDecimal downTakeProfitPrice = baseGridElement.getShortTraderParam().getTakeProfitPrice();
+            executor.placeTakeProfit(
+                    downTakeProfitPrice,
+                    FuturesPriceTrigger.RuleEnum.NUMBER_2,
+                    ORDER_TYPE_CLOSE_SHORT,
+                    config.getQuantity(),
+                    profitId -> {
+                        shortTakeProfitTraderIdParam(
+                                baseGridElement,
+                                profitId,
+                                true
+                        );
+                    }
+            );
 
-            BigDecimal longPriceQueueOne = longPriceQueue.get(0);
-            BigDecimal longTp = longPriceQueueOne.add(step).setScale(1, RoundingMode.HALF_UP);
-            executor.placeConditionalEntryOrder(longPriceQueueOne,
-                    FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
-                    orderId -> { currentLongOrderIds.put(orderId, longTp); log.info("[Gate] 初始条件多单已挂, id:{}, trigger:{}, 止盈:{}", orderId, longPriceQueue.get(0), longTp); },
+            /**
+             * 挂初始位置的up位置的多单
+             * 挂初始位置的down位置的空单
+             */
+            Integer upId = baseGridElement.getUpId();
+            GridElement upGridElementOne = GridElement.findById(upId);
+            BigDecimal longTp = upGridElementOne.getGridPrice();
+            executor.placeConditionalEntryOrder(
+                    longTp,
+                    FuturesPriceTrigger.RuleEnum.NUMBER_1,
+                    config.getQuantity(),
+                    orderId -> {
+                        longEntryTraderIdParam(
+                                upGridElementOne,
+                                orderId,
+                                true
+                        );
+                    },
+                    null);
+            Integer downId = baseGridElement.getDownId();
+            GridElement downGridElementOne = GridElement.findById(downId);
+            BigDecimal shortTp = downGridElementOne.getGridPrice();
+            executor.placeConditionalEntryOrder(
+                    shortTp,
+                    FuturesPriceTrigger.RuleEnum.NUMBER_2,
+                    negate(config.getQuantity()),
+                    orderId -> {
+                        shortEntryTraderIdParam(
+                                downGridElementOne,
+                                orderId,
+                                true
+                        );
+                    },
                     null);
 
-
-            BigDecimal shortPriceQueueOne = shortPriceQueue.get(0);
-            BigDecimal shortTp = shortPriceQueueOne.subtract(step).setScale(1, RoundingMode.HALF_UP);
-            executor.placeConditionalEntryOrder(shortPriceQueueOne,
-                    FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
-                    orderId -> { currentShortOrderIds.put(orderId, shortTp); log.info("[Gate] 初始条件空单已挂, id:{}, trigger:{}, 止盈:{}", orderId, shortPriceQueue.get(0), shortTp); },
-                    null);
-
-
-            log.info("[Gate] 网格队列已生成, 空队首:{} → 尾:{}, 多队首:{} → 尾:{}, step:{}, 已激活",
-                    shortPriceQueueOne, shortPriceQueue.get(shortPriceQueue.size() - 1),
-                    longPriceQueueOne, longPriceQueue.get(longPriceQueue.size() - 1),
-                    step);
             state = StrategyState.ACTIVE;
         }
+    }
+
+    /**
+     * 更新基座止盈信息,将止盈价、订单ID等写入 TraderParam 并回填到 ID=0 的网格元素中。
+     */
+    private void longTakeProfitTraderIdParam(
+            GridElement baseElement,String profitId, boolean flag
+    ) {
+        TraderParam tp = baseElement.getLongTraderParam();
+        tp.setTakeProfitOrderId(profitId);
+        tp.setTakeProfitPlaced(flag);
+        baseElement.setLongTakeProfitOrderId(profitId);
+        GridElement.refreshIndices();
+    }
+    private void shortTakeProfitTraderIdParam(
+            GridElement baseElement,String profitId, boolean flag
+    ) {
+        TraderParam tp = baseElement.getShortTraderParam();
+        tp.setTakeProfitOrderId(profitId);
+        tp.setTakeProfitPlaced(flag);
+        baseElement.setShortTakeProfitOrderId(profitId);
+        GridElement.refreshIndices();
+    }
+
+    private void longEntryTraderIdParam(
+            GridElement baseElement,String entryId,boolean flag
+    ) {
+        TraderParam tp = baseElement.getLongTraderParam();
+        tp.setEntryOrderId(entryId);
+        tp.setEntryOrderPlaced(flag);
+        baseElement.setHasLongOrder(flag);
+        baseElement.setLongOrderId(entryId);
+        GridElement.refreshIndices();
+    }
+
+    private void shortEntryTraderIdParam(
+            GridElement baseElement, String entryId, boolean flag
+    ) {
+        TraderParam tp = baseElement.getShortTraderParam();
+        tp.setEntryOrderId(entryId);
+        tp.setEntryOrderPlaced(flag);
+        baseElement.setHasShortOrder(flag);
+        baseElement.setShortOrderId(entryId);
+        GridElement.refreshIndices();
     }
 
     /**
@@ -607,10 +743,13 @@
         BigDecimal step = shortBaseEntryPrice.multiply(config.getGridRate()).setScale(1, RoundingMode.HALF_UP);
         config.setStep(step);
         BigDecimal elem = shortBaseEntryPrice.subtract(step).setScale(1, RoundingMode.HALF_UP);
-        for (int i = 0; i < config.getGridQueueSize(); i++) {
-            shortPriceQueue.add(elem);
-            elem = elem.subtract(step).setScale(1, RoundingMode.HALF_UP);
-        }
+            for (int i = 0; i < config.getGridQueueSize(); i++) {
+                shortPriceQueue.add(elem);
+                elem = elem.subtract(step).setScale(1, RoundingMode.HALF_UP);
+                if (elem.compareTo(BigDecimal.ZERO) <= 0) {
+                    break;
+                }
+            }
         shortPriceQueue.sort((a, b) -> b.compareTo(a));
         log.info("[Gate] 空队列:{}", shortPriceQueue);
     }
@@ -630,6 +769,112 @@
         }
         longPriceQueue.sort(BigDecimal::compareTo);
         log.info("[Gate] 多队列:{}", longPriceQueue);
+    }
+
+    /**
+     * 根据当前多空价格队列同步构建网格元素列表,写入 config。
+     *
+     * <h3>ID 分配规则</h3>
+     * <ul>
+     *   <li>空仓队列:id 从 -1 自减(-1, -2, -3...),第一个元素 upId=0,最后一个 downId=null</li>
+     *   <li>位置 0:gridPrice=shortBaseEntryPrice,upId=-1,downId=1,其数据在基座开仓时更新</li>
+     *   <li>多仓队列:id 从 1 自增(1, 2, 3...),第一个元素 upId=0,最后一个 downId=null</li>
+     * </ul>
+     *
+     * <h3>链表关系</h3>
+     * 所有元素通过 upId/downId 串成一条双向链表:
+     * ... → -3 → -2 → -1 → 0 → 1 → 2 → 3 → ...
+     */
+    private void updateGridElements() {
+        List<GridElement> elements = new ArrayList<>();
+        int shortSize = shortPriceQueue.size();
+        int longSize = longPriceQueue.size();
+        BigDecimal step = config.getStep().subtract(config.getContractMultiplier());
+        String qty = config.getQuantity();
+
+        // 空仓队列:id 从 -1 自减, shortPriceQueue[i] → id=-(i+1)
+        for (int i = 0; i < shortSize; i++) {
+            int id = -(i + 1);
+            Integer upId = (i == 0) ? 0 : id + 1;
+            Integer downId = (i == shortSize - 1) ? null : id - 1;
+            BigDecimal price = shortPriceQueue.get(i);
+            TraderParam longParam = TraderParam.builder()
+                    .direction(TraderParam.Direction.LONG)
+                    .entryPrice(price)
+                    .takeProfitPrice(price.add(step).setScale(1, RoundingMode.HALF_UP))
+                    .quantity(qty)
+                    .build();
+            TraderParam shortParam = TraderParam.builder()
+                    .direction(TraderParam.Direction.SHORT)
+                    .entryPrice(price)
+                    .takeProfitPrice(price.subtract(step).setScale(1, RoundingMode.HALF_UP))
+                    .quantity(qty)
+                    .build();
+            elements.add(GridElement.builder()
+                    .id(id)
+                    .gridPrice(price)
+                    .upId(upId)
+                    .downId(downId)
+                    .longTraderParam(longParam)
+                    .shortTraderParam(shortParam)
+                    .build());
+        }
+
+        // 位置 0:基底价格,数据在基座开仓时更新
+        {
+            BigDecimal price = shortBaseEntryPrice;
+            TraderParam longParam = TraderParam.builder()
+                    .direction(TraderParam.Direction.LONG)
+                    .entryPrice(price)
+                    .takeProfitPrice(price.add(step).setScale(1, RoundingMode.HALF_UP))
+                    .quantity(qty)
+                    .build();
+            TraderParam shortParam = TraderParam.builder()
+                    .direction(TraderParam.Direction.SHORT)
+                    .entryPrice(price)
+                    .takeProfitPrice(price.subtract(step).setScale(1, RoundingMode.HALF_UP))
+                    .quantity(qty)
+                    .build();
+            elements.add(GridElement.builder()
+                    .id(0)
+                    .gridPrice(price)
+                    .upId(shortSize > 0 ? -1 : null)
+                    .downId(longSize > 0 ? 1 : null)
+                    .longTraderParam(longParam)
+                    .shortTraderParam(shortParam)
+                    .build());
+        }
+
+        // 多仓队列:id 从 1 自增, longPriceQueue[i] → id=i+1
+        for (int i = 0; i < longSize; i++) {
+            int id = i + 1;
+            Integer upId = (i == 0) ? 0 : id - 1;
+            Integer downId = (i == longSize - 1) ? null : id + 1;
+            BigDecimal price = longPriceQueue.get(i);
+            TraderParam longParam = TraderParam.builder()
+                    .direction(TraderParam.Direction.LONG)
+                    .entryPrice(price)
+                    .takeProfitPrice(price.add(step).setScale(1, RoundingMode.HALF_UP))
+                    .quantity(qty)
+                    .build();
+            TraderParam shortParam = TraderParam.builder()
+                    .direction(TraderParam.Direction.SHORT)
+                    .entryPrice(price)
+                    .takeProfitPrice(price.subtract(step).setScale(1, RoundingMode.HALF_UP))
+                    .quantity(qty)
+                    .build();
+            elements.add(GridElement.builder()
+                    .id(id)
+                    .gridPrice(price)
+                    .upId(upId)
+                    .downId(downId)
+                    .longTraderParam(longParam)
+                    .shortTraderParam(shortParam)
+                    .build());
+        }
+
+        config.setGridElements(elements);
+        log.info("[Gate] 网格元素列表已构建, 共{}个元素 (空仓:{} 位置:0 多仓:{})", elements.size(), shortSize, longSize);
     }
 
     /**
@@ -683,39 +928,105 @@
             shortPriceQueue.sort((a, b) -> b.compareTo(a));
         }
 
-//        synchronized (longPriceQueue) {
-//            BigDecimal first = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(0);
-//            BigDecimal gridStep = config.getStep();
-//            for (int i = 1; i <= matched.size(); i++) {
-//                BigDecimal elem = first.subtract(gridStep.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP);
-//                longPriceQueue.add(elem);
-//            }
-//            longPriceQueue.sort(BigDecimal::compareTo);
-//            while (longPriceQueue.size() > config.getGridQueueSize()) {
-//                longPriceQueue.remove(longPriceQueue.size() - 1);
-//            }
-//        }
+        synchronized (longPriceQueue) {
+            BigDecimal first = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(0);
+            BigDecimal gridStep = config.getStep();
+            for (int i = 1; i <= matched.size(); i++) {
+                BigDecimal elem = first.subtract(gridStep.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP);
+                longPriceQueue.add(elem);
+            }
+            longPriceQueue.sort(BigDecimal::compareTo);
+            while (longPriceQueue.size() > config.getGridQueueSize()) {
+                longPriceQueue.remove(longPriceQueue.size() - 1);
+            }
+        }
 
         if (!isMarginSafe()) {
             log.warn("[Gate] 保证金超限,跳过挂条件单");
         } else {
 
-            BigDecimal newShortFirst = shortPriceQueue.get(0);
-            BigDecimal step = config.getStep();
-            BigDecimal stpElem = newShortFirst.subtract(step).setScale(1, RoundingMode.HALF_UP);
-            executor.placeConditionalEntryOrder(newShortFirst,
-                    FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
-                    orderId -> { currentShortOrderIds.put(orderId, stpElem); log.info("[Gate] 新条件空单, id:{}, trigger:{}, 止盈:{}", orderId, newShortFirst, stpElem); },
-                    null);
+            /**
+             * 下一个开仓位置
+             *      获取队列第一个元素的价格对应的网格
+             *      判断网格是否能开空仓,如果不能则跳过
+             *      前进方向挂空仓条件单
+             *      后置方向挂多空条件单
+             */
+            //下一个开仓位置
+            BigDecimal newLongFirst = shortPriceQueue.get(0);
+            GridElement UpGridElement = GridElement.findByPrice(newLongFirst);
 
-            BigDecimal newLongFirst = newShortFirst.add( step.multiply(new BigDecimal("2")));
-            if (newLongFirst.compareTo(longEntryPrice) < 0) {
+            // 判断网格是否能开空仓,如果不能则跳过
+            if (UpGridElement != null) {
 
-                BigDecimal ltpElem = newLongFirst.add(step).setScale(1, RoundingMode.HALF_UP);
-                executor.placeConditionalEntryOrder(newLongFirst,
-                        FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
-                        orderId -> { currentLongOrderIds.put(orderId, ltpElem); log.info("[Gate] 新条件多单, id:{}, trigger:{}, 止盈:{}", orderId, newLongFirst, ltpElem); },
-                        null);
+                if (!UpGridElement.isHasShortOrder()) {
+
+                    //挂空仓条件单
+                    TraderParam upShortTraderParam = UpGridElement.getShortTraderParam();
+                    executor.placeConditionalEntryOrder(
+                            upShortTraderParam.getEntryPrice(),
+                            FuturesPriceTrigger.RuleEnum.NUMBER_2,
+                            negate(upShortTraderParam.getQuantity()),
+                            orderId ->
+                            {
+                                shortEntryTraderIdParam(
+                                        UpGridElement,
+                                        orderId,
+                                        true
+                                );
+                            },
+                            null
+                    );
+                }
+            }
+
+
+
+            int i = UpGridElement.getId() + 2;
+            GridElement downGridElement = GridElement.findById(i);
+            if (downGridElement != null){
+
+                TraderParam downLongTraderParam = downGridElement.getLongTraderParam();
+                if (!downGridElement.isHasShortOrder()){
+                    executor.placeConditionalEntryOrder(
+                            downLongTraderParam.getEntryPrice(),
+                            FuturesPriceTrigger.RuleEnum.NUMBER_1,
+                            downLongTraderParam.getQuantity(),
+                            orderId ->
+                            {
+                                longEntryTraderIdParam(
+                                        downGridElement,
+                                        orderId,
+                                        true
+                                );
+                            },
+                            null
+                    );
+                }
+
+                TraderParam downShortTraderParam = downGridElement.getShortTraderParam();
+                BigDecimal downGridPrice = downGridElement.getGridPrice();
+                if (
+                        !downGridElement.isHasShortOrder() &&
+                                downGridPrice.compareTo(longEntryPrice) <= 0 &&
+                                downGridPrice.compareTo(shortEntryPrice) >= 0
+                ){
+                    executor.placeConditionalEntryOrder(
+                            downShortTraderParam.getEntryPrice(),
+                            FuturesPriceTrigger.RuleEnum.NUMBER_2,
+                            negate(downShortTraderParam.getQuantity()),
+                            orderId ->
+                            {
+                                shortEntryTraderIdParam(
+                                        downGridElement,
+                                        orderId,
+                                        true
+                                );
+                            },
+                            null
+                    );
+
+                }
             }
 
         }
@@ -763,6 +1074,11 @@
 
         log.info("[Gate] 多仓队列触发, 匹配{}个元素, 当前价:{}", matched.size(), currentPrice);
 
+        /**
+         * 匹配到元素后,
+         *  多仓队列更新
+         *  空仓队列更新
+         */
         synchronized (longPriceQueue) {
             longPriceQueue.removeAll(matched);
             BigDecimal max = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(longPriceQueue.size() - 1);
@@ -773,44 +1089,104 @@
             }
             longPriceQueue.sort(BigDecimal::compareTo);
         }
-
-//        synchronized (shortPriceQueue) {
-//            BigDecimal first = shortPriceQueue.isEmpty() ? matched.get(0) : shortPriceQueue.get(0);
-//            BigDecimal gridStep = config.getStep();
-//            for (int i = 1; i <= matched.size(); i++) {
-//                BigDecimal elem = first.add(gridStep.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP);
-//                shortPriceQueue.add(elem);
-//            }
-//            shortPriceQueue.sort((a, b) -> b.compareTo(a));
-//            while (shortPriceQueue.size() > config.getGridQueueSize()) {
-//                shortPriceQueue.remove(shortPriceQueue.size() - 1);
-//            }
-//        }
-
-
+        synchronized (shortPriceQueue) {
+            BigDecimal first = shortPriceQueue.isEmpty() ? matched.get(0) : shortPriceQueue.get(0);
+            BigDecimal gridStep = config.getStep();
+            for (int i = 1; i <= matched.size(); i++) {
+                BigDecimal elem = first.add(gridStep.multiply(BigDecimal.valueOf(i))).setScale(1, RoundingMode.HALF_UP);
+                shortPriceQueue.add(elem);
+            }
+            shortPriceQueue.sort((a, b) -> b.compareTo(a));
+            while (shortPriceQueue.size() > config.getGridQueueSize()) {
+                shortPriceQueue.remove(shortPriceQueue.size() - 1);
+            }
+        }
 
         if (!isMarginSafe()) {
             log.warn("[Gate] 保证金超限,跳过挂条件单");
         } else {
 
-            BigDecimal step = config.getStep();
-
+            /**
+             * 下一个开仓位置
+             *      获取队列第一个元素的价格对应的网格
+             *      判断网格是否能开多仓,如果不能则跳过
+             *      前进方向挂多仓条件单
+             *      后置方向挂多空条件单
+             */
+            //下一个开仓位置
             BigDecimal newLongFirst = longPriceQueue.get(0);
-            BigDecimal ltpElem = newLongFirst.add(step).setScale(1, RoundingMode.HALF_UP);
-            executor.placeConditionalEntryOrder(newLongFirst,
-                    FuturesPriceTrigger.RuleEnum.NUMBER_1, config.getQuantity(),
-                    orderId -> { currentLongOrderIds.put(orderId, ltpElem); log.info("[Gate] 新条件多单, id:{}, trigger:{}, 止盈:{}", orderId, newLongFirst, ltpElem); },
-                    null);
+            GridElement UpGridElement = GridElement.findByPrice(newLongFirst);
+
+            // 判断网格是否能开多仓,如果不能则跳过
+            if (UpGridElement != null) {
+
+                if (!UpGridElement.isHasLongOrder()) {
+                    //挂多仓条件单
+                    TraderParam upLongTraderParam = UpGridElement.getLongTraderParam();
+                    executor.placeConditionalEntryOrder(
+                            upLongTraderParam.getEntryPrice(),
+                            FuturesPriceTrigger.RuleEnum.NUMBER_1,
+                            config.getQuantity(),
+                            orderId ->
+                            {
+                                longEntryTraderIdParam(
+                                        UpGridElement,
+                                        orderId,
+                                        true
+                                );
+                            },
+                            null
+                    );
+                }
+            }
 
 
-            BigDecimal newShortFirst = newLongFirst.subtract( step.multiply(new BigDecimal("2")));
-            if (newShortFirst.compareTo(shortEntryPrice) > 0){
 
-                BigDecimal stpElem = newShortFirst.subtract(step).setScale(1, RoundingMode.HALF_UP);
-                executor.placeConditionalEntryOrder(newShortFirst,
-                        FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(config.getQuantity()),
-                        orderId -> { currentShortOrderIds.put(orderId, stpElem); log.info("[Gate] 新条件空单, id:{}, trigger:{}, 止盈:{}", orderId, newShortFirst, stpElem); },
-                        null);
+            int i = UpGridElement.getId() - 2;
+            GridElement downGridElement = GridElement.findById(i);
+            if (downGridElement != null){
+
+                TraderParam shortTraderParam = downGridElement.getShortTraderParam();
+                if (!downGridElement.isHasShortOrder()){
+                    executor.placeConditionalEntryOrder(
+                            shortTraderParam.getEntryPrice(),
+                            FuturesPriceTrigger.RuleEnum.NUMBER_2,
+                            negate(config.getQuantity()),
+                            orderId ->
+                            {
+                                shortEntryTraderIdParam(
+                                        downGridElement,
+                                        orderId,
+                                        true
+                                );
+                            },
+                            null
+                    );
+                }
+
+                TraderParam downLongTraderParam = downGridElement.getLongTraderParam();
+                BigDecimal downGridPrice = downGridElement.getGridPrice();
+                if (
+                        !downGridElement.isHasLongOrder() &&
+                                downGridPrice.compareTo(longEntryPrice) <= 0 &&
+                                downGridPrice.compareTo(shortEntryPrice) >= 0
+                ){
+                    executor.placeConditionalEntryOrder(
+                            downLongTraderParam.getEntryPrice(),
+                            FuturesPriceTrigger.RuleEnum.NUMBER_1,
+                            config.getQuantity(),
+                            orderId ->
+                            {
+                                longEntryTraderIdParam(
+                                        downGridElement,
+                                        orderId,
+                                        true
+                                );
+                            },
+                            null
+                    );
+
+                }
             }
 
         }
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
index ee5151c..da78ba3 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
@@ -176,13 +176,18 @@
     public void placeTakeProfit(BigDecimal triggerPrice,
                                  FuturesPriceTrigger.RuleEnum rule,
                                  String orderType,
-                                 String size) {
+                                 String size,
+                                Consumer<String> onSuccess) {
         executor.execute(() -> {
             FuturesPriceTriggeredOrder order = buildTriggeredOrder(triggerPrice, rule, orderType, size);
             try {
                 TriggerOrderResponse response = futuresApi.createPriceTriggeredOrder(SETTLE, order);
                 log.info("[TradeExec] 止盈单已创建, 触发价:{}, 类型:{}, size:{}, id:{}",
                         triggerPrice, orderType, size, response.getId());
+                String orderId = String.valueOf(response.getId());
+                if (onSuccess != null) {
+                    onSuccess.accept(orderId);
+                }
             } catch (Exception e) {
                 log.error("[TradeExec] 止盈单创建失败, 触发价:{}, size:{}, 立即市价止盈", triggerPrice, size, e);
                 marketClose(size);
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
index e21b897..484d8ac 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
@@ -50,39 +50,39 @@
 
         try {
             //测试盘
-//            config = GateConfig.builder()
-//                    .apiKey("d90ca272391992b8e74f8f92cedb21ec")
-//                    .apiSecret("1861e4f52de4bb53369ea3208d9ede38ece4777368030f96c77d27934c46c274")
-//                    .contract("ETH_USDT")
-//                    .leverage("100")
-//                    .marginMode("CROSS")
-//                    .positionMode("dual")
-//                    .gridRate(new BigDecimal("0.003"))
-//                    .overallTp(new BigDecimal("5"))
-//                    .maxLoss(new BigDecimal("15"))
-//                    .quantity("1")
-//                    .contractMultiplier(new BigDecimal("0.01"))
-//                    .unrealizedPnlPriceMode(GateConfig.PnLPriceMode.LAST_PRICE)
-//                    .isProduction(false)
-//                    .reopenMaxRetries(3)
-//                    .build();
-            //实盘
             config = GateConfig.builder()
-                    .apiKey("865371cdaccd5d238aceb06a55f0143a")
-                    .apiSecret("49589c30dfdc3acba007eed445a94990c4b0aa5faac9843e32defdd7371f5a50")
+                    .apiKey("d90ca272391992b8e74f8f92cedb21ec")
+                    .apiSecret("1861e4f52de4bb53369ea3208d9ede38ece4777368030f96c77d27934c46c274")
                     .contract("ETH_USDT")
                     .leverage("100")
                     .marginMode("CROSS")
                     .positionMode("dual")
-                    .gridRate(new BigDecimal("0.005"))
+                    .gridRate(new BigDecimal("0.002"))
                     .overallTp(new BigDecimal("5"))
                     .maxLoss(new BigDecimal("15"))
                     .quantity("1")
                     .contractMultiplier(new BigDecimal("0.01"))
                     .unrealizedPnlPriceMode(GateConfig.PnLPriceMode.LAST_PRICE)
-                    .isProduction(true)
+                    .isProduction(false)
                     .reopenMaxRetries(3)
                     .build();
+            //实盘
+//            config = GateConfig.builder()
+//                    .apiKey("865371cdaccd5d238aceb06a55f0143a")
+//                    .apiSecret("49589c30dfdc3acba007eed445a94990c4b0aa5faac9843e32defdd7371f5a50")
+//                    .contract("ETH_USDT")
+//                    .leverage("100")
+//                    .marginMode("CROSS")
+//                    .positionMode("dual")
+//                    .gridRate(new BigDecimal("0.005"))
+//                    .overallTp(new BigDecimal("5"))
+//                    .maxLoss(new BigDecimal("15"))
+//                    .quantity("1")
+//                    .contractMultiplier(new BigDecimal("0.01"))
+//                    .unrealizedPnlPriceMode(GateConfig.PnLPriceMode.LAST_PRICE)
+//                    .isProduction(true)
+//                    .reopenMaxRetries(3)
+//                    .build();
 
             // 1. 初始化交易服务:查用户ID → 切持仓模式 → 清条件单 → 平已有仓位 → 设杠杆
             gridTradeService = new GateGridTradeService(config);
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java b/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java
new file mode 100644
index 0000000..e34f80c
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java
@@ -0,0 +1,372 @@
+package com.xcong.excoin.modules.gateApi;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 网格元素,表示网格交易策略中的一个价格层级。
+ *
+ * <p>每个网格层级包含该价格位置上的多仓和空仓挂单信息,
+ * 通过编号和网格价格唯一标识一个网格层级。
+ *
+ * <h3>关键字段</h3>
+ * <ul>
+ *   <li><b>编号</b>:网格层级的唯一标识</li>
+ *   <li><b>网格价格</b>:该层级对应的触发价格</li>
+ *   <li><b>多仓挂单</b>:是否已有多头挂单、多头挂单参数</li>
+ *   <li><b>空仓挂单</b>:是否有空头挂单、空头挂单参数</li>
+ * </ul>
+ *
+ * <h3>使用示例</h3>
+ * <pre>
+ *   GridElement element = GridElement.builder()
+ *       .id(1)
+ *       .gridPrice(new BigDecimal("2300.0"))
+ *       .build();
+ *
+ *   // 挂多仓单
+ *   TraderParam longParam = TraderParam.builder()
+ *       .direction(TraderParam.Direction.LONG)
+ *       .entryPrice(new BigDecimal("2293.7"))
+ *       .takeProfitPrice(new BigDecimal("2301.6"))
+ *       .build();
+ *   element.setHasLongOrder(true);
+ *   element.setLongTraderParam(longParam);
+ * </pre>
+ *
+ * @author Administrator
+ */
+public class GridElement {
+
+    /** 网格层级编号 */
+    private int id;
+    /** 网格触发价格 */
+    private BigDecimal gridPrice;
+    /** 是否存在多仓挂单 */
+    private boolean hasLongOrder;
+    /** 是否存在空仓挂单 */
+    private boolean hasShortOrder;
+    /** 多仓挂单参数 */
+    private TraderParam longTraderParam;
+    /** 空仓挂单参数 */
+    private TraderParam shortTraderParam;
+    /** 上一个网格编号,null 表示无上一级 */
+    private Integer upId;
+    /** 下一个网格编号,null 表示无下一级 */
+    private Integer downId;
+    /** 多仓挂单订单 ID */
+    private String longOrderId;
+    /** 空仓挂单订单 ID */
+    private String shortOrderId;
+    /** 多仓止盈订单 ID */
+    private String longTakeProfitOrderId;
+    /** 空仓止盈订单 ID */
+    private String shortTakeProfitOrderId;
+
+    /** 全局 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
+    private static final Map<Integer, GridElement> INDEX = new ConcurrentHashMap<>();
+    /** 全局价格索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
+    private static final Map<BigDecimal, GridElement> PRICE_INDEX = new ConcurrentHashMap<>();
+    /** 全局多仓订单 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
+    private static final Map<String, GridElement> LONG_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+    /** 全局空仓订单 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
+    private static final Map<String, GridElement> SHORT_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+    /** 全局多仓止盈订单 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
+    private static final Map<String, GridElement> LONG_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+    /** 全局空仓止盈订单 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */
+    private static final Map<String, GridElement> SHORT_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>();
+
+    /**
+     * 根据 ID 快速查找网格元素(O(1))。
+     *
+     * @param id 网格层级编号
+     * @return 对应的 GridElement,不存在则返回 null
+     */
+    public static GridElement findById(int id) {
+        return INDEX.get(id);
+    }
+
+    /**
+     * 根据价格快速查找网格元素(O(1))。
+     *
+     * @param price 网格价格
+     * @return 对应的 GridElement,不存在则返回 null
+     */
+    public static GridElement findByPrice(BigDecimal price) {
+        return PRICE_INDEX.get(price);
+    }
+
+    /**
+     * 根据多仓挂单订单 ID 快速查找网格元素(O(1))。
+     *
+     * @param orderId 多仓挂单订单 ID
+     * @return 对应的 GridElement,不存在则返回 null
+     */
+    public static GridElement findByLongOrderId(String orderId) {
+        return LONG_ORDER_ID_INDEX.get(orderId);
+    }
+
+    /**
+     * 根据空仓挂单订单 ID 快速查找网格元素(O(1))。
+     *
+     * @param orderId 空仓挂单订单 ID
+     * @return 对应的 GridElement,不存在则返回 null
+     */
+    public static GridElement findByShortOrderId(String orderId) {
+        return SHORT_ORDER_ID_INDEX.get(orderId);
+    }
+
+    /**
+     * 根据多仓止盈订单 ID 快速查找网格元素(O(1))。
+     *
+     * @param orderId 多仓止盈订单 ID
+     * @return 对应的 GridElement,不存在则返回 null
+     */
+    public static GridElement findByLongTakeProfitOrderId(String orderId) {
+        return LONG_TP_ORDER_ID_INDEX.get(orderId);
+    }
+
+    /**
+     * 根据空仓止盈订单 ID 快速查找网格元素(O(1))。
+     *
+     * @param orderId 空仓止盈订单 ID
+     * @return 对应的 GridElement,不存在则返回 null
+     */
+    public static GridElement findByShortTakeProfitOrderId(String orderId) {
+        return SHORT_TP_ORDER_ID_INDEX.get(orderId);
+    }
+
+    /**
+     * 从列表中重建全局 ID 索引和价格索引。
+     * 由 {@link GateConfig#setGridElements(List)} 在每次列表变更后调用。
+     */
+    public static void rebuildIndex(List<GridElement> elements) {
+        INDEX.clear();
+        PRICE_INDEX.clear();
+        LONG_ORDER_ID_INDEX.clear();
+        SHORT_ORDER_ID_INDEX.clear();
+        LONG_TP_ORDER_ID_INDEX.clear();
+        SHORT_TP_ORDER_ID_INDEX.clear();
+        for (GridElement e : elements) {
+            INDEX.put(e.getId(), e);
+            putDynamicIndices(e);
+        }
+    }
+
+    /**
+     * 刷新动态索引(价格索引、多仓/空仓订单 ID 索引)。
+     * 在对 GridElement 的 {@link #longOrderId}、{@link #shortOrderId}、
+     * {@link #longTraderParam}、{@link #shortTraderParam} 等字段修改后调用,
+     * 使快速查找方法获取到最新数据。
+     */
+    public static void refreshIndices() {
+        PRICE_INDEX.clear();
+        LONG_ORDER_ID_INDEX.clear();
+        SHORT_ORDER_ID_INDEX.clear();
+        LONG_TP_ORDER_ID_INDEX.clear();
+        SHORT_TP_ORDER_ID_INDEX.clear();
+        for (GridElement e : INDEX.values()) {
+            putDynamicIndices(e);
+        }
+    }
+
+    private static void putDynamicIndices(GridElement e) {
+        PRICE_INDEX.put(e.getGridPrice(), e);
+        if (e.getLongOrderId() != null) {
+            LONG_ORDER_ID_INDEX.put(e.getLongOrderId(), e);
+        }
+        if (e.getShortOrderId() != null) {
+            SHORT_ORDER_ID_INDEX.put(e.getShortOrderId(), e);
+        }
+        if (e.getLongTakeProfitOrderId() != null) {
+            LONG_TP_ORDER_ID_INDEX.put(e.getLongTakeProfitOrderId(), e);
+        }
+        if (e.getShortTakeProfitOrderId() != null) {
+            SHORT_TP_ORDER_ID_INDEX.put(e.getShortTakeProfitOrderId(), e);
+        }
+    }
+
+    /**
+     * @return 根据 upId 获取上一个网格元素,无上一级则返回 null
+     */
+    public GridElement getUp() {
+        return upId != null ? INDEX.get(upId) : null;
+    }
+
+    /**
+     * @return 根据 downId 获取下一个网格元素,无下一级则返回 null
+     */
+    public GridElement getDown() {
+        return downId != null ? INDEX.get(downId) : null;
+    }
+
+    private GridElement(Builder builder) {
+        this.id = builder.id;
+        this.gridPrice = builder.gridPrice;
+        this.hasLongOrder = builder.hasLongOrder;
+        this.hasShortOrder = builder.hasShortOrder;
+        this.longTraderParam = builder.longTraderParam;
+        this.shortTraderParam = builder.shortTraderParam;
+        this.upId = builder.upId;
+        this.downId = builder.downId;
+        this.longOrderId = builder.longOrderId;
+        this.shortOrderId = builder.shortOrderId;
+        this.longTakeProfitOrderId = builder.longTakeProfitOrderId;
+        this.shortTakeProfitOrderId = builder.shortTakeProfitOrderId;
+    }
+
+    // ==================== 网格层级编号 ====================
+
+    /** @return 网格层级编号 */
+    public int getId() { return id; }
+    /** 设置网格层级编号 */
+    public void setId(int id) { this.id = id; }
+
+    // ==================== 网格价格 ====================
+
+    /** @return 网格触发价格 */
+    public BigDecimal getGridPrice() { return gridPrice; }
+    /** 设置网格触发价格 */
+    public void setGridPrice(BigDecimal gridPrice) { this.gridPrice = gridPrice; }
+
+    // ==================== 多仓挂单标记 ====================
+
+    /** @return 是否存在多仓挂单 */
+    public boolean isHasLongOrder() { return hasLongOrder; }
+    /** 标记是否存在多仓挂单 */
+    public void setHasLongOrder(boolean hasLongOrder) { this.hasLongOrder = hasLongOrder; }
+
+    // ==================== 空仓挂单标记 ====================
+
+    /** @return 是否存在空仓挂单 */
+    public boolean isHasShortOrder() { return hasShortOrder; }
+    /** 标记是否存在空仓挂单 */
+    public void setHasShortOrder(boolean hasShortOrder) { this.hasShortOrder = hasShortOrder; }
+
+    // ==================== 多仓挂单参数 ====================
+
+    /** @return 多仓挂单参数 */
+    public TraderParam getLongTraderParam() { return longTraderParam; }
+    /** 设置多仓挂单参数 */
+    public void setLongTraderParam(TraderParam longTraderParam) { this.longTraderParam = longTraderParam; }
+
+    // ==================== 空仓挂单参数 ====================
+
+    /** @return 空仓挂单参数 */
+    public TraderParam getShortTraderParam() { return shortTraderParam; }
+    /** 设置空仓挂单参数 */
+    public void setShortTraderParam(TraderParam shortTraderParam) { this.shortTraderParam = shortTraderParam; }
+
+    // ==================== 上一个网格编号 ====================
+
+    /** @return 上一个网格编号,null 表示无上一级 */
+    public Integer getUpId() { return upId; }
+    /** 设置上一个网格编号 */
+    public void setUpId(Integer upId) { this.upId = upId; }
+
+    // ==================== 下一个网格编号 ====================
+
+    /** @return 下一个网格编号,null 表示无下一级 */
+    public Integer getDownId() { return downId; }
+    /** 设置下一个网格编号 */
+    public void setDownId(Integer downId) { this.downId = downId; }
+
+    // ==================== 多仓挂单订单 ID ====================
+
+    /** @return 多仓挂单订单 ID */
+    public String getLongOrderId() { return longOrderId; }
+    /** 设置多仓挂单订单 ID */
+    public void setLongOrderId(String longOrderId) { this.longOrderId = longOrderId; }
+
+    // ==================== 空仓挂单订单 ID ====================
+
+    /** @return 空仓挂单订单 ID */
+    public String getShortOrderId() { return shortOrderId; }
+    /** 设置空仓挂单订单 ID */
+    public void setShortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; }
+
+    // ==================== 多仓止盈订单 ID ====================
+
+    /** @return 多仓止盈订单 ID */
+    public String getLongTakeProfitOrderId() { return longTakeProfitOrderId; }
+    /** 设置多仓止盈订单 ID */
+    public void setLongTakeProfitOrderId(String longTakeProfitOrderId) { this.longTakeProfitOrderId = longTakeProfitOrderId; }
+
+    // ==================== 空仓止盈订单 ID ====================
+
+    /** @return 空仓止盈订单 ID */
+    public String getShortTakeProfitOrderId() { return shortTakeProfitOrderId; }
+    /** 设置空仓止盈订单 ID */
+    public void setShortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * GridElement 的流式构造器。
+     *
+     * <h3>必填项</h3>
+     * {@code id}、{@code gridPrice} 必须设置。
+     *
+     * <h3>默认值</h3>
+     * hasLongOrder/hasShortOrder 默认为 false,upId/downId/TraderParam 默认为 null
+     */
+    public static class Builder {
+        /** 网格层级编号(必填) */
+        private int id;
+        /** 网格触发价格(必填) */
+        private BigDecimal gridPrice;
+        /** 是否有多仓挂单,默认 false */
+        private boolean hasLongOrder = false;
+        /** 是否有空仓挂单,默认 false */
+        private boolean hasShortOrder = false;
+        /** 多仓挂单参数 */
+        private TraderParam longTraderParam;
+        /** 空仓挂单参数 */
+        private TraderParam shortTraderParam;
+        /** 上一个网格编号,默认 null(无上一级) */
+        private Integer upId;
+        /** 下一个网格编号,默认 null(无下一级) */
+        private Integer downId;
+        /** 多仓挂单订单 ID */
+        private String longOrderId;
+        /** 空仓挂单订单 ID */
+        private String shortOrderId;
+        /** 多仓止盈订单 ID */
+        private String longTakeProfitOrderId;
+        /** 空仓止盈订单 ID */
+        private String shortTakeProfitOrderId;
+
+        /** 设置网格层级编号 */
+        public Builder id(int id) { this.id = id; return this; }
+        /** 设置网格触发价格 */
+        public Builder gridPrice(BigDecimal gridPrice) { this.gridPrice = gridPrice; return this; }
+        /** 设置是否存在多仓挂单 */
+        public Builder hasLongOrder(boolean hasLongOrder) { this.hasLongOrder = hasLongOrder; return this; }
+        /** 设置是否存在空仓挂单 */
+        public Builder hasShortOrder(boolean hasShortOrder) { this.hasShortOrder = hasShortOrder; return this; }
+        /** 设置多仓挂单参数 */
+        public Builder longTraderParam(TraderParam longTraderParam) { this.longTraderParam = longTraderParam; return this; }
+        /** 设置空仓挂单参数 */
+        public Builder shortTraderParam(TraderParam shortTraderParam) { this.shortTraderParam = shortTraderParam; return this; }
+        /** 设置上一个网格编号 */
+        public Builder upId(Integer upId) { this.upId = upId; return this; }
+        /** 设置下一个网格编号 */
+        public Builder downId(Integer downId) { this.downId = downId; return this; }
+        /** 设置多仓挂单订单 ID */
+        public Builder longOrderId(String longOrderId) { this.longOrderId = longOrderId; return this; }
+        /** 设置空仓挂单订单 ID */
+        public Builder shortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; return this; }
+        /** 设置多仓止盈订单 ID */
+        public Builder longTakeProfitOrderId(String longTakeProfitOrderId) { this.longTakeProfitOrderId = longTakeProfitOrderId; return this; }
+        /** 设置空仓止盈订单 ID */
+        public Builder shortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; return this; }
+
+        public GridElement build() {
+            return new GridElement(this);
+        }
+    }
+}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java b/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java
new file mode 100644
index 0000000..bce7886
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java
@@ -0,0 +1,222 @@
+package com.xcong.excoin.modules.gateApi;
+
+import java.math.BigDecimal;
+
+/**
+ * 网格交易单参数,封装单笔条件开仓单及其止盈单的完整状态。
+ *
+ * <p>每笔挂单对应的参数独立存储为一个 TraderParam 实例,
+ * 用于追踪条件开仓单和止盈条件单的挂单状态、价格位置及订单 ID。
+ *
+ * <h3>关键字段</h3>
+ * <ul>
+ *   <li><b>方向</b>:多 / 空,决定挂单和止盈的触发方向</li>
+ *   <li><b>价格</b>:挂单价(条件开仓触发价)、止盈价(止盈触发价)</li>
+ *   <li><b>挂单状态</b>:挂单价是否挂成功、止盈价是否挂成功</li>
+ *   <li><b>网格位置</b>:挂单价网格位置、止盈价网格位置(用于定位在价格队列中的索引)</li>
+ *   <li><b>订单ID</b>:挂单订单 ID、止盈订单 ID(用于取消和匹配)</li>
+ * </ul>
+ *
+ * <h3>使用示例</h3>
+ * <pre>
+ *   TraderParam param = TraderParam.builder()
+ *       .direction(Direction.LONG)
+ *       .entryPrice(new BigDecimal("2293.7"))
+ *       .takeProfitPrice(new BigDecimal("2301.6"))
+ *       .quantity("1")
+ *       .entryGridPosition(3)
+ *       .takeProfitGridPosition(4)
+ *       .build();
+ *
+ *   // 挂单成功后更新
+ *   param.setEntryOrderPlaced(true);
+ *   param.setEntryOrderId("12345");
+ *
+ *   // 止盈单挂成功后更新
+ *   param.setTakeProfitPlaced(true);
+ *   param.setTakeProfitOrderId("12346");
+ * </pre>
+ *
+ * @author Administrator
+ */
+public class TraderParam {
+
+    /**
+     * 交易方向。
+     * <ul>
+     *   <li>{@link #LONG} — 多头</li>
+     *   <li>{@link #SHORT} — 空头</li>
+     * </ul>
+     */
+    public enum Direction {
+        /** 多头方向 */
+        LONG,
+        /** 空头方向 */
+        SHORT
+    }
+
+    /** 交易方向(多 / 空) */
+    private Direction direction;
+    /** 下单数量(合约张数) */
+    private String quantity;
+    /** 挂单价在网格队列中的位置(索引,-1 表示未定位) */
+    private int entryGridPosition;
+    /** 条件开仓触发价 */
+    private BigDecimal entryPrice;
+    /** 挂单(条件开仓单)订单 ID */
+    private String entryOrderId;
+    /** 挂单价(条件开仓单)是否挂成功 */
+    private boolean entryOrderPlaced;
+    /** 止盈价在网格队列中的位置(索引,-1 表示未定位) */
+    private int takeProfitGridPosition;
+    /** 止盈触发价 */
+    private BigDecimal takeProfitPrice;
+    /** 止盈条件单订单 ID */
+    private String takeProfitOrderId;
+    /** 止盈价是否挂成功 */
+    private boolean takeProfitPlaced;
+
+    private TraderParam(Builder builder) {
+        this.direction = builder.direction;
+        this.entryPrice = builder.entryPrice;
+        this.takeProfitPrice = builder.takeProfitPrice;
+        this.quantity = builder.quantity;
+        this.takeProfitPlaced = builder.takeProfitPlaced;
+        this.entryOrderPlaced = builder.entryOrderPlaced;
+        this.entryGridPosition = builder.entryGridPosition;
+        this.takeProfitGridPosition = builder.takeProfitGridPosition;
+        this.takeProfitOrderId = builder.takeProfitOrderId;
+        this.entryOrderId = builder.entryOrderId;
+    }
+
+    // ==================== 交易方向 ====================
+
+    /** @return 交易方向(多 / 空) */
+    public Direction getDirection() { return direction; }
+    /** 设置交易方向 */
+    public void setDirection(Direction direction) { this.direction = direction; }
+
+    // ==================== 条件开仓触发价 ====================
+
+    /** @return 条件开仓触发价 */
+    public BigDecimal getEntryPrice() { return entryPrice; }
+    /** 设置条件开仓触发价 */
+    public void setEntryPrice(BigDecimal entryPrice) { this.entryPrice = entryPrice; }
+
+    // ==================== 止盈触发价 ====================
+
+    /** @return 止盈触发价 */
+    public BigDecimal getTakeProfitPrice() { return takeProfitPrice; }
+    /** 设置止盈触发价 */
+    public void setTakeProfitPrice(BigDecimal takeProfitPrice) { this.takeProfitPrice = takeProfitPrice; }
+
+    // ==================== 下单数量 ====================
+
+    /** @return 下单数量(合约张数) */
+    public String getQuantity() { return quantity; }
+    /** 设置下单数量 */
+    public void setQuantity(String quantity) { this.quantity = quantity; }
+
+    // ==================== 挂单价网格位置 ====================
+
+    /** @return 挂单价在网格队列中的索引位置,-1 表示未定位 */
+    public int getEntryGridPosition() { return entryGridPosition; }
+    /** 设置挂单价在网格队列中的索引位置 */
+    public void setEntryGridPosition(int entryGridPosition) { this.entryGridPosition = entryGridPosition; }
+
+    // ==================== 止盈价网格位置 ====================
+
+    /** @return 止盈价在网格队列中的索引位置,-1 表示未定位 */
+    public int getTakeProfitGridPosition() { return takeProfitGridPosition; }
+    /** 设置止盈价在网格队列中的索引位置 */
+    public void setTakeProfitGridPosition(int takeProfitGridPosition) { this.takeProfitGridPosition = takeProfitGridPosition; }
+
+    // ==================== 止盈价是否挂成功 ====================
+
+    /** @return 止盈条件单是否已挂成功 */
+    public boolean isTakeProfitPlaced() { return takeProfitPlaced; }
+    /** 标记止盈条件单已挂成功 */
+    public void setTakeProfitPlaced(boolean takeProfitPlaced) { this.takeProfitPlaced = takeProfitPlaced; }
+
+    // ==================== 挂单价是否挂成功 ====================
+
+    /** @return 条件开仓单是否已挂成功 */
+    public boolean isEntryOrderPlaced() { return entryOrderPlaced; }
+    /** 标记条件开仓单已挂成功 */
+    public void setEntryOrderPlaced(boolean entryOrderPlaced) { this.entryOrderPlaced = entryOrderPlaced; }
+
+    // ==================== 止盈订单 ID ====================
+
+    /** @return 止盈条件单订单 ID(挂成功后由交易所返回) */
+    public String getTakeProfitOrderId() { return takeProfitOrderId; }
+    /** 记录止盈条件单订单 ID */
+    public void setTakeProfitOrderId(String takeProfitOrderId) { this.takeProfitOrderId = takeProfitOrderId; }
+
+    // ==================== 挂单订单 ID ====================
+
+    /** @return 挂单(条件开仓单)订单 ID(挂成功后由交易所返回) */
+    public String getEntryOrderId() { return entryOrderId; }
+    /** 记录条件开仓单订单 ID */
+    public void setEntryOrderId(String entryOrderId) { this.entryOrderId = entryOrderId; }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * TraderParam 的流式构造器。
+     *
+     * <h3>必填项</h3>
+     * {@code direction}、{@code entryPrice}、{@code takeProfitPrice} 必须设置。
+     *
+     * <h3>默认值</h3>
+     * quantity=1 / entryGridPosition=-1 / takeProfitGridPosition=-1 / 挂单状态均为 false
+     */
+    public static class Builder {
+        /** 交易方向(必填) */
+        private Direction direction;
+        /** 条件开仓触发价(必填) */
+        private BigDecimal entryPrice;
+        /** 止盈触发价(必填) */
+        private BigDecimal takeProfitPrice;
+        /** 下单数量,默认 "1" */
+        private String quantity = "1";
+        /** 止盈价是否挂成功,默认 false */
+        private boolean takeProfitPlaced = false;
+        /** 挂单价是否挂成功,默认 false */
+        private boolean entryOrderPlaced = false;
+        /** 挂单价网格位置,默认 -1(未定位) */
+        private int entryGridPosition = -1;
+        /** 止盈价网格位置,默认 -1(未定位) */
+        private int takeProfitGridPosition = -1;
+        /** 止盈订单 ID */
+        private String takeProfitOrderId;
+        /** 挂单订单 ID */
+        private String entryOrderId;
+
+        /** 设置交易方向(多 / 空) */
+        public Builder direction(Direction direction) { this.direction = direction; return this; }
+        /** 设置条件开仓触发价 */
+        public Builder entryPrice(BigDecimal entryPrice) { this.entryPrice = entryPrice; return this; }
+        /** 设置止盈触发价 */
+        public Builder takeProfitPrice(BigDecimal takeProfitPrice) { this.takeProfitPrice = takeProfitPrice; return this; }
+        /** 设置下单数量(合约张数) */
+        public Builder quantity(String quantity) { this.quantity = quantity; return this; }
+        /** 设置止盈价是否已挂成功 */
+        public Builder takeProfitPlaced(boolean takeProfitPlaced) { this.takeProfitPlaced = takeProfitPlaced; return this; }
+        /** 设置挂单价是否已挂成功 */
+        public Builder entryOrderPlaced(boolean entryOrderPlaced) { this.entryOrderPlaced = entryOrderPlaced; return this; }
+        /** 设置挂单价在网格队列中的索引位置 */
+        public Builder entryGridPosition(int entryGridPosition) { this.entryGridPosition = entryGridPosition; return this; }
+        /** 设置止盈价在网格队列中的索引位置 */
+        public Builder takeProfitGridPosition(int takeProfitGridPosition) { this.takeProfitGridPosition = takeProfitGridPosition; return this; }
+        /** 设置止盈条件单订单 ID */
+        public Builder takeProfitOrderId(String takeProfitOrderId) { this.takeProfitOrderId = takeProfitOrderId; return this; }
+        /** 设置挂单(条件开仓单)订单 ID */
+        public Builder entryOrderId(String entryOrderId) { this.entryOrderId = entryOrderId; return this; }
+
+        public TraderParam build() {
+            return new TraderParam(this);
+        }
+    }
+}

--
Gitblit v1.9.1