From e45e705c22df5bc979e72db6014dd1ff9637be42 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Wed, 24 Jun 2026 22:21:58 +0800
Subject: [PATCH] fix(okx): 修复网格交易成交日志记录问题

---
 src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/AbstractOkxPrivateChannelHandler.java |  160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 160 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/AbstractOkxPrivateChannelHandler.java b/src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/AbstractOkxPrivateChannelHandler.java
new file mode 100644
index 0000000..ce9f6c9
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxApi/wsHandler/AbstractOkxPrivateChannelHandler.java
@@ -0,0 +1,160 @@
+package com.xcong.excoin.modules.okxApi.wsHandler;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.xcong.excoin.modules.okxApi.OkxGridTradeService;
+import lombok.extern.slf4j.Slf4j;
+import org.java_websocket.client.WebSocketClient;
+
+/**
+ * OKX 私有频道 WS 处理器的抽象基类。
+ *
+ * <h3>与 Gate 版本的关键区别</h3>
+ * <ul>
+ *   <li>OKX 私有频道连接到<b>独立的私有 WebSocket 端点</b> ({@code wss://ws.okx.com:8443/ws/v5/private}),
+ *       需要先发送 login 消息认证,不同于 Gate 的单一 WS + 签名订阅模式。</li>
+ *   <li>订阅格式使用 {@code op/subscribe} 而非 event/subscribe。</li>
+ *   <li>签名算法使用 HMAC-SHA256 + Base64,而非 Gate 的 HMAC-SHA512 + Hex。</li>
+ * </ul>
+ *
+ * <h3>架构</h3>
+ * 公有频道(如 k-line)连接到 public WS 端点,无需认证。
+ * 私有频道(如 positions、orders-algo)连接到 private WS 端点,由
+ * {@link com.xcong.excoin.modules.okxApi.OkxKlineWebSocketClient} 负责
+ * 在连接建立时发送 login 消息认证。
+ *
+ * <h3>订阅格式</h3>
+ * <pre>
+ * {"op":"subscribe","args":[{"channel":"positions","instType":"SWAP"}]}
+ * {"op":"subscribe","args":[{"channel":"orders-algo","instType":"SWAP","instId":"ETH-USDT-SWAP"}]}
+ * </pre>
+ *
+ * <h3>取消订阅格式</h3>
+ * <pre>
+ * {"op":"unsubscribe","args":[{"channel":"positions","instType":"SWAP"}]}
+ * </pre>
+ *
+ * @author Administrator
+ */
+@Slf4j
+public abstract class AbstractOkxPrivateChannelHandler implements OkxChannelHandler {
+
+    /** 频道名称,如 "positions"、"orders-algo" */
+    private final String channelName;
+
+    /** OKX API Key */
+    protected final String apiKey;
+
+    /** OKX API Secret(用于签名) */
+    protected final String apiSecret;
+
+    /** OKX API Passphrase */
+    protected final String passphrase;
+
+    /** 交易对标识,如 "ETH-USDT-SWAP" */
+    private final String instId;
+
+    /** 网格交易服务实例 */
+    private final OkxGridTradeService gridTradeService;
+
+    /** 订阅确认状态 */
+    private volatile boolean subscribed = false;
+
+    /**
+     * 构造私有频道处理器。
+     *
+     * @param channelName      频道名称(如 "positions"、"orders-algo")
+     * @param apiKey           OKX API Key
+     * @param apiSecret        OKX API Secret
+     * @param passphrase       OKX API Passphrase
+     * @param instId           交易对标识(如 "ETH-USDT-SWAP")
+     * @param gridTradeService 网格交易服务实例
+     */
+    public AbstractOkxPrivateChannelHandler(String channelName,
+                                             String apiKey, String apiSecret,
+                                             String passphrase,
+                                             String instId,
+                                             OkxGridTradeService gridTradeService) {
+        this.channelName = channelName;
+        this.apiKey = apiKey;
+        this.apiSecret = apiSecret;
+        this.passphrase = passphrase;
+        this.instId = instId;
+        this.gridTradeService = gridTradeService;
+    }
+
+    /**
+     * @return 频道名称(如 "positions")
+     */
+    @Override
+    public String getChannelName() {
+        return channelName;
+    }
+
+    /**
+     * @return 交易对标识(如 "ETH-USDT-SWAP")
+     */
+    @Override
+    public String getInstId() {
+        return instId;
+    }
+
+    /**
+     * 发送订阅请求。
+     * 默认实现发送 {@code {"op":"subscribe","args":[{"channel":channelName,"instType":"SWAP"}]}}。
+     * 子类可覆盖以添加额外参数(如 instId)。
+     *
+     * @param ws 私有频道 WebSocket 客户端
+     */
+    @Override
+    public void subscribe(WebSocketClient ws) {
+        JSONObject msg = new JSONObject();
+        msg.put("op", "subscribe");
+        JSONArray args = new JSONArray();
+        JSONObject arg = new JSONObject();
+        arg.put("channel", channelName);
+        arg.put("instType", "SWAP");
+        args.add(arg);
+        msg.put("args", args);
+        ws.send(msg.toJSONString());
+        log.info("[OKX-WS] 订阅私有频道: {}, instType: SWAP", channelName);
+    }
+
+    /**
+     * 发送取消订阅请求。
+     *
+     * @param ws 私有频道 WebSocket 客户端
+     */
+    @Override
+    public void unsubscribe(WebSocketClient ws) {
+        JSONObject msg = new JSONObject();
+        msg.put("op", "unsubscribe");
+        JSONArray args = new JSONArray();
+        JSONObject arg = new JSONObject();
+        arg.put("channel", channelName);
+        arg.put("instType", "SWAP");
+        args.add(arg);
+        msg.put("args", args);
+        ws.send(msg.toJSONString());
+        log.info("[OKX-WS] 取消订阅私有频道: {}", channelName);
+    }
+
+    /**
+     * @return 网格交易服务实例
+     */
+    protected OkxGridTradeService getGridTradeService() {
+        return gridTradeService;
+    }
+
+    // ==================== 订阅状态 ====================
+
+    @Override
+    public boolean isSubscribed() {
+        return subscribed;
+    }
+
+    @Override
+    public void setSubscribed(boolean subscribed) {
+        this.subscribed = subscribed;
+    }
+}

--
Gitblit v1.9.1