From dad0b1cd6cd39d2525f23b1b33df19932fc4cddb Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Mon, 29 Jun 2026 11:28:27 +0800
Subject: [PATCH] 止损追单逻辑(多仓/空仓对称): 触发 → 查询 → 计算 → 下单 清理:取消相邻网格旧挂单 + 取消最远止盈单 一句话总结:每次止损触发补回 quantity*2 张,但总持仓不超 maxPositionSize,也不再累加放大。

---
 src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java |   67 +++++++++++++++++++++++++--------
 1 files changed, 50 insertions(+), 17 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 10916de..8c9fe92 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -1242,15 +1242,31 @@
         if (!newEntryGrid.isHasLongOrder()) {
             BigDecimal triggerPrice = newEntryGrid.getGridPrice();
 
-            // 累计止损张数 + 当前止损量作为追单size,不再依赖positionSize(避免WS竞态)
-            accumulatedLongLossCount += Integer.parseInt(config.getQuantity());
-            String size = String.valueOf(accumulatedLongLossCount + Integer.parseInt(config.getQuantity()));
-            log.info("[Gate] 多仓止损触发 gridId:{}, 在gridId:{}挂{}基础张多单",
-                    gridId, newEntryGridId, size);
-
-            newEntryGrid.getLongTraderParam().setQuantity(size);
-            placeEntryOrderWithPreFlag(newEntryGrid, true, triggerPrice,
-                    FuturesPriceTrigger.RuleEnum.NUMBER_1, size);
+            // 止损触发后持仓在减少,取REST和WS缓存中较小值更准确
+            int posSize = Math.min(queryPositionSize(Position.ModeEnum.DUAL_LONG), longPositionSize.intValue());
+            int maxPos = config.getMaxPositionSize();
+            int targetAmount = Integer.parseInt(config.getQuantity()) * 2; // quantity + 本次止损量
+            int addSize;
+            if (maxPos > 0) {
+                int remainingRoom = maxPos - posSize;
+                if (remainingRoom <= 0) {
+                    log.warn("[Gate] 多仓止损触发 gridId:{}, 当前持仓{}/{}已达上限,跳过追单",
+                            gridId, posSize, maxPos);
+                    addSize = 0;
+                } else {
+                    addSize = Math.min(remainingRoom, targetAmount);
+                }
+            } else {
+                addSize = targetAmount;
+            }
+            if (addSize > 0) {
+                String size = String.valueOf(addSize);
+                log.info("[Gate] 多仓止损触发 gridId:{}, 在gridId:{}补{}张多单(当前{}/上限{})",
+                        gridId, newEntryGridId, size, posSize, maxPos > 0 ? maxPos : "无");
+                newEntryGrid.getLongTraderParam().setQuantity(size);
+                placeEntryOrderWithPreFlag(newEntryGrid, true, triggerPrice,
+                        FuturesPriceTrigger.RuleEnum.NUMBER_1, size);
+            }
         }else{
             log.warn("[Gate] 多仓止损触发 gridId:{}, 目标gridId:{}已有挂单,跳过重复下单", gridId, newEntryGridId);
         }
@@ -1301,14 +1317,31 @@
         if (!newEntryGrid.isHasShortOrder()) {
             BigDecimal triggerPrice = newEntryGrid.getGridPrice();
 
-            // 累计止损张数 + 当前止损量作为追单size,不再依赖positionSize(避免WS竞态)
-            accumulatedShortLossCount += Integer.parseInt(config.getQuantity());
-            String size = String.valueOf(accumulatedShortLossCount + Integer.parseInt(config.getQuantity()));
-            log.info("[Gate] 空仓止损触发 gridId:{}, 在gridId:{}挂{}基础张空单",
-                    gridId, newEntryGridId, size);
-            newEntryGrid.getShortTraderParam().setQuantity(size);
-            placeEntryOrderWithPreFlag(newEntryGrid, false, triggerPrice,
-                    FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(size));
+            // 止损触发后持仓在减少,取REST和WS缓存中较小值更准确
+            int posSize = Math.min(queryPositionSize(Position.ModeEnum.DUAL_SHORT), shortPositionSize.intValue());
+            int maxPos = config.getMaxPositionSize();
+            int targetAmount = Integer.parseInt(config.getQuantity()) * 2; // quantity + 本次止损量
+            int addSize;
+            if (maxPos > 0) {
+                int remainingRoom = maxPos - posSize;
+                if (remainingRoom <= 0) {
+                    log.warn("[Gate] 空仓止损触发 gridId:{}, 当前持仓{}/{}已达上限,跳过追单",
+                            gridId, posSize, maxPos);
+                    addSize = 0;
+                } else {
+                    addSize = Math.min(remainingRoom, targetAmount);
+                }
+            } else {
+                addSize = targetAmount;
+            }
+            if (addSize > 0) {
+                String size = String.valueOf(addSize);
+                log.info("[Gate] 空仓止损触发 gridId:{}, 在gridId:{}补{}张空单(当前{}/上限{})",
+                        gridId, newEntryGridId, size, posSize, maxPos > 0 ? maxPos : "无");
+                newEntryGrid.getShortTraderParam().setQuantity(size);
+                placeEntryOrderWithPreFlag(newEntryGrid, false, triggerPrice,
+                        FuturesPriceTrigger.RuleEnum.NUMBER_2, negate(size));
+            }
         }else{
             log.warn("[Gate] 空仓止损触发 gridId:{}, 目标gridId:{}已有挂单,跳过重复下单", gridId, newEntryGridId);
         }

--
Gitblit v1.9.1