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

---
 src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java         |   21 +++++++---
 src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridWsClient.java             |   16 +++++---
 src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java |   17 +++++++-
 src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java            |   15 +++----
 4 files changed, 45 insertions(+), 24 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 dca76ea..9306cc7 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridTradeService.java
@@ -104,18 +104,27 @@
      */
     public void init() {
         try {
-            // 1. 查询账户获取初始本金
+            // 1. 查询账户获取初始本金(仅取 USDT 合约账户余额)
             String balanceResp = executor.getBalance();
             if (balanceResp != null) {
                 JSONObject json = JSON.parseObject(balanceResp);
                 if ("0".equals(json.getString("code"))) {
                     JSONArray data = json.getJSONArray("data");
                     if (data != null && !data.isEmpty()) {
-                        JSONObject detail = data.getJSONObject(0);
-                        String totalEq = detail.getString("totalEq");
-                        if (totalEq != null) {
-                            this.initialPrincipal = new BigDecimal(totalEq);
-                            log.info("[OKX] 初始本金: {} USDT", initialPrincipal);
+                        JSONObject accountData = data.getJSONObject(0);
+                        JSONArray details = accountData.getJSONArray("details");
+                        if (details != null) {
+                            for (int i = 0; i < details.size(); i++) {
+                                JSONObject detail = details.getJSONObject(i);
+                                if ("USDT".equals(detail.getString("ccy"))) {
+                                    String eq = detail.getString("eq");
+                                    if (eq != null) {
+                                        this.initialPrincipal = new BigDecimal(eq);
+                                        log.info("[OKX] 初始本金(USDT合约): {} USDT", initialPrincipal);
+                                    }
+                                    break;
+                                }
+                            }
                         }
                     }
                 }
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridWsClient.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridWsClient.java
index da664ba..9f9517f 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridWsClient.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxGridWsClient.java
@@ -38,10 +38,10 @@
 
     private static final int HEARTBEAT_TIMEOUT = 10;
 
-    /** 模拟盘公共 WS 地址 */
-    private static final String WS_PUBLIC_URL_SIM = "wss://wspap.okx.com:8443/ws/v5/public";
-    /** 实盘公共 WS 地址 */
-    private static final String WS_PUBLIC_URL_PROD = "wss://ws.okx.com:8443/ws/v5/public";
+    /** 模拟盘业务 WS 地址(K线等行情数据) */
+    private static final String WS_BUSINESS_URL_SIM = "wss://wspap.okx.com:8443/ws/v5/business";
+    /** 实盘业务 WS 地址(K线等行情数据) */
+    private static final String WS_BUSINESS_URL_PROD = "wss://ws.okx.com:8443/ws/v5/business";
     /** 模拟盘私有 WS 地址 */
     private static final String WS_PRIVATE_URL_SIM = "wss://wspap.okx.com:8443/ws/v5/private";
     /** 实盘私有 WS 地址 */
@@ -119,9 +119,9 @@
             System.setProperty("https.protocols", "TLSv1.2,TLSv1.3");
             String wsUrl;
             if (account.isAccountType()) {
-                wsUrl = isPublic ? WS_PUBLIC_URL_PROD : WS_PRIVATE_URL_PROD;
+                wsUrl = isPublic ? WS_BUSINESS_URL_PROD : WS_PRIVATE_URL_PROD;
             } else {
-                wsUrl = isPublic ? WS_PUBLIC_URL_SIM : WS_PRIVATE_URL_SIM;
+                wsUrl = isPublic ? WS_BUSINESS_URL_SIM : WS_PRIVATE_URL_SIM;
             }
             URI uri = new URI(wsUrl);
 
@@ -212,6 +212,10 @@
 
     private void handleMessage(String message) {
         try {
+            if ("pong".equals(message)) {
+                log.debug("[{}] 收到 pong", logPrefix);
+                return;
+            }
             JSONObject response = JSON.parseObject(message);
             String event = response.getString("event");
             String op = response.getString("op");
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 d96dd44..a562b93 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/OkxTradeExecutor.java
@@ -219,11 +219,9 @@
         }
         executor.execute(() -> {
             try {
-                LinkedHashMap<String, Object> params = new LinkedHashMap<>();
-                params.put("instId", instId);
-                params.put("algoId", algoId);
-                String resp = okxAccount.requestHandler.sendSignedRequest(
-                        okxAccount.baseUrl, "/api/v5/trade/cancel-algos", params, HttpMethod.POST, okxAccount.isSimluate());
+                String body = "[{\"instId\":\"" + instId + "\",\"algoId\":\"" + algoId + "\"}]";
+                String resp = okxAccount.requestHandler.sendSignedRequestRaw(
+                        okxAccount.baseUrl, "/api/v5/trade/cancel-algos", body, HttpMethod.POST, okxAccount.isSimluate());
                 log.info("[OkxExec] 条件单已取消, algoId:{}", algoId);
                 if (onSuccess != null) {
                     onSuccess.accept(algoId);
@@ -240,10 +238,9 @@
     public void cancelAllAlgoOrders() {
         executor.execute(() -> {
             try {
-                LinkedHashMap<String, Object> params = new LinkedHashMap<>();
-                params.put("instId", instId);
-                String resp = okxAccount.requestHandler.sendSignedRequest(
-                        okxAccount.baseUrl, "/api/v5/trade/cancel-algos", params, HttpMethod.POST, okxAccount.isSimluate());
+                String body = "[{\"instId\":\"" + instId + "\",\"instType\":\"SWAP\"}]";
+                String resp = okxAccount.requestHandler.sendSignedRequestRaw(
+                        okxAccount.baseUrl, "/api/v5/trade/cancel-algos", body, HttpMethod.POST, okxAccount.isSimluate());
                 log.info("[OkxExec] 已尝试清除条件单, resp:{}", resp);
             } catch (Exception e) {
                 log.error("[OkxExec] 清除条件单失败", e);
diff --git a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java
index 17c0d82..da84578 100644
--- a/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/okxNewPrice/okxpi/config/RequestHandler.java
@@ -118,9 +118,20 @@
         if (null == secretKey || secretKey.isEmpty() || null == apiKey || apiKey.isEmpty()) {
             throw new FebsException("[RequestHandler] Secret key/API key cannot be null or empty!");
         }
-        //parameters.put("timestamp", UrlBuilder.buildTimestamp());
-        //String queryString = UrlBuilder.joinQueryParameters(parameters);
-        //String signature = SignatureGenerator.getSignature(queryString, secretKey);
         return sendApiRequest(baseUrl, urlPath, parameters, httpMethod, RequestType.SIGNED, isSimluate);
     }
+
+    public String sendSignedRequestRaw(String baseUrl, String urlPath, String rawBody,
+                                        HttpMethod httpMethod, boolean isSimluate) {
+        if (null == secretKey || secretKey.isEmpty() || null == apiKey || apiKey.isEmpty()) {
+            throw new FebsException("[RequestHandler] Secret key/API key cannot be null or empty!");
+        }
+        String fullUrl = UrlBuilder.buildFullUrl(baseUrl, urlPath, null, null);
+        log.debug("{} {}", httpMethod, fullUrl);
+        String timestamp = DateUtils.format(DateUtils.FORMAT_UTC_ISO8601, new Date(), 0);
+        String queryString = urlPath;
+        String sign = SignUtils.signRest(secretKey, timestamp, httpMethod.toString(), queryString, rawBody);
+        Request request = RequestBuilder.buildApiKeyRequest(fullUrl, rawBody, passphrase, sign, timestamp, httpMethod, apiKey, isSimluate);
+        return ResponseHandler.handleResponse(request, isSimluate);
+    }
 }

--
Gitblit v1.9.1