From edcf404c20e3ed87e3d0710595750495a26975d1 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Tue, 20 Oct 2026 10:42:54 +0800
Subject: [PATCH] fix(gateApi): 修复止损订单数量参数类型及优化WebSocket心跳机制
---
src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java | 48 ++++++++++++++++++++++++++++++++++++++----------
1 files changed, 38 insertions(+), 10 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 af1bde2..19b3cb0 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -2325,14 +2325,17 @@
int baseQty = Integer.parseInt(config.getBaseQuantity());
int gridCount = baseQty / qty;
GridElement entryElem = GridElement.findById(gridId);
- if (gridCount <= 0 || filledQty < qty) {
+ if (gridCount <= 0 || filledQty <= 0) {
// 早期返回需重置防重入标记
if (entryElem != null) { entryElem.setExtendStopLossInProgress(false); }
return;
}
- // [Gate] 止损只针对初始开仓仓位(baseQuantity),加仓部分只做止盈
- int totalOrders = filledQty / qty;
+ // [Gate] 止损只针对初始开仓仓位(baseQuantity),加仓部分只做止盈;
+ // 持仓不足一个网格量时也按剩余张数挂一张止损(手动重建场景,避免裸奔)
+ int slSize = Math.min(filledQty, baseQty);
+ int totalOrders = slSize / qty;
+ int remainder = slSize % qty;
int[] orders = new int[gridCount];
if (gridCount == 1) {
@@ -2356,6 +2359,7 @@
for (int i = 0; i < gridCount; i++) {
if (orders[i] > 0) { totalOrdersToPlace += orders[i]; }
}
+ if (remainder > 0) { totalOrdersToPlace += 1; }
if (totalOrdersToPlace == 0) {
if (entryElem != null) { entryElem.setExtendStopLossInProgress(false); }
return;
@@ -2366,13 +2370,23 @@
for (int i = 0; i < gridCount; i++) {
if (orders[i] > 0) {
int sgId = gridId - 2 - i;
- placeStopLossOrders(sgId, orders[i], qty, FuturesPriceTrigger.RuleEnum.NUMBER_2,
+ placeStopLossOrders(sgId, orders[i], String.valueOf(qty), FuturesPriceTrigger.RuleEnum.NUMBER_2,
ORDER_TYPE_CLOSE_LONG, true, remainCount, entryElem);
if (detail.length() > 0) {
detail.append(" ");
}
detail.append(sgId).append("x").append(orders[i]);
}
+ }
+ // 不足一个网格量的余数:单独挂一张止损
+ if (remainder > 0) {
+ int sgId = gridId - 2 - totalOrders;
+ placeStopLossOrders(sgId, 1, String.valueOf(remainder), FuturesPriceTrigger.RuleEnum.NUMBER_2,
+ ORDER_TYPE_CLOSE_LONG, true, remainCount, entryElem);
+ if (detail.length() > 0) {
+ detail.append(" ");
+ }
+ detail.append(sgId).append("x").append(remainder);
}
log.info("[Gate] 多仓追挂止损, 成交{}张, gridId:{}, 网格数:{}, 分配:{}",
@@ -2388,14 +2402,17 @@
int baseQty = Integer.parseInt(config.getBaseQuantity());
int gridCount = baseQty / qty;
GridElement entryElem = GridElement.findById(gridId);
- if (gridCount <= 0 || filledQty < qty) {
+ if (gridCount <= 0 || filledQty <= 0) {
// 早期返回需重置防重入标记
if (entryElem != null) { entryElem.setExtendStopLossInProgress(false); }
return;
}
- // [Gate] 止损只针对初始开仓仓位(baseQuantity),加仓部分只做止盈
- int totalOrders = filledQty / qty;
+ // [Gate] 止损只针对初始开仓仓位(baseQuantity),加仓部分只做止盈;
+ // 持仓不足一个网格量时也按剩余张数挂一张止损(手动重建场景,避免裸奔)
+ int slSize = Math.min(filledQty, baseQty);
+ int totalOrders = slSize / qty;
+ int remainder = slSize % qty;
int[] orders = new int[gridCount];
if (gridCount == 1) {
@@ -2419,6 +2436,7 @@
for (int i = 0; i < gridCount; i++) {
if (orders[i] > 0) { totalOrdersToPlace += orders[i]; }
}
+ if (remainder > 0) { totalOrdersToPlace += 1; }
if (totalOrdersToPlace == 0) {
if (entryElem != null) { entryElem.setExtendStopLossInProgress(false); }
return;
@@ -2429,13 +2447,23 @@
for (int i = 0; i < gridCount; i++) {
if (orders[i] > 0) {
int sgId = gridId + 2 + i;
- placeStopLossOrders(sgId, orders[i], qty, FuturesPriceTrigger.RuleEnum.NUMBER_1,
+ placeStopLossOrders(sgId, orders[i], String.valueOf(qty), FuturesPriceTrigger.RuleEnum.NUMBER_1,
ORDER_TYPE_CLOSE_SHORT, false, remainCount, entryElem);
if (detail.length() > 0) {
detail.append(" ");
}
detail.append(sgId).append("x").append(orders[i]);
}
+ }
+ // 不足一个网格量的余数:单独挂一张止损
+ if (remainder > 0) {
+ int sgId = gridId + 2 + totalOrders;
+ placeStopLossOrders(sgId, 1, String.valueOf(remainder), FuturesPriceTrigger.RuleEnum.NUMBER_1,
+ ORDER_TYPE_CLOSE_SHORT, false, remainCount, entryElem);
+ if (detail.length() > 0) {
+ detail.append(" ");
+ }
+ detail.append(sgId).append("x").append(remainder);
}
log.info("[Gate] 空仓追挂止损, 成交{}张, gridId:{}, 网格数:{}, 分配:{}",
@@ -2473,7 +2501,7 @@
/**
* 在指定网格位置挂 count 个独立止损单,每个 size 张。
*/
- private void placeStopLossOrders(int gridId, int count, int qty,
+ private void placeStopLossOrders(int gridId, int count, String qtyStr,
FuturesPriceTrigger.RuleEnum rule,
String orderType, boolean isLong,
AtomicInteger remainCount,
@@ -2506,8 +2534,8 @@
return;
}
BigDecimal triggerPrice = elem.getGridPrice();
+ String size = isLong ? negate(qtyStr) : qtyStr;
for (int i = 0; i < count; i++) {
- String size = isLong ? negate(String.valueOf(qty)) : String.valueOf(qty);
int finalGridId = gridId;
int finalI = i;
executor.placeTakeProfit(
--
Gitblit v1.9.1