From 097ee94cc027baf4970c4fc5daf2aece694d08d9 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Fri, 08 May 2026 14:34:58 +0800
Subject: [PATCH] refactor(gateApi): 重构 Gate API 模块代码结构

---
 src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java                           |   91 +++++++++++++++++-----
 src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java                     |   10 +-
 src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md                                    |   16 +++
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java    |   16 ++--
 src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java                       |   45 +++++-----
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java        |    6 
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java |    4 
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java      |    4 
 src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java                              |   26 +++--
 9 files changed, 142 insertions(+), 76 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 ed17373..f5b7f62 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -7,7 +7,9 @@
 import io.gate.gateapi.api.FuturesApi;
 import io.gate.gateapi.models.AccountDetail;
 import io.gate.gateapi.models.FuturesAccount;
+import io.gate.gateapi.models.FuturesOrder;
 import io.gate.gateapi.models.FuturesPriceTrigger;
+import io.gate.gateapi.models.Position;
 import lombok.extern.slf4j.Slf4j;
 
 import java.math.BigDecimal;
@@ -76,31 +78,79 @@
             detailClient.setApiKeySecret(config.getApiKey(), config.getApiSecret());
             AccountDetail detail = new AccountApi(detailClient).getAccountDetail();
             this.userId = detail.getUserId();
-            log.info("[Gate] uid:{}", userId);
+            log.info("[Gate] 用户ID: {}", userId);
 
             FuturesAccount account = futuresApi.listFuturesAccounts(SETTLE);
             if (!config.getPositionMode().equals(account.getPositionMode())) {
                 futuresApi.setPositionMode(SETTLE, config.getPositionMode());
             }
-            log.info("[Gate] mode:{} balance:{}", config.getPositionMode(), account.getAvailable());
+            log.info("[Gate] 持仓模式: {} 余额: {}", config.getPositionMode(), account.getAvailable());
 
             futuresApi.cancelPriceTriggeredOrderList(SETTLE, config.getContract());
-            log.info("[Gate] old orders cleared");
+            log.info("[Gate] 旧条件单已清除");
+
+            closeExistingPositions();
 
             futuresApi.updateContractPositionLeverageCall(
                     SETTLE, config.getContract(), config.getLeverage(),
                     config.getMarginMode(), config.getPositionMode(), null);
-            log.info("[Gate] {}x {}", config.getLeverage(), config.getMarginMode());
+            log.info("[Gate] 杠杆: {}x {}", config.getLeverage(), config.getMarginMode());
         } catch (GateApiException e) {
-            log.error("[Gate] init fail, label:{}, msg:{}", e.getErrorLabel(), e.getMessage());
+            log.error("[Gate] 初始化失败, label:{}, msg:{}", e.getErrorLabel(), e.getMessage());
         } catch (ApiException e) {
-            log.error("[Gate] init fail, code:{}", e.getCode());
+            log.error("[Gate] 初始化失败, code:{}", e.getCode());
+        }
+    }
+
+    /**
+     * 平掉当前合约所有已有仓位。
+     * 策略启动前的准备工作,确保从零持仓状态开始运行。
+     */
+    private void closeExistingPositions() {
+        try {
+            java.util.List<Position> positions = futuresApi.listPositions(SETTLE).execute();
+            if (positions == null || positions.isEmpty()) {
+                log.info("[Gate] 无已有仓位,无需平仓");
+                return;
+            }
+
+            for (Position pos : positions) {
+                if (!config.getContract().equals(pos.getContract())) {
+                    continue;
+                }
+                String sizeStr = pos.getSize();
+                long size = Long.parseLong(sizeStr);
+                if (size == 0) {
+                    continue;
+                }
+
+                String closeSize = size > 0 ? String.valueOf(-size) : String.valueOf(Math.abs(size));
+                boolean isLong = size > 0;
+                Position.ModeEnum mode = pos.getMode();
+
+                FuturesOrder closeOrder = new FuturesOrder();
+                closeOrder.setContract(config.getContract());
+                closeOrder.setSize(closeSize);
+                closeOrder.setPrice("0");
+                closeOrder.setTif(FuturesOrder.TifEnum.IOC);
+                closeOrder.setReduceOnly(true);
+                if (mode != null && mode.getValue() != null && mode.getValue().contains("dual")) {
+                    closeOrder.setAutoSize(isLong ? FuturesOrder.AutoSizeEnum.LONG : FuturesOrder.AutoSizeEnum.SHORT);
+                }
+                closeOrder.setText("t-grid-init-close");
+                futuresApi.createFuturesOrder(SETTLE, closeOrder, null);
+                log.info("[Gate] 已平掉已有仓位, 方向:{}, sizes:{}, mode:{}", isLong ? "多头" : "空头", sizeStr, mode);
+            }
+        } catch (GateApiException e) {
+            log.warn("[Gate] 平已有仓位失败, label:{}, msg:{}, 可能无仓位", e.getErrorLabel(), e.getMessage());
+        } catch (Exception e) {
+            log.warn("[Gate] 平已有仓位异常, 可能无仓位", e);
         }
     }
 
     public void startGrid() {
         if (state != StrategyState.WAITING_KLINE && state != StrategyState.STOPPED) {
-            log.warn("[Gate] already running, state:{}", state);
+            log.warn("[Gate] 策略已在运行中, state:{}", state);
             return;
         }
         state = StrategyState.WAITING_KLINE;
@@ -109,14 +159,14 @@
         shortActive = false;
         longReopenFails = 0;
         shortReopenFails = 0;
-        log.info("[Gate] grid started");
+        log.info("[Gate] 网格策略已启动");
     }
 
     public void stopGrid() {
         state = StrategyState.STOPPED;
         executor.cancelAllPriceTriggeredOrders();
         executor.shutdown();
-        log.info("[Gate] stopped, pnl:{}", cumulativePnl);
+        log.info("[Gate] 策略已停止, 累计盈亏: {}", cumulativePnl);
     }
 
     /**
@@ -129,7 +179,7 @@
         }
 
         state = StrategyState.OPENING;
-        log.info("[Gate] first kline, opening...");
+        log.info("[Gate] 首根K线到达,开始双开...");
 
         executor.openLong(config.getQuantity(), () -> {
             synchronized (this) {
@@ -148,7 +198,7 @@
                     "close-short-position", "close_short");
             if (longActive && shortActive && state != StrategyState.STOPPED) {
                 state = StrategyState.ACTIVE;
-                log.info("[Gate] active, long:{}, short:{}, tpL:{}, tpS:{}",
+                log.info("[Gate] 已激活, 多头入场:{}, 空头入场:{}, 多头止盈:{}, 空头止盈:{}",
                         longEntryPrice, shortEntryPrice, longTpPrice(), shortTpPrice());
             }
         });
@@ -166,7 +216,7 @@
 
         if ("dual_long".equals(mode)) {
             if (longActive && !hasPosition) {
-                log.info("[Gate] long closed");
+                log.info("[Gate] 多头已平仓");
                 longActive = false;
                 tryReopenLong(0);
             } else if (hasPosition) {
@@ -175,7 +225,7 @@
             }
         } else if ("dual_short".equals(mode)) {
             if (shortActive && !hasPosition) {
-                log.info("[Gate] short closed");
+                log.info("[Gate] 空头已平仓");
                 shortActive = false;
                 tryReopenShort(0);
             } else if (hasPosition) {
@@ -193,18 +243,18 @@
             return;
         }
         cumulativePnl = cumulativePnl.add(pnl);
-        log.info("[Gate] pnl+{}, side:{}, total:{}", pnl, side, cumulativePnl);
+        log.info("[Gate] 盈亏累加:{}, 方向:{}, 累计:{}", pnl, side, cumulativePnl);
 
         if (cumulativePnl.compareTo(config.getOverallTp()) >= 0) {
-            log.info("[Gate] TP reached {}→STOPPED", cumulativePnl);
+            log.info("[Gate] 已达止盈目标 {}→已停止", cumulativePnl);
             state = StrategyState.STOPPED;
         } else if (cumulativePnl.compareTo(config.getMaxLoss().negate()) <= 0) {
-            log.info("[Gate] loss {}→STOPPED", cumulativePnl);
+            log.info("[Gate] 已达亏损上限 {}→已停止", cumulativePnl);
             state = StrategyState.STOPPED;
         }
     }
 
-    // ---- reopen with retry ----
+    // ---- 补仓(含重试) ----
 
     private void tryReopenLong(int retry) {
         if (state == StrategyState.STOPPED) {
@@ -226,7 +276,7 @@
             if (state != StrategyState.STOPPED) {
                 state = StrategyState.ACTIVE;
             }
-            log.info("[Gate] long reopened, price:{}", longEntryPrice);
+            log.info("[Gate] 多头已补开, 价格:{}", longEntryPrice);
         });
     }
 
@@ -250,11 +300,11 @@
             if (state != StrategyState.STOPPED) {
                 state = StrategyState.ACTIVE;
             }
-            log.info("[Gate] short reopened, price:{}", shortEntryPrice);
+            log.info("[Gate] 空头已补开, 价格:{}", shortEntryPrice);
         });
     }
 
-    // ---- util ----
+    // ---- 止盈价格计算 ----
 
     private BigDecimal longTpPrice() {
         return lastKlinePrice.multiply(BigDecimal.ONE.add(config.getGridRate()))
@@ -266,6 +316,7 @@
                 .setScale(1, RoundingMode.HALF_UP);
     }
 
+    /** 对数量取反(开多用正数,开空用负数) */
     private String negate(String qty) {
         return qty.startsWith("-") ? qty.substring(1) : "-" + qty;
     }
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
index 14a46ba..5a5f7b0 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
@@ -48,6 +48,7 @@
  *
  * @author Administrator
  */
+@SuppressWarnings("ALL")
 @Slf4j
 public class GateKlineWebSocketClient {
 
@@ -100,7 +101,7 @@
      */
     public void init() {
         if (!isInitialized.compareAndSet(false, true)) {
-            log.warn("[WS] already init, skip");
+            log.warn("[WS] 已初始化过,跳过重复初始化");
             return;
         }
         connect();
@@ -113,7 +114,7 @@
      * 避免 onClose 回调中的 reconnectWithBackoff 访问已关闭的线程池。
      */
     public void destroy() {
-        log.info("[WS] destroy...");
+        log.info("[WS] 开始销毁...");
 
         if (webSocketClient != null && webSocketClient.isOpen()) {
             for (GateChannelHandler handler : channelHandlers) {
@@ -123,7 +124,7 @@
                 Thread.sleep(500);
             } catch (InterruptedException e) {
                 Thread.currentThread().interrupt();
-                log.warn("[WS] unsubscribe wait interrupted");
+                log.warn("[WS] 取消订阅等待被中断");
             }
         }
 
@@ -132,7 +133,7 @@
                 webSocketClient.closeBlocking();
             } catch (InterruptedException e) {
                 Thread.currentThread().interrupt();
-                log.warn("[WS] close interrupted");
+                log.warn("[WS] 关闭连接时被中断");
             }
         }
 
@@ -146,7 +147,7 @@
         }
         shutdownExecutorGracefully(sharedExecutor);
 
-        log.info("[WS] destroyed");
+        log.info("[WS] 销毁完成");
     }
 
     /**
@@ -155,7 +156,7 @@
      */
     private void connect() {
         if (isConnecting.get() || !isConnecting.compareAndSet(false, true)) {
-            log.info("[WS] already connecting");
+            log.info("[WS] 连接进行中,跳过重复请求");
             return;
         }
         try {
@@ -168,7 +169,7 @@
             webSocketClient = new WebSocketClient(uri) {
                 @Override
                 public void onOpen(ServerHandshake handshake) {
-                    log.info("[WS] connected");
+                    log.info("[WS] 连接成功");
                     isConnected.set(true);
                     isConnecting.set(false);
                     if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
@@ -178,7 +179,7 @@
                         }
                         sendPing();
                     } else {
-                        log.warn("[WS] shutting down, ignore onOpen");
+                        log.warn("[WS] 应用正在关闭,忽略连接成功回调");
                     }
                 }
 
@@ -191,28 +192,28 @@
 
                 @Override
                 public void onClose(int code, String reason, boolean remote) {
-                    log.warn("[WS] closed, code:{}, reason:{}", code, reason);
+                    log.warn("[WS] 连接关闭, code:{}, reason:{}", code, reason);
                     isConnected.set(false);
                     isConnecting.set(false);
                     cancelPongTimeout();
                     if (sharedExecutor != null && !sharedExecutor.isShutdown() && !sharedExecutor.isTerminated()) {
                         sharedExecutor.execute(() -> {
-                            try { reconnectWithBackoff(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Exception e) { log.error("[WS] reconnect fail", e); }
+                            try { reconnectWithBackoff(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Exception e) { log.error("[WS] 重连失败", e); }
                         });
                     } else {
-                        log.warn("[WS] executor closed, no reconnect");
+                        log.warn("[WS] 线程池已关闭,不执行重连");
                     }
                 }
 
                 @Override
                 public void onError(Exception ex) {
-                    log.error("[WS] error", ex);
+                    log.error("[WS] 发生错误", ex);
                     isConnected.set(false);
                 }
             };
             webSocketClient.connect();
         } catch (URISyntaxException e) {
-            log.error("[WS] bad uri", e);
+            log.error("[WS] URI格式错误", e);
             isConnecting.set(false);
         }
     }
@@ -229,21 +230,21 @@
             String event = response.getString("event");
 
             if (FUTURES_PONG.equals(channel)) {
-                log.debug("[WS] pong received");
+                log.debug("[WS] 收到 pong 响应");
                 cancelPongTimeout();
                 return;
             }
             if ("subscribe".equals(event)) {
-                log.info("[WS] {} subscribed: {}", channel, response.getJSONObject("result"));
+                log.info("[WS] {} 订阅成功: {}", channel, response.getJSONObject("result"));
                 return;
             }
             if ("unsubscribe".equals(event)) {
-                log.info("[WS] {} unsubscribed", channel);
+                log.info("[WS] {} 取消订阅成功", channel);
                 return;
             }
             if ("error".equals(event)) {
                 JSONObject error = response.getJSONObject("error");
-                log.error("[WS] {} error, code:{}, msg:{}",
+                log.error("[WS] {} 错误, code:{}, msg:{}",
                         channel,
                         error != null ? error.getInteger("code") : "N/A",
                         error != null ? error.getString("message") : response.getString("msg"));
@@ -255,7 +256,7 @@
                 }
             }
         } catch (Exception e) {
-            log.error("[WS] handle msg fail: {}", message, e);
+            log.error("[WS] 处理消息失败: {}", message, e);
         }
     }
 
@@ -286,9 +287,9 @@
                 pingMsg.put("time", System.currentTimeMillis() / 1000);
                 pingMsg.put("channel", FUTURES_PING);
                 webSocketClient.send(pingMsg.toJSONString());
-                log.debug("[WS] ping sent");
+                log.debug("[WS] 发送 ping 请求");
             }
-        } catch (Exception e) { log.warn("[WS] ping fail", e); }
+        } catch (Exception e) { log.warn("[WS] 发送 ping 失败", e); }
     }
 
     private synchronized void cancelPongTimeout() {
@@ -301,9 +302,9 @@
         int attempt = 0, maxAttempts = 3;
         long delayMs = 5000;
         while (attempt < maxAttempts) {
-            try { Thread.sleep(delayMs); connect(); return; } catch (Exception e) { log.warn("[WS] reconnect attempt {} fail", attempt + 1, e); delayMs *= 2; attempt++; }
+            try { Thread.sleep(delayMs); connect(); return; } catch (Exception e) { log.warn("[WS] 第{}次重连失败", attempt + 1, e); delayMs *= 2; attempt++; }
         }
-        log.error("[WS] reconnect exhausted after {} attempts", maxAttempts);
+        log.error("[WS] 超过最大重试次数({}),放弃重连", maxAttempts);
     }
 
     private void shutdownExecutorGracefully(ExecutorService executor) {
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 40b49c1..bc9856b 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
@@ -100,8 +100,10 @@
                 order.setTif(FuturesOrder.TifEnum.IOC);
                 order.setText("t-grid-long");
                 FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, order, null);
-                log.info("[TradeExec] 开多成功, price:{}, id:{}", result.getFillPrice(), result.getId());
-                if (onSuccess != null) onSuccess.run();
+                log.info("[TradeExec] 开多成功, 价格:{}, id:{}", result.getFillPrice(), result.getId());
+                if (onSuccess != null) {
+                    onSuccess.run();
+                }
             } catch (Exception e) {
                 log.error("[TradeExec] 开多失败", e);
             }
@@ -125,8 +127,10 @@
                 order.setTif(FuturesOrder.TifEnum.IOC);
                 order.setText("t-grid-short");
                 FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, order, null);
-                log.info("[TradeExec] 开空成功, price:{}, id:{}", result.getFillPrice(), result.getId());
-                if (onSuccess != null) onSuccess.run();
+                log.info("[TradeExec] 开空成功, 价格:{}, id:{}", result.getFillPrice(), result.getId());
+                if (onSuccess != null) {
+                    onSuccess.run();
+                }
             } catch (Exception e) {
                 log.error("[TradeExec] 开空失败", e);
             }
@@ -151,23 +155,23 @@
             FuturesPriceTriggeredOrder order = buildTriggeredOrder(triggerPrice, rule, orderType, autoSize);
             try {
                 TriggerOrderResponse response = futuresApi.createPriceTriggeredOrder(SETTLE, order);
-                log.info("[TradeExec] 止盈单已创建, tp:{}, orderType:{}, id:{}",
+                log.info("[TradeExec] 止盈单已创建, 触发价:{}, 类型:{}, id:{}",
                         triggerPrice, orderType, response.getId());
             } catch (GateApiException e) {
                 if ("AUTO_USER_EXIST_POSITION_ORDER".equals(e.getErrorLabel())) {
-                    log.warn("[TradeExec] 止盈单已存在,清除后重试");
+                    log.warn("[TradeExec] 止盈单已存在,清除旧单后重试");
                     try {
                         futuresApi.cancelPriceTriggeredOrderList(SETTLE, contract);
                         TriggerOrderResponse response = futuresApi.createPriceTriggeredOrder(SETTLE, order);
-                        log.info("[TradeExec] 止盈单重试成功, tp:{}, id:{}", triggerPrice, response.getId());
+                        log.info("[TradeExec] 止盈单重试成功, 触发价:{}, id:{}", triggerPrice, response.getId());
                     } catch (Exception retryEx) {
                         log.error("[TradeExec] 止盈单重试失败", retryEx);
                     }
                 } else {
-                    log.error("[TradeExec] 止盈单创建失败, tp:{}", triggerPrice, e);
+                    log.error("[TradeExec] 止盈单创建失败, 触发价:{}", triggerPrice, e);
                 }
             } catch (Exception e) {
-                log.error("[TradeExec] 止盈单创建失败, tp:{}", triggerPrice, e);
+                log.error("[TradeExec] 止盈单创建失败, 触发价:{}", triggerPrice, e);
             }
         });
     }
@@ -179,9 +183,9 @@
         executor.execute(() -> {
             try {
                 futuresApi.cancelPriceTriggeredOrderList(SETTLE, contract);
-                log.info("[TradeExec] 已清除所有止盈止损单");
+                log.info("[TradeExec] 已清除所有止盈止损条件单");
             } catch (Exception e) {
-                log.error("[TradeExec] 清除止盈止损单失败", e);
+                log.error("[TradeExec] 清除止盈止损条件单失败", e);
             }
         });
     }
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 cb24977..dffccd1 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
@@ -45,7 +45,7 @@
 
     @PostConstruct
     public void init() {
-        log.info("[GateMgr] init...");
+        log.info("[管理器] 开始初始化...");
 
         try {
             config = GateConfig.builder()
@@ -73,24 +73,24 @@
             wsClient.addChannelHandler(new PositionClosesChannelHandler(
                     config.getApiKey(), config.getApiSecret(), config.getContract(), gridTradeService));
             wsClient.init();
-            log.info("[GateMgr] ws connected, 3 handlers registered");
+            log.info("[管理器] WS已连接, 已注册 3 个频道处理器");
 
             gridTradeService.startGrid();
         } catch (Exception e) {
-            log.error("[GateMgr] init fail", e);
+            log.error("[管理器] 初始化失败", e);
         }
     }
 
     @PreDestroy
     public void destroy() {
-        log.info("[GateMgr] destroy...");
+        log.info("[管理器] 开始销毁...");
         if (gridTradeService != null) {
             gridTradeService.stopGrid();
         }
         if (wsClient != null) {
             wsClient.destroy();
         }
-        log.info("[GateMgr] destroyed");
+        log.info("[管理器] 销毁完成");
     }
 
     public GateKlineWebSocketClient getKlineWebSocketClient() { return wsClient; }
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md b/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
index c58d0d0..d2555eb 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
@@ -127,7 +127,7 @@
 Spring @PostConstruct
   → GateConfig.builder()...build()
   → GateGridTradeService(config)
-    → init(): 查ID → 查账户切持仓 → 清旧条件单 → 设杠杆
+    → init(): 查ID → 查账户切持仓 → 清旧条件单 → 平已有仓位 → 设杠杆
   → GateKlineWebSocketClient(config.getWsUrl())
     → addChannelHandler x3 → init() → connect()
       → onOpen: handlers依次subscribe → sendPing
@@ -230,15 +230,25 @@
 |------|-----|------|
 | 获取用户ID | `GET /account/detail` | `AccountApi.getAccountDetail()` |
 | 切持仓模式 | `POST /futures/usdt/set_position_mode` | `FuturesApi.setPositionMode()` |
+| 查仓位 | `GET /futures/usdt/positions` | `FuturesApi.listPositions()` |
+| 市价平仓 | `POST /futures/usdt/orders` (reduce_only, IOC) | `FuturesApi.createFuturesOrder()` |
 | 设杠杆 | `POST /futures/usdt/positions/{contract}/leverage` | `FuturesApi.updateContractPositionLeverageCall()` |
 | 查账户 | `GET /futures/usdt/accounts` | `FuturesApi.listFuturesAccounts()` |
 | 清除条件单 | `DELETE /futures/usdt/price_orders` | `FuturesApi.cancelPriceTriggeredOrderList()` |
 | 市价单 | `POST /futures/usdt/orders` (price=0, IOC) | `FuturesApi.createFuturesOrder()` |
 | 条件单 | `POST /futures/usdt/price_orders` | `FuturesApi.createPriceTriggeredOrder()` |
 
----
+**初始化顺序** (`init()`):
+```
+1. 获取用户 ID
+2. 查账户 → 如需要切持仓模式
+3. 清除旧的止盈止损条件单
+4. 市价平掉当前合约所有已有仓位(确保从零持仓开始)
+5. 设杠杆
+6. 打印账户余额
+```
 
-## GateWebSocketClientMain
+---
 
 独立 `main()` 方法入口,通过 Spring XML 上下文启动,运行后手动关闭。
 
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java
index 9c51b45..f3173d2 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java
@@ -64,7 +64,7 @@
         long timeSec = System.currentTimeMillis() / 1000;
         JSONObject msg = buildAuthRequest("subscribe", buildUid(), timeSec);
         ws.send(msg.toJSONString());
-        log.info("[{}] subscribed, contract:{}", channelName, contract);
+        log.info("[{}] 订阅成功, 合约:{}", channelName, contract);
     }
 
     /**
@@ -87,7 +87,7 @@
         auth.put("SIGN", hs512Sign("unsubscribe", timeSec));
         msg.put("auth", auth);
         ws.send(msg.toJSONString());
-        log.info("[{}] unsubscribed, contract:{}", channelName, contract);
+        log.info("[{}] 取消订阅成功, 合约:{}", channelName, contract);
     }
 
     protected GateGridTradeService getGridTradeService() { return gridTradeService; }
@@ -139,7 +139,7 @@
             }
             return hex.toString();
         } catch (Exception e) {
-            log.error("[{}] sign fail", channelName, e);
+            log.error("[{}] 签名计算失败", channelName, e);
             return "";
         }
     }
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java
index cf44e10..ca5eaf0 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java
@@ -57,7 +57,7 @@
         payload.add(contract);
         msg.put("payload", payload);
         ws.send(msg.toJSONString());
-        log.info("[{}] subscribed, contract:{}, interval:{}", CHANNEL_NAME, contract, INTERVAL);
+        log.info("[{}] 订阅成功, 合约:{}, 周期:{}", CHANNEL_NAME, contract, INTERVAL);
     }
 
     @Override
@@ -71,7 +71,7 @@
         payload.add(contract);
         msg.put("payload", payload);
         ws.send(msg.toJSONString());
-        log.info("[{}] unsubscribed", CHANNEL_NAME);
+        log.info("[{}] 取消订阅成功", CHANNEL_NAME);
     }
 
     @Override
@@ -79,20 +79,20 @@
         if (!CHANNEL_NAME.equals(response.getString("channel"))) return false;
         try {
             JSONArray resultArray = response.getJSONArray("result");
-            if (resultArray == null || resultArray.isEmpty()) { log.warn("[{}] empty", CHANNEL_NAME); return true; }
+            if (resultArray == null || resultArray.isEmpty()) { log.warn("[{}] 数据为空", CHANNEL_NAME); return true; }
             JSONObject data = resultArray.getJSONObject(0);
             BigDecimal closePx = new BigDecimal(data.getString("c"));
 
-            log.info("========== Gate K线 ==========");
-            log.info("n:{} t:{} o:{} h:{} l:{} c:{} v:{} a:{} w:{}",
-                    data.getString("n"), DateUtil.TimeStampToDateTime(data.getLong("t")),
+            log.info("========== Gate K线数据 ==========");
+            log.info("名称: {} 时间: {}", data.getString("n"), DateUtil.TimeStampToDateTime(data.getLong("t")));
+            log.info("开盘: {} 最高: {} 最低: {} 收盘: {} 成交量: {} 成交额: {} 已完结: {}",
                     data.getString("o"), data.getString("h"), data.getString("l"),
                     data.getString("c"), data.getString("v"), data.getString("a"),
                     data.getBooleanValue("w"));
-            log.info("==============================");
+            log.info("==================================");
 
             if (gridTradeService != null) gridTradeService.onKline(closePx);
-        } catch (Exception e) { log.error("[{}] handle fail", CHANNEL_NAME, e); }
+        } catch (Exception e) { log.error("[{}] 处理数据失败", CHANNEL_NAME, e); }
         return true;
     }
 }
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java
index 78f6c14..c420da2 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java
@@ -45,12 +45,12 @@
                 if (!getContract().equals(item.getString("contract"))) continue;
                 BigDecimal pnl = new BigDecimal(item.getString("pnl"));
                 String side = item.getString("side");
-                log.info("[{}] side:{}, pnl:{}", CHANNEL_NAME, side, pnl);
+                log.info("[{}] 平仓更新, 方向:{}, 盈亏:{}", CHANNEL_NAME, side, pnl);
                 if (getGridTradeService() != null) {
                     getGridTradeService().onPositionClose(getContract(), side, pnl);
                 }
             }
-        } catch (Exception e) { log.error("[{}] handle fail", CHANNEL_NAME, e); }
+        } catch (Exception e) { log.error("[{}] 处理数据失败", CHANNEL_NAME, e); }
         return true;
     }
 }
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java
index 50cf707..4f0e6e1 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java
@@ -47,12 +47,12 @@
                 String mode = pos.getString("mode");
                 BigDecimal size = new BigDecimal(pos.getString("size"));
                 BigDecimal entryPrice = new BigDecimal(pos.getString("entry_price"));
-                log.info("[{}] mode:{}, size:{}, entry:{}", CHANNEL_NAME, mode, size, entryPrice);
+                log.info("[{}] 持仓更新, 模式:{}, 数量:{}, 入场价:{}", CHANNEL_NAME, mode, size, entryPrice);
                 if (getGridTradeService() != null) {
                     getGridTradeService().onPositionUpdate(getContract(), mode, size, entryPrice);
                 }
             }
-        } catch (Exception e) { log.error("[{}] handle fail", CHANNEL_NAME, e); }
+        } catch (Exception e) { log.error("[{}] 处理数据失败", CHANNEL_NAME, e); }
         return true;
     }
 }

--
Gitblit v1.9.1