From 917000befa702ed94fa12c4bf7395b940080eb71 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Tue, 02 Jun 2026 11:35:23 +0800
Subject: [PATCH] fix(okx): 修复账户余额获取和API请求处理问题

---
 src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java                |   49 +++++++++++++++---------
 src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxAlgoOrdersChannelHandler.java |    6 ++
 src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java                   |    8 ++--
 src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxPositionsChannelHandler.java  |    6 ++
 4 files changed, 44 insertions(+), 25 deletions(-)

diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
index 7b700d8..d0bc3b9 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
@@ -356,7 +356,7 @@
     // ---- 订单/条件单推送回调 ----
 
     public void onOrderUpdate(String algoId, String state, String ordType) {
-        if (!"effective".equals(state) && !"canceled".equals(state)) {
+        if (!"filled".equals(state) && !"canceled".equals(state)) {
             return;
         }
 
@@ -408,31 +408,33 @@
             baseGridElement.setShortOrderId(baseShortTp.getEntryOrderId());
             baseGridElement.setHasShortOrder(true);
 
-            // 挂多仓止损 (id=-2 到 -11)
+            // 挂多仓止损 (id=-2 到 -11),每格 quantity 张
             for (int id = -2; id >= -11; id--) {
                 OkxGridElement elem = OkxGridElement.findById(id);
                 if (elem == null) continue;
                 BigDecimal triggerPrice = elem.getGridPrice();
                 int finalId = id;
-                executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", "1",
+                executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", config.getQuantity(),
                         profitId -> {
                             elem.setLongStopLossOrderId(profitId);
                             OkxGridElement.refreshIndices();
-                            log.info("[OKX] 多仓止损已挂, gridId:{}, 触发价:{}, stopLossId:{}", finalId, triggerPrice, profitId);
+                            log.info("[OKX] 多仓止损已挂, gridId:{}, 触发价:{}, qty:{}, stopLossId:{}",
+                                    finalId, triggerPrice, config.getQuantity(), profitId);
                         });
             }
 
-            // 挂空仓止损 (id=2 到 11)
+            // 挂空仓止损 (id=2 到 11),每格 quantity 张
             for (int id = 2; id <= 11; id++) {
                 OkxGridElement elem = OkxGridElement.findById(id);
                 if (elem == null) continue;
                 BigDecimal triggerPrice = elem.getGridPrice();
                 int finalId = id;
-                executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", "1",
+                executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", config.getQuantity(),
                         profitId -> {
                             elem.setShortStopLossOrderId(profitId);
                             OkxGridElement.refreshIndices();
-                            log.info("[OKX] 空仓止损已挂, gridId:{}, 触发价:{}, stopLossId:{}", finalId, triggerPrice, profitId);
+                            log.info("[OKX] 空仓止损已挂, gridId:{}, 触发价:{}, qty:{}, stopLossId:{}",
+                                    finalId, triggerPrice, config.getQuantity(), profitId);
                         });
             }
 
@@ -561,10 +563,12 @@
 
         BigDecimal triggerPrice = newEntryGrid.getGridPrice();
         BigDecimal priceDiff = longEntryPrice.subtract(triggerPrice).abs();
-        int entryQty = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
-        entryQty = Math.max(1, entryQty);
+        int count = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
+        count = Math.max(1, count);
+        int entryQty = count * Integer.parseInt(config.getQuantity());
         String size = String.valueOf(entryQty);
-        log.info("[OKX] 多仓止损触发 gridId:{}, 在gridId:{}挂{}张多单", gridId, newEntryGridId, entryQty);
+        log.info("[OKX] 多仓止损触发 gridId:{}, 在gridId:{}挂{}张多单(价差:{},步长:{},count:{},qty:{})",
+                gridId, newEntryGridId, entryQty, priceDiff, config.getStep(), count, config.getQuantity());
         newEntryGrid.getLongTraderParam().setQuantity(size);
         placeEntryOrderWithPreFlag(newEntryGrid, true, triggerPrice, size);
     }
@@ -601,15 +605,20 @@
 
         BigDecimal triggerPrice = newEntryGrid.getGridPrice();
         BigDecimal priceDiff = shortEntryPrice.subtract(triggerPrice).abs();
-        int entryQty = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
-        entryQty = Math.max(1, entryQty);
+        int count = priceDiff.divide(config.getStep(), 0, RoundingMode.DOWN).intValue();
+        count = Math.max(1, count);
+        int entryQty = count * Integer.parseInt(config.getQuantity());
         String size = String.valueOf(entryQty);
-        log.info("[OKX] 空仓止损触发 gridId:{}, 在gridId:{}挂{}张空单", gridId, newEntryGridId, entryQty);
+        log.info("[OKX] 空仓止损触发 gridId:{}, 在gridId:{}挂{}张空单(价差:{},步长:{},count:{},qty:{})",
+                gridId, newEntryGridId, entryQty, priceDiff, config.getStep(), count, config.getQuantity());
         newEntryGrid.getShortTraderParam().setQuantity(size);
         placeEntryOrderWithPreFlag(newEntryGrid, false, triggerPrice, size);
     }
 
     private void extendLongStopLoss(int filledQty) {
+        // filledQty 为本次新增止损张数 = count * quantity, 需要按 quantity 为粒度拆分为 count 个止损单
+        int qty = Integer.parseInt(config.getQuantity());
+        int stopLossCount = filledQty / qty;
         int furthestSlId = 0;
         for (OkxGridElement e : config.getGridElements()) {
             if (e.getLongStopLossOrderId() != null && e.getId() < furthestSlId) {
@@ -617,14 +626,14 @@
             }
         }
         if (furthestSlId == 0) furthestSlId = -11;
-        log.info("[OKX] 多仓追挂止损, 当前最远止损gridId:{}, 追加{}张", furthestSlId, filledQty);
-        for (int i = 0; i < filledQty; i++) {
+        log.info("[OKX] 多仓追挂止损, 当前最远止损gridId:{}, 追加{}单, 每单{}张", furthestSlId, stopLossCount, qty);
+        for (int i = 0; i < stopLossCount; i++) {
             int newSlId = furthestSlId - i - 1;
             OkxGridElement elem = OkxGridElement.findById(newSlId);
             if (elem == null) continue;
             BigDecimal triggerPrice = elem.getGridPrice();
             int finalSlId = newSlId;
-            executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", "1",
+            executor.placeTakeProfit(triggerPrice.toString(), "sell", "long", config.getQuantity(),
                     profitId -> {
                         elem.setLongStopLossOrderId(profitId);
                         OkxGridElement.refreshIndices();
@@ -634,6 +643,8 @@
     }
 
     private void extendShortStopLoss(int filledQty) {
+        int qty = Integer.parseInt(config.getQuantity());
+        int stopLossCount = filledQty / qty;
         int furthestSlId = 0;
         for (OkxGridElement e : config.getGridElements()) {
             if (e.getShortStopLossOrderId() != null && e.getId() > furthestSlId) {
@@ -641,14 +652,14 @@
             }
         }
         if (furthestSlId == 0) furthestSlId = 11;
-        log.info("[OKX] 空仓追挂止损, 当前最远止损gridId:{}, 追加{}张", furthestSlId, filledQty);
-        for (int i = 0; i < filledQty; i++) {
+        log.info("[OKX] 空仓追挂止损, 当前最远止损gridId:{}, 追加{}单, 每单{}张", furthestSlId, stopLossCount, qty);
+        for (int i = 0; i < stopLossCount; i++) {
             int newSlId = furthestSlId + i + 1;
             OkxGridElement elem = OkxGridElement.findById(newSlId);
             if (elem == null) continue;
             BigDecimal triggerPrice = elem.getGridPrice();
             int finalSlId = newSlId;
-            executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", "1",
+            executor.placeTakeProfit(triggerPrice.toString(), "buy", "short", config.getQuantity(),
                     profitId -> {
                         elem.setShortStopLossOrderId(profitId);
                         OkxGridElement.refreshIndices();
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java
index 5f8ca15..640424a 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java
@@ -86,7 +86,7 @@
      * @param onFailure 失败回调
      */
     public void openLong(String quantity, Consumer<String> onSuccess, Runnable onFailure) {
-        submitOrder("buy", "long", quantity, "market", null, false, "tGridLong", onSuccess, onFailure);
+        submitOrder("buy", "long", quantity, "market", null, false, null, onSuccess, onFailure);
     }
 
     /**
@@ -97,7 +97,7 @@
      * @param onFailure 失败回调
      */
     public void openShort(String quantity, Consumer<String> onSuccess, Runnable onFailure) {
-        submitOrder("sell", "short", quantity, "market", null, false, "tGridShort", onSuccess, onFailure);
+        submitOrder("sell", "short", quantity, "market", null, false, null, onSuccess, onFailure);
     }
 
     /**
@@ -233,7 +233,7 @@
     }
 
     /**
-     * 异步取消所有未完成的 algo 订单。
+     * 异步取消所有未完成的 algo 订单(best-effort,失败仅警告)。
      */
     public void cancelAllAlgoOrders() {
         executor.execute(() -> {
@@ -243,7 +243,7 @@
                         okxAccount.baseUrl, "/api/v5/trade/cancel-algos", body, HttpMethod.POST, okxAccount.isSimluate());
                 log.info("[OkxExec] 已尝试清除条件单, resp:{}", resp);
             } catch (Exception e) {
-                log.error("[OkxExec] 清除条件单失败", e);
+                log.warn("[OkxExec] 清除条件单失败(若无挂单可忽略), msg:{}", e.getMessage());
             }
         });
     }
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxAlgoOrdersChannelHandler.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxAlgoOrdersChannelHandler.java
index 5410920..11114d6 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxAlgoOrdersChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxAlgoOrdersChannelHandler.java
@@ -18,10 +18,12 @@
     private static final String CHANNEL_NAME = "orders-algo";
 
     private final String instId;
+    private final String instFamily;
     private final OkxGridTradeService gridTradeService;
 
     public OkxAlgoOrdersChannelHandler(String instId, OkxGridTradeService gridTradeService) {
         this.instId = instId;
+        this.instFamily = instId.contains("-") ? instId.substring(0, instId.lastIndexOf("-")) : instId;
         this.gridTradeService = gridTradeService;
     }
 
@@ -34,12 +36,13 @@
         JSONObject arg = new JSONObject();
         arg.put("channel", CHANNEL_NAME);
         arg.put("instType", "SWAP");
+        arg.put("instFamily", instFamily);
         msg.put("op", "subscribe");
         JSONArray args = new JSONArray();
         args.add(arg);
         msg.put("args", args);
         ws.send(msg.toJSONString());
-        log.info("[OKX-WS] {} 订阅成功", CHANNEL_NAME);
+        log.info("[OKX-WS] {} 订阅成功, instFamily:{}", CHANNEL_NAME, instFamily);
     }
 
     @Override
@@ -48,6 +51,7 @@
         JSONObject arg = new JSONObject();
         arg.put("channel", CHANNEL_NAME);
         arg.put("instType", "SWAP");
+        arg.put("instFamily", instFamily);
         msg.put("op", "unsubscribe");
         JSONArray args = new JSONArray();
         args.add(arg);
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxPositionsChannelHandler.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxPositionsChannelHandler.java
index 5749544..51ae155 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxPositionsChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/gridWs/OkxPositionsChannelHandler.java
@@ -20,10 +20,12 @@
     private static final String CHANNEL_NAME = "positions";
 
     private final String instId;
+    private final String instFamily;
     private final OkxGridTradeService gridTradeService;
 
     public OkxPositionsChannelHandler(String instId, OkxGridTradeService gridTradeService) {
         this.instId = instId;
+        this.instFamily = instId.contains("-") ? instId.substring(0, instId.lastIndexOf("-")) : instId;
         this.gridTradeService = gridTradeService;
     }
 
@@ -36,12 +38,13 @@
         JSONObject arg = new JSONObject();
         arg.put("channel", CHANNEL_NAME);
         arg.put("instType", "SWAP");
+        arg.put("instFamily", instFamily);
         msg.put("op", "subscribe");
         JSONArray args = new JSONArray();
         args.add(arg);
         msg.put("args", args);
         ws.send(msg.toJSONString());
-        log.info("[OKX-WS] {} 订阅成功", CHANNEL_NAME);
+        log.info("[OKX-WS] {} 订阅成功, instFamily:{}", CHANNEL_NAME, instFamily);
     }
 
     @Override
@@ -50,6 +53,7 @@
         JSONObject arg = new JSONObject();
         arg.put("channel", CHANNEL_NAME);
         arg.put("instType", "SWAP");
+        arg.put("instFamily", instFamily);
         msg.put("op", "unsubscribe");
         JSONArray args = new JSONArray();
         args.add(arg);

--
Gitblit v1.9.1