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 ++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 509 insertions(+), 133 deletions(-)

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
+                    );
+
+                }
             }
 
         }

--
Gitblit v1.9.1