From 025c66091b6b6903b5e830c5bde981fdbacbc744 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Mon, 11 May 2026 17:46:25 +0800
Subject: [PATCH] docs(gateApi): 删除 Gate API 模块相关文件

---
 src/main/java/com/xcong/excoin/modules/okxApi/OkxGridTradeService.java |  150 ++++---
 /dev/null                                                              |   99 -----
 src/main/java/com/xcong/excoin/modules/okxApi/okxApi-logic.md          |  724 ++++++++++++++++++++++++++++++++++++++
 src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java    |  148 ++++++-
 4 files changed, 939 insertions(+), 182 deletions(-)

diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/Example.java b/src/main/java/com/xcong/excoin/modules/gateApi/Example.java
deleted file mode 100644
index c8f8ff3..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/Example.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-// Import classes:
-import io.gate.gateapi.ApiClient;
-import io.gate.gateapi.ApiException;
-import io.gate.gateapi.Configuration;
-import io.gate.gateapi.GateApiException;
-import io.gate.gateapi.api.FuturesApi;
-import io.gate.gateapi.auth.*;
-import io.gate.gateapi.models.*;
-import io.gate.gateapi.api.AccountApi;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-
-
-/**
- * Gate SDK API 使用示例。
- *
- * <h3>演示内容</h3>
- * <ol>
- *   <li>通过 API Key/Secret 初始化客户端</li>
- *   <li>查询期货账户余额</li>
- *   <li>设置双向持仓模式</li>
- *   <li>设置杠杆倍数</li>
- *   <li>切换保证金模式(全仓/逐仓)</li>
- * </ol>
- *
- * <h3>注意</h3>
- * 此文件仅作为 SDK 用法参考,不影响实际策略运行。
- * 当前策略中相同功能的实现在 {@code GateGridTradeService.init()} 中。
- *
- * @author Administrator
- */
-@Slf4j
-public class Example {
-    /**
-     * 示例入口:依次执行查询账户 → 设置双向持仓 → 设杠杆 → 切换保证金模式。
-     */
-    public static void main(String[] args) {
-        ApiClient defaultClient = Configuration.getDefaultApiClient();
-        defaultClient.setBasePath("https://api-testnet.gateapi.io/api/v4");
-//        defaultClient.setBasePath("https://api.gateio.ws/api/v4");
-
-        // Configure APIv4 authorization: apiv4
-        defaultClient.setApiKeySecret("d90ca272391992b8e74f8f92cedb21ec", "1861e4f52de4bb53369ea3208d9ede38ece4777368030f96c77d27934c46c274");
-
-        try {
-
-            String CONTRACT = "ETH_USDT";
-            String SETTLE = "usdt";
-            //保证金模式 isolated/cross
-            String MARGINMODE = "CROSS";
-            String LEVERAGE = "100";
-            FuturesApi futuresApi = new FuturesApi(defaultClient);
-            FuturesAccount account = futuresApi.listFuturesAccounts(SETTLE);
-            log.info("[Gate] 初始本金: {} USDT", account.getTotal());
-
-            //设置持仓模式为双向持仓
-            Boolean inDualMode = account.getInDualMode();
-            if (!inDualMode) {
-                try {
-                    futuresApi.setDualModeCall(SETTLE,true,null).execute();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-
-            try {
-                futuresApi.updateDualModePositionLeverageCall(
-                        SETTLE, CONTRACT, LEVERAGE,
-                        null, null).execute();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-
-            if (!MARGINMODE.equals(account.getMarginMode())) {
-
-                UpdateDualCompPositionCrossModeRequest updateDualCompPositionCrossModeRequest = new UpdateDualCompPositionCrossModeRequest();
-                updateDualCompPositionCrossModeRequest.setMode(MARGINMODE);
-                updateDualCompPositionCrossModeRequest.setContract(CONTRACT);
-                try {
-                    futuresApi.updateDualCompPositionCrossModeCall(SETTLE, updateDualCompPositionCrossModeRequest, null).execute();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        } catch (GateApiException e) {
-            System.err.println(String.format("Gate api exception, label: %s, message: %s", e.getErrorLabel(), e.getMessage()));
-            e.printStackTrace();
-        } catch (ApiException e) {
-            System.err.println("Exception when calling AccountApi#getAccountDetail");
-            e.printStackTrace();
-        }
-    }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
deleted file mode 100644
index b65d0aa..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
+++ /dev/null
@@ -1,261 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import java.math.BigDecimal;
-
-/**
- * Gate 模块统一配置。
- *
- * <p>通过 Builder 模式集中管理所有运行参数,避免参数散落在多个文件中。
- * 提供 REST API 和 WebSocket 地址的自动环境切换(测试网/生产网)。
- *
- * <h3>使用示例</h3>
- * <pre>
- *   GateConfig config = GateConfig.builder()
- *       .apiKey("...")
- *       .apiSecret("...")
- *       .contract("XAU_USDT")
- *       .leverage("100")
- *       .gridRate(new BigDecimal("0.0035"))
- *       .contractMultiplier("0.001")
- *       .isProduction(false)
- *       .build();
- *
- *   String restUrl = config.getRestBasePath();  // 自动返回测试网或生产网地址
- *   String wsUrl   = config.getWsUrl();
- * </pre>
- *
- * <h3>默认值</h3>
- * <ul>
- *   <li>合约: BTC_USDT, 杠杆: 10x, 全仓, 双向持仓</li>
- *   <li>网格间距: 0.35%, 队列容量: 50, 保证金比例上限: 20%</li>
- *   <li>止盈: 0.5 USDT, 亏损上限: 7.5 USDT</li>
- *   <li>数量: 1 张, 合约乘数: 0.001, 环境: 测试网</li>
- * </ul>
- *
- * @author Administrator
- */
-public class GateConfig {
-
-    /** 未实现盈亏计价模式 */
-    public enum PnLPriceMode {
-        /** 按最新成交价计算 */
-        LAST_PRICE,
-        /** 按标记价格计算 */
-        MARK_PRICE
-    }
-
-    /** Gate API v4 密钥 */
-    private final String apiKey;
-    /** Gate API v4 签名密钥 */
-    private final String apiSecret;
-    /** 合约名称(如 XAU_USDT) */
-    private final String contract;
-    /** 杠杆倍数 */
-    private final String leverage;
-    /** 保证金模式(cross / isolated) */
-    private final String marginMode;
-    /** 持仓模式(single / dual / dual_plus) */
-    private final String positionMode;
-    /** 网格间距比例(如 0.0035 表示 0.35%) */
-    private final BigDecimal gridRate;
-    /** 整体止盈阈值(USDT) */
-    private final BigDecimal overallTp;
-    /** 最大亏损阈值(USDT) */
-    private final BigDecimal maxLoss;
-    /** 下单数量(合约张数) */
-    private final String quantity;
-    /** 是否为生产环境 */
-    private final boolean isProduction;
-    /** 补仓最大重试次数 */
-    private final int reopenMaxRetries;
-    /** 网格队列容量 */
-    private final int gridQueueSize;
-    /** 保证金占初始本金比例上限 */
-    private final BigDecimal marginRatioLimit;
-    /** 合约乘数(单张合约代表的基础资产数量,如 BTC_USDT=0.001, ETH_USDT=0.01) */
-    private final BigDecimal contractMultiplier;
-    /** 未实现盈亏计价模式:最新价 / 标记价格 */
-    private final PnLPriceMode unrealizedPnlPriceMode;
-
-    private GateConfig(Builder builder) {
-        this.apiKey = builder.apiKey;
-        this.apiSecret = builder.apiSecret;
-        this.contract = builder.contract;
-        this.leverage = builder.leverage;
-        this.marginMode = builder.marginMode;
-        this.positionMode = builder.positionMode;
-        this.gridRate = builder.gridRate;
-        this.overallTp = builder.overallTp;
-        this.maxLoss = builder.maxLoss;
-        this.quantity = builder.quantity;
-        this.isProduction = builder.isProduction;
-        this.reopenMaxRetries = builder.reopenMaxRetries;
-        this.gridQueueSize = builder.gridQueueSize;
-        this.marginRatioLimit = builder.marginRatioLimit;
-        this.contractMultiplier = builder.contractMultiplier;
-        this.unrealizedPnlPriceMode = builder.unrealizedPnlPriceMode;
-    }
-
-    // ==================== REST/WS 地址 ====================
-
-    /**
-     * 根据环境返回 REST API 基础路径。
-     * <ul>
-     *   <li>测试网: {@code https://api-testnet.gateapi.io/api/v4}</li>
-     *   <li>生产网: {@code https://api.gateio.ws/api/v4}</li>
-     * </ul>
-     */
-    public String getRestBasePath() {
-        return isProduction
-                ? "https://api.gateio.ws/api/v4"
-                : "https://api-testnet.gateapi.io/api/v4";
-    }
-
-    /**
-     * 根据环境返回 WebSocket 地址。
-     * <ul>
-     *   <li>测试网: {@code wss://ws-testnet.gate.com/v4/ws/futures/usdt}</li>
-     *   <li>生产网: {@code wss://fx-ws.gateio.ws/v4/ws/usdt}</li>
-     * </ul>
-     */
-    public String getWsUrl() {
-        return isProduction
-                ? "wss://fx-ws.gateio.ws/v4/ws/usdt"
-                : "wss://ws-testnet.gate.com/v4/ws/futures/usdt";
-    }
-
-    // ==================== 认证信息 ====================
-
-    /** @return Gate API v4 密钥 */
-    public String getApiKey() { return apiKey; }
-    /** @return Gate API v4 签名密钥,用于 HMAC-SHA512 签名 */
-    public String getApiSecret() { return apiSecret; }
-
-    // ==================== 交易标的 ====================
-
-    /** @return 合约名称(如 ETH_USDT、XAU_USDT) */
-    public String getContract() { return contract; }
-    /** @return 杠杆倍数(如 "100" 表示 100x) */
-    public String getLeverage() { return leverage; }
-
-    // ==================== 持仓配置 ====================
-
-    /** @return 保证金模式(cross=全仓 / isolated=逐仓) */
-    public String getMarginMode() { return marginMode; }
-    /** @return 持仓模式(single=单向 / dual=双向 / dual_plus) */
-    public String getPositionMode() { return positionMode; }
-
-    // ==================== 策略参数 ====================
-
-    /** @return 网格间距比例(如 0.0015 表示 0.15%),用于生成价格队列和计算止盈价 */
-    public BigDecimal getGridRate() { return gridRate; }
-    /** @return 整体止盈阈值(USDT),累计已实现盈亏 ≥ 此值时策略停止 */
-    public BigDecimal getOverallTp() { return overallTp; }
-    /** @return 最大亏损阈值(USDT),累计已实现盈亏 ≤ -此值时策略停止 */
-    public BigDecimal getMaxLoss() { return maxLoss; }
-    /** @return 每次下单的张数(如 "1" 表示 1 张合约) */
-    public String getQuantity() { return quantity; }
-    /** @return 网格价格队列的容量上限(超出时截断尾部) */
-    public int getGridQueueSize() { return gridQueueSize; }
-
-    // ==================== 风险控制 ====================
-
-    /** @return 保证金占初始本金比例上限(默认 0.2 即 20%),超限跳过开仓 */
-    public BigDecimal getMarginRatioLimit() { return marginRatioLimit; }
-    /** @return 补仓最大重试次数(当前版本未使用) */
-    public int getReopenMaxRetries() { return reopenMaxRetries; }
-
-    // ==================== 盈亏计算 ====================
-
-    /** @return 合约乘数(单张合约代表的基础资产数量,如 ETH_USDT=0.01) */
-    public BigDecimal getContractMultiplier() { return contractMultiplier; }
-    /** @return 未实现盈亏计价模式:LAST_PRICE(最新成交价)/ MARK_PRICE(标记价格) */
-    public PnLPriceMode getUnrealizedPnlPriceMode() { return unrealizedPnlPriceMode; }
-
-    // ==================== 环境 ====================
-
-    /** @return 是否为生产环境(true=实盘生产网 / false=模拟盘测试网) */
-    public boolean isProduction() { return isProduction; }
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * GateConfig 的流式构造器,提供合理的默认值。
-     *
-     * <h3>必填项</h3>
-     * {@code apiKey} 和 {@code apiSecret} 必须设置,其余参数均有默认值。
-     *
-     * <h3>默认值</h3>
-     * BTC_USDT / 10x / cross(全仓) / dual(双向) / gridRate=0.35% /
-     * overallTp=0.5 / maxLoss=7.5 / quantity=1 / isProduction=false
-     */
-    public static class Builder {
-        /** Gate API v4 密钥(必填) */
-        private String apiKey;
-        /** Gate API v4 签名密钥(必填) */
-        private String apiSecret;
-        /** 合约名称,默认 BTC_USDT */
-        private String contract = "BTC_USDT";
-        /** 杠杆倍数,默认 "10" */
-        private String leverage = "10";
-        /** 保证金模式,默认 "cross"(全仓) */
-        private String marginMode = "cross";
-        /** 持仓模式,默认 "dual"(双向) */
-        private String positionMode = "dual";
-        /** 网格间距比例,默认 0.0035(0.35%) */
-        private BigDecimal gridRate = new BigDecimal("0.0035");
-        /** 整体止盈阈值(USDT),默认 0.5 */
-        private BigDecimal overallTp = new BigDecimal("0.5");
-        /** 最大亏损阈值(USDT),默认 7.5 */
-        private BigDecimal maxLoss = new BigDecimal("7.5");
-        /** 每次下单张数,默认 "1" */
-        private String quantity = "1";
-        /** 是否为生产环境,默认 false(测试网) */
-        private boolean isProduction = false;
-        /** 补仓最大重试次数,默认 3 */
-        private int reopenMaxRetries = 3;
-        /** 网格队列容量,默认 50 */
-        private int gridQueueSize = 50;
-        /** 保证金占初始本金比例上限,默认 0.2(20%) */
-        private BigDecimal marginRatioLimit = new BigDecimal("0.2");
-        /** 合约乘数,默认 0.001 */
-        private BigDecimal contractMultiplier = new BigDecimal("0.001");
-        /** 未实现盈亏计价模式,默认 LAST_PRICE(最新成交价) */
-        private PnLPriceMode unrealizedPnlPriceMode = PnLPriceMode.LAST_PRICE;
-
-        /** 设置 API Key */
-        public Builder apiKey(String apiKey) { this.apiKey = apiKey; return this; }
-        /** 设置 API Secret */
-        public Builder apiSecret(String apiSecret) { this.apiSecret = apiSecret; return this; }
-        /** 设置合约名称 */
-        public Builder contract(String contract) { this.contract = contract; return this; }
-        /** 设置杠杆倍数 */
-        public Builder leverage(String leverage) { this.leverage = leverage; return this; }
-        /** 设置保证金模式(cross=全仓 / isolated=逐仓) */
-        public Builder marginMode(String marginMode) { this.marginMode = marginMode; return this; }
-        /** 设置持仓模式(single=单向 / dual=双向) */
-        public Builder positionMode(String positionMode) { this.positionMode = positionMode; return this; }
-        /** 设置网格间距比例 */
-        public Builder gridRate(BigDecimal gridRate) { this.gridRate = gridRate; return this; }
-        /** 设置整体止盈阈值(USDT) */
-        public Builder overallTp(BigDecimal overallTp) { this.overallTp = overallTp; return this; }
-        /** 设置最大亏损阈值(USDT) */
-        public Builder maxLoss(BigDecimal maxLoss) { this.maxLoss = maxLoss; return this; }
-        /** 设置每次下单张数 */
-        public Builder quantity(String quantity) { this.quantity = quantity; return this; }
-        /** 设置环境(true=实盘生产网 / false=模拟盘测试网) */
-        public Builder isProduction(boolean isProduction) { this.isProduction = isProduction; return this; }
-        /** 设置补仓最大重试次数 */
-        public Builder reopenMaxRetries(int reopenMaxRetries) { this.reopenMaxRetries = reopenMaxRetries; return this; }
-        /** 设置合约乘数(单张合约代表的基础资产数量) */
-        public Builder contractMultiplier(BigDecimal contractMultiplier) { this.contractMultiplier = contractMultiplier; return this; }
-        /** 设置未实现盈亏计价模式 */
-        public Builder unrealizedPnlPriceMode(PnLPriceMode mode) { this.unrealizedPnlPriceMode = mode; return this; }
-
-        public GateConfig build() {
-            return new GateConfig(this);
-        }
-    }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
deleted file mode 100644
index feb3fa0..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
+++ /dev/null
@@ -1,780 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import io.gate.gateapi.ApiClient;
-import io.gate.gateapi.ApiException;
-import io.gate.gateapi.GateApiException;
-import io.gate.gateapi.api.AccountApi;
-import io.gate.gateapi.api.FuturesApi;
-import io.gate.gateapi.models.*;
-import lombok.extern.slf4j.Slf4j;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Gate 网格交易服务 — 策略核心。
- *
- * <h3>策略</h3>
- * 多空双开基底 → 生成价格网格队列 → K线触达网格线 → 开仓+设止盈 → 队列动态转移。
- * 每根 K 线更新 {@code unrealizedPnl}(浮动盈亏),平仓后累加到 {@code cumulativePnl}(已实现盈亏)。
- *
- * <h3>未实现盈亏公式(正向合约)</h3>
- * <pre>
- *   多仓: 持仓量 × 合约乘数 × (计价价格 − 开仓均价)
- *   空仓: 持仓量 × 合约乘数 × (开仓均价 − 计价价格)
- * </pre>
- * 计价价格支持切换:{@link GateConfig.PnLPriceMode#LAST_PRICE 最新成交价} 或
- * {@link GateConfig.PnLPriceMode#MARK_PRICE 标记价格}(通过 {@link #setMarkPrice(BigDecimal)} 注入)。
- * 入场价和持仓量由 {@link #onPositionUpdate(String, Position.ModeEnum, BigDecimal, BigDecimal)} 实时更新。
- *
- * <h3>状态机</h3>
- * <pre>
- *   WAITING_KLINE → (首K线) → 异步双开基底
- *
- *   仓位推送(dual_long/dual_short) → 基底成交 → 记录入场价 → 双基底都成交 → 生成队列 → ACTIVE
- *
- *   ACTIVE:
- *     ├─ 每根K线 → 更新 unrealizedPnl + processShortGrid + processLongGrid
- *     │    ├─ 当前价 &lt; 空仓队列元素 → 匹配 → 开空 + 以多仓队列首元素为种子生成新元素加入多仓队列
- *     │    └─ 当前价 &gt; 多仓队列元素 → 匹配 → 开多 + 以空仓队列首元素为种子生成新元素加入空仓队列
- *     ├─ 仓位推送(非基底) → 设止盈条件单 entry × (1±gridRate),使用 plan-close-*-position
- *     ├─ 保证金≥初始本金 marginRatioLimit → 跳过开仓,队列照常更新
- *     ├─ 额外反向开仓:触发价夹在多/空持仓均价之间且多持仓均价&gt;空持仓均价时,额外反向开仓一次
- *     └─ cumulativePnl ≥ overallTp 或 ≤ -maxLoss → STOPPED
- * </pre>
- *
- * <h3>队列转移规则</h3>
- * 触发后不再简单复制 matched 元素到对方队列,而是以对方队列首元素为种子,生成新元素:
- * <ul>
- *   <li>空仓队列触发 → 多仓队列新增:以多仓队列首元素(最小价)为基准,生成递减元素</li>
- *   <li>多仓队列触发 → 空仓队列新增:以空仓队列首元素(最高价)为基准,生成递增元素</li>
- * </ul>
- *
- * <h3>贴近持仓均价过滤</h3>
- * 转移生成新元素时,若新元素与对应方向持仓均价的差距小于 gridRate,则跳过该元素,
- * 避免在持仓成本附近生成无效网格线。
- *
- * <h3>额外反向开仓条件</h3>
- * 当触发价在空仓均价和回撤后的多仓均价之间(即多&gt;空且价格夹在中间),额外反向开仓一次:
- * <ul>
- *   <li>空仓队列触发 → 额外开多:需满足 shortEntryPrice &lt; currentPrice &lt; longEntryPrice × (1 − gridRate)</li>
- *   <li>多仓队列触发 → 额外开空:需满足 shortEntryPrice × (1 + gridRate) &lt; currentPrice &lt; longEntryPrice</li>
- * </ul>
- *
- * <h3>止盈条件单</h3>
- * 使用 Gate API 的 plan-close-long-position / plan-close-short-position(仓位计划止盈止损),
- * 支持指定张数部分平仓。每次网格触发开仓 quantity 张,只为该批张数创建独立条件单,互不覆盖。
- *
- * @author Administrator
- */
-@Slf4j
-public class GateGridTradeService {
-
-    public enum StrategyState {
-        WAITING_KLINE, OPENING, ACTIVE, STOPPED
-    }
-
-    /**
-     * 止盈条件单 order_type:仓位计划止盈止损 — 平多仓(支持部分平仓,size&lt;0)。
-     * 注意:不能用 close-long-position(仅支持全平且双仓需 auto_size),
-     * 必须用 plan-close-long-position 以支持指定张数部分平仓。
-     */
-    private static final String ORDER_TYPE_CLOSE_LONG = "plan-close-long-position";
-    /**
-     * 止盈条件单 order_type:仓位计划止盈止损 — 平空仓(支持部分平仓,size&gt;0)。
-     * 注意:不能用 close-short-position(仅支持全平且双仓需 auto_size),
-     * 必须用 plan-close-short-position 以支持指定张数部分平仓。
-     */
-    private static final String ORDER_TYPE_CLOSE_SHORT = "plan-close-short-position";
-
-    private final GateConfig config;
-    private final GateTradeExecutor executor;
-    private final FuturesApi futuresApi;
-    private static final String SETTLE = "usdt";
-
-    private volatile StrategyState state = StrategyState.WAITING_KLINE;
-
-    /** 空仓价格队列,降序排列(大→小),容量 gridQueueSize */
-    private final List<BigDecimal> shortPriceQueue = Collections.synchronizedList(new ArrayList<>());
-    /** 多仓价格队列,升序排列(小→大),容量 gridQueueSize */
-    private final List<BigDecimal> longPriceQueue = Collections.synchronizedList(new ArrayList<>());
-
-    /** 基底空头入场价 */
-    private BigDecimal shortBaseEntryPrice;
-    /** 基底多头入场价 */
-    private BigDecimal longBaseEntryPrice;
-    /** 基底多头是否已开 */
-    private volatile boolean baseLongOpened = false;
-    /** 基底空头是否已开 */
-    private volatile boolean baseShortOpened = false;
-
-    /** 空头是否活跃(有仓位) */
-    private volatile boolean shortActive = false;
-    /** 多头是否活跃(有仓位) */
-    private volatile boolean longActive = false;
-
-    private volatile BigDecimal lastKlinePrice;
-    private volatile BigDecimal markPrice = BigDecimal.ZERO;
-    private volatile BigDecimal cumulativePnl = BigDecimal.ZERO;
-    private volatile BigDecimal unrealizedPnl = BigDecimal.ZERO;
-    private volatile BigDecimal longEntryPrice = BigDecimal.ZERO;
-    private volatile BigDecimal shortEntryPrice = BigDecimal.ZERO;
-    private volatile BigDecimal longPositionSize = BigDecimal.ZERO;
-    private volatile BigDecimal shortPositionSize = BigDecimal.ZERO;
-    private Long userId;
-    private volatile BigDecimal initialPrincipal = BigDecimal.ZERO;
-
-    public GateGridTradeService(GateConfig config) {
-        this.config = config;
-        ApiClient apiClient = new ApiClient();
-        apiClient.setBasePath(config.getRestBasePath());
-        apiClient.setApiKeySecret(config.getApiKey(), config.getApiSecret());
-        this.futuresApi = new FuturesApi(apiClient);
-        this.executor = new GateTradeExecutor(apiClient, config.getContract());
-    }
-
-    // ---- 初始化 ----
-
-    /**
-     * 初始化策略环境。
-     *
-     * <h3>执行顺序</h3>
-     * <ol>
-     *   <li>获取用户 ID(用于私有频道订阅 payload)</li>
-     *   <li>获取账户信息 → 记录初始本金</li>
-     *   <li>如需要,切换为双向持仓模式</li>
-     *   <li>如需要,调整持仓模式(single/dual)</li>
-     *   <li>清除旧的止盈止损条件单</li>
-     *   <li>平掉所有已有仓位</li>
-     *   <li>设置杠杆倍数</li>
-     * </ol>
-     */
-    public void init() {
-        try {
-            ApiClient detailClient = new ApiClient();
-            detailClient.setBasePath(config.getRestBasePath());
-            detailClient.setApiKeySecret(config.getApiKey(), config.getApiSecret());
-            AccountDetail detail = new AccountApi(detailClient).getAccountDetail();
-            this.userId = detail.getUserId();
-            log.info("[Gate] 用户ID: {}", userId);
-
-            FuturesAccount account = futuresApi.listFuturesAccounts(SETTLE);
-            this.initialPrincipal = new BigDecimal(account.getTotal());
-            log.info("[Gate] 初始本金: {} USDT", initialPrincipal);
-
-            futuresApi.cancelPriceTriggeredOrderList(SETTLE, config.getContract());
-            log.info("[Gate] 旧条件单已清除");
-            closeExistingPositions();
-
-            //设置持仓模式为双向持仓
-            Boolean inDualMode = account.getInDualMode();
-            if (!inDualMode) {
-                try {
-                    futuresApi.setDualModeCall(SETTLE,true,null).execute();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-
-            try {
-                futuresApi.updateDualModePositionLeverageCall(
-                        SETTLE, config.getContract(), config.getLeverage(),
-                        null, null).execute();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-
-            if (!config.getMarginMode().equals(account.getMarginMode())) {
-
-                UpdateDualCompPositionCrossModeRequest updateDualCompPositionCrossModeRequest = new UpdateDualCompPositionCrossModeRequest();
-                updateDualCompPositionCrossModeRequest.setMode(config.getMarginMode());
-                updateDualCompPositionCrossModeRequest.setContract(config.getContract());
-                try {
-                    futuresApi.updateDualCompPositionCrossModeCall(SETTLE, updateDualCompPositionCrossModeRequest, null).execute();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-            log.info("[Gate] 持仓模式: {} 余额: {}", config.getPositionMode(), account.getAvailable());
-            log.info("[Gate] 杠杆: {}x {}", config.getLeverage(), config.getMarginMode());
-        } catch (GateApiException e) {
-            log.error("[Gate] 初始化失败, label:{}, msg:{}", e.getErrorLabel(), e.getMessage());
-        } catch (ApiException e) {
-            log.error("[Gate] 初始化失败, code:{}", e.getCode());
-        }
-    }
-
-    /**
-     * 平掉当前合约的所有已有仓位。
-     *
-     * <h3>平仓策略</h3>
-     * <ul>
-     *   <li>单向持仓:size=相反数,reduceOnly=true,市价 IOC 平仓</li>
-     *   <li>双向持仓:size=0,close=false,autoSize=LONG/SHORT,reduceOnly=true,市价 IOC 全平</li>
-     * </ul>
-     *
-     * <h3>注意事项</h3>
-     * 双向持仓模式下必须使用 autoSize 参数,不能直接传负数 size,
-     * 否则 Gate API 会拒绝(双向模式下空头 size 为负是正常的持仓方向)。
-     */
-    private void closeExistingPositions() {
-        try {
-            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));
-                Position.ModeEnum mode = pos.getMode();
-                FuturesOrder closeOrder = new FuturesOrder();
-                closeOrder.setContract(config.getContract());
-                closeOrder.setPrice("0");
-                closeOrder.setTif(FuturesOrder.TifEnum.IOC);
-                closeOrder.setReduceOnly(true);
-                if (mode != null && mode.getValue() != null && mode.getValue().contains("dual")) {
-                    closeOrder.setSize("0");
-                    closeOrder.setClose(false);
-                    closeOrder.setAutoSize(size > 0 ? FuturesOrder.AutoSizeEnum.LONG : FuturesOrder.AutoSizeEnum.SHORT);
-                } else {
-                    closeOrder.setSize(closeSize);
-                }
-                closeOrder.setText("t-grid-init-close");
-                futuresApi.createFuturesOrder(SETTLE, closeOrder, null);
-                log.info("[Gate] 平已有仓位, 方向:{}, size:{}, mode:{}", size > 0 ? "多" : "空", sizeStr, mode);
-            }
-        } catch (GateApiException e) {
-            log.warn("[Gate] 平仓位失败, label:{}, msg:{}", e.getErrorLabel(), e.getMessage());
-        } catch (Exception e) {
-            log.warn("[Gate] 平仓位异常", e);
-        }
-    }
-
-    // ---- 启动/停止 ----
-
-    /**
-     * 启动网格策略。重置所有状态变量和队列,进入 WAITING_KLINE 等待首根 K 线。
-     * 仅当当前状态为 WAITING_KLINE 或 STOPPED 时才允许启动。
-     */
-    public void startGrid() {
-        if (state != StrategyState.WAITING_KLINE && state != StrategyState.STOPPED) {
-            log.warn("[Gate] 策略已在运行中, state:{}", state);
-            return;
-        }
-        state = StrategyState.WAITING_KLINE;
-        cumulativePnl = BigDecimal.ZERO;
-        unrealizedPnl = BigDecimal.ZERO;
-        markPrice = BigDecimal.ZERO;
-        longEntryPrice = BigDecimal.ZERO;
-        shortEntryPrice = BigDecimal.ZERO;
-        longPositionSize = BigDecimal.ZERO;
-        shortPositionSize = BigDecimal.ZERO;
-        baseLongOpened = false;
-        baseShortOpened = false;
-        longActive = false;
-        shortActive = false;
-        shortPriceQueue.clear();
-        longPriceQueue.clear();
-        log.info("[Gate] 网格策略已启动");
-    }
-
-    /**
-     * 停止网格策略。取消所有条件单 → 关闭交易线程池。
-     * 状态设为 STOPPED,K 线回调将直接返回不再处理。
-     */
-    public void stopGrid() {
-        state = StrategyState.STOPPED;
-        executor.cancelAllPriceTriggeredOrders();
-        executor.shutdown();
-        log.info("[Gate] 策略已停止, 累计盈亏: {}", cumulativePnl);
-    }
-
-    // ---- K线回调 ----
-
-    /**
-     * K 线回调入口。由 {@link CandlestickChannelHandler} 在收到 WebSocket K 线推送时调用。
-     *
-     * <h3>处理流程</h3>
-     * <ol>
-     *   <li>更新 lastKlinePrice → 计算 unrealizedPnl(浮动盈亏)</li>
-     *   <li>STOPPED → 直接返回(仅保留盈亏更新)</li>
-     *   <li>WAITING_KLINE → 切换为 OPENING → 异步提交基底双开(开多+开空)</li>
-     *   <li>OPENING → 等待仓位推送回调生成队列,此处返回</li>
-     *   <li>ACTIVE → 执行 processShortGrid + processLongGrid</li>
-     * </ol>
-     *
-     * <h3>注意</h3>
-     * 基底双开下单提交到 GateTradeExecutor 的独立线程池中异步执行,
-     * 成交状态由 onPositionUpdate 回调驱动,不阻塞 WS 回调线程。
-     *
-     * @param closePrice K 线收盘价(即当前最新成交价)
-     */
-    public void onKline(BigDecimal closePrice) {
-        lastKlinePrice = closePrice;
-        updateUnrealizedPnl();
-        if (state == StrategyState.STOPPED) {
-            return;
-        }
-
-        if (state == StrategyState.WAITING_KLINE) {
-            state = StrategyState.OPENING;
-            log.info("[Gate] 首根K线到达,开基底仓位...");
-            executor.openLong(config.getQuantity(), () -> {
-                log.info("[Gate] 基底多单已提交");
-            }, null);
-            executor.openShort(negate(config.getQuantity()), () -> {
-                log.info("[Gate] 基底空单已提交");
-            }, null);
-            return;
-        }
-
-        if (state != StrategyState.ACTIVE) {
-            return;
-        }
-        processShortGrid(closePrice);
-        processLongGrid(closePrice);
-    }
-
-    // ---- 仓位推送回调 ----
-
-    /**
-     * 仓位推送回调。由 {@link PositionsChannelHandler} 在收到 WebSocket 仓位更新时调用。
-     *
-     * <h3>处理逻辑</h3>
-     * <ul>
-     *   <li><b>有仓位 (size ≠ 0)</b>:
-     *     <ul>
-     *       <li>首次开仓(基底):标记 baseOpened=true,记录基底入场价,双基底都成交后生成网格队列</li>
-     *       <li>仓位净增加(size > 之前记录值):说明网格触发了新开仓 → 取对应方向队列首元素为止盈价,设止盈条件单</li>
-     *       <li>仓位减少或不变(止盈平仓后):仅更新 positionSize,不重复设止盈</li>
-     *     </ul>
-     *   </li>
-     *   <li><b>无仓位 (size = 0)</b>:清空活跃标记和持仓量</li>
-     * </ul>
-     *
-     * @param contract   合约名称
-     * @param mode       持仓模式(DUAL_LONG / DUAL_SHORT)
-     * @param size       持仓张数(多头为正、空头为负)
-     * @param entryPrice 当前持仓加权均价(交易所计算)
-     */
-    public void onPositionUpdate(String contract, Position.ModeEnum mode, BigDecimal size,
-                                  BigDecimal entryPrice) {
-        if (state == StrategyState.STOPPED || state == StrategyState.WAITING_KLINE) {
-            return;
-        }
-
-        boolean hasPosition = size.abs().compareTo(BigDecimal.ZERO) > 0;
-
-        if (Position.ModeEnum.DUAL_LONG == mode) {
-            if (hasPosition) {
-                longActive = true;
-                longEntryPrice = entryPrice;
-                if (!baseLongOpened) {
-                    longPositionSize = size;
-                    longBaseEntryPrice = entryPrice;
-                    baseLongOpened = true;
-                    log.info("[Gate] 基底多成交价: {}", longBaseEntryPrice);
-                    tryGenerateQueues();
-                } else if (size.compareTo(longPositionSize) > 0) {
-                    longPositionSize = size;
-                    if (longPriceQueue.isEmpty()) {
-                        log.warn("[Gate] 多仓队列为空,无法设止盈");
-                    } else {
-                        BigDecimal tpPrice = longPriceQueue.get(0);
-                        executor.placeTakeProfit(tpPrice,
-                                FuturesPriceTrigger.RuleEnum.NUMBER_1, ORDER_TYPE_CLOSE_LONG, negate(config.getQuantity()));
-                        log.info("[Gate] 多单止盈已设, entry:{}, tp:{}, size:{}", entryPrice, tpPrice, negate(config.getQuantity()));
-                    }
-                } else {
-                    longPositionSize = size;
-                }
-            } else {
-                longActive = false;
-                longPositionSize = BigDecimal.ZERO;
-            }
-        } else if (Position.ModeEnum.DUAL_SHORT == mode) {
-            if (hasPosition) {
-                shortActive = true;
-                shortEntryPrice = entryPrice;
-                if (!baseShortOpened) {
-                    shortPositionSize = size.abs();
-                    shortBaseEntryPrice = entryPrice;
-                    baseShortOpened = true;
-                    log.info("[Gate] 基底空成交价: {}", shortBaseEntryPrice);
-                    tryGenerateQueues();
-                } else if (size.abs().compareTo(shortPositionSize) > 0) {
-                    shortPositionSize = size.abs();
-                    if (shortPriceQueue.isEmpty()) {
-                        log.warn("[Gate] 空仓队列为空,无法设止盈");
-                    } else {
-                        BigDecimal tpPrice = shortPriceQueue.get(0);
-                        executor.placeTakeProfit(tpPrice,
-                                FuturesPriceTrigger.RuleEnum.NUMBER_2, ORDER_TYPE_CLOSE_SHORT, config.getQuantity());
-                        log.info("[Gate] 空单止盈已设, entry:{}, tp:{}, size:{}", entryPrice, tpPrice, config.getQuantity());
-                    }
-                } else {
-                    shortPositionSize = size.abs();
-                }
-            } else {
-                shortActive = false;
-                shortPositionSize = BigDecimal.ZERO;
-            }
-        }
-    }
-
-    // ---- 平仓推送回调 ----
-
-    /**
-     * 平仓推送回调。由 {@link PositionClosesChannelHandler} 在收到平仓推送时调用。
-     *
-     * <h3>累加规则</h3>
-     * cumulativePnl += pnl。止盈平仓时 pnl > 0,止损平仓时 pnl < 0。
-     * 累加后检查停止条件:≥ overallTp 或 ≤ -maxLoss。
-     *
-     * @param contract 合约名称
-     * @param side     平仓方向("long" / "short")
-     * @param pnl      本次平仓的盈亏金额
-     */
-    public void onPositionClose(String contract, String side, BigDecimal pnl) {
-        if (state == StrategyState.STOPPED) {
-            return;
-        }
-        cumulativePnl = cumulativePnl.add(pnl);
-        log.info("[Gate] 盈亏累加:{}, 方向:{}, 累计:{}", pnl, side, cumulativePnl);
-
-        if (cumulativePnl.compareTo(config.getOverallTp()) >= 0) {
-            log.info("[Gate] 已达止盈目标 {}→已停止", cumulativePnl);
-            state = StrategyState.STOPPED;
-        } else if (cumulativePnl.compareTo(config.getMaxLoss().negate()) <= 0) {
-            log.info("[Gate] 已达亏损上限 {}→已停止", cumulativePnl);
-            state = StrategyState.STOPPED;
-        }
-    }
-
-    // ---- 网格队列处理 ----
-
-    /**
-     * 尝试生成网格队列。双基底(多+空)都成交后才触发:
-     * 生成空仓队列 + 多仓队列 → 状态切换为 ACTIVE。
-     */
-    private void tryGenerateQueues() {
-        if (baseLongOpened && baseShortOpened) {
-            generateShortQueue();
-            generateLongQueue();
-            state = StrategyState.ACTIVE;
-            log.info("[Gate] 网格队列已生成, 空队首:{} → 尾:{}, 多队首:{} → 尾:{}, 已激活",
-                    shortPriceQueue.get(0), shortPriceQueue.get(shortPriceQueue.size() - 1),
-                    longPriceQueue.get(0), longPriceQueue.get(longPriceQueue.size() - 1));
-        }
-    }
-
-    /**
-     * 生成空仓价格队列。
-     * 以空头基底入场价 shortBaseEntryPrice 为基准,按 gridRate 递减生成 gridQueueSize 个价格元素:
-     * <pre>shortBaseEntryPrice × (1 − gridRate × i), i=1..gridQueueSize</pre>
-     * 队列降序排列(大→小),方便 processShortGrid 中从头遍历。
-     */
-    private void generateShortQueue() {
-        shortPriceQueue.clear();
-        BigDecimal step = config.getGridRate();
-        for (int i = 1; i <= config.getGridQueueSize(); i++) {
-            shortPriceQueue.add(shortBaseEntryPrice.multiply(BigDecimal.ONE.subtract(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP));
-        }
-        shortPriceQueue.sort((a, b) -> b.compareTo(a));
-        //输出队列:shortPriceQueue;
-        log.info("[Gate] 空队列:{}", shortPriceQueue);
-    }
-
-    /**
-     * 生成多仓价格队列。
-     * 以多头基底入场价 longBaseEntryPrice 为基准,按 gridRate 递增生成 gridQueueSize 个价格元素:
-     * <pre>longBaseEntryPrice × (1 + gridRate × i), i=1..gridQueueSize</pre>
-     * 队列升序排列(小→大),方便 processLongGrid 中从头遍历。
-     */
-    private void generateLongQueue() {
-        longPriceQueue.clear();
-        BigDecimal step = config.getGridRate();
-        for (int i = 1; i <= config.getGridQueueSize(); i++) {
-            longPriceQueue.add(longBaseEntryPrice.multiply(BigDecimal.ONE.add(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP));
-        }
-        longPriceQueue.sort(BigDecimal::compareTo);
-        log.info("[Gate] 多队列:{}", longPriceQueue);
-    }
-
-    /**
-     * 空仓网格处理(价格跌破空仓队列中的高价)。
-     *
-     * <h3>匹配规则</h3>
-     * 遍历空仓队列(降序),收集所有大于当前价的元素为 matched。
-     * 队列为降序排列,一旦遇 price ≤ currentPrice 即停止遍历。
-     *
-     * <h3>执行流程</h3>
-     * <ol>
-     *   <li>匹配队列元素 → 为空则直接返回</li>
-     *   <li>空仓队列:移除 matched 元素,尾部补充新元素(尾价 × (1 − gridRate) 循环递减)</li>
-     *   <li>多仓队列:以多仓队列首元素(最小价)为种子,生成 matched.size() 个递减元素加入</li>
-     *   <li>保证金检查 → 安全则开空一次</li>
-     *   <li>额外反向开多:若多仓均价 > 空仓均价 且 当前价夹在中间且远离多仓均价</li>
-     * </ol>
-     *
-     * <h3>多仓队列转移过滤</h3>
-     * 新增元素若与多仓持仓均价差距小于 gridRate,则跳过该元素(避免在持仓成本附近生成无效网格线)。
-     */
-    private void processShortGrid(BigDecimal currentPrice) {
-        List<BigDecimal> matched = new ArrayList<>();
-        synchronized (shortPriceQueue) {
-            for (BigDecimal p : shortPriceQueue) {
-                if (p.compareTo(currentPrice) > 0) {
-                    matched.add(p);
-                } else {
-                    break;
-                }
-            }
-        }
-        log.info("[Gate] 原空队列:{}", shortPriceQueue);
-        if (matched.isEmpty()) {
-            log.info("[Gate] 空仓队列未触发, 当前价:{}", currentPrice);
-            return;
-        }
-        log.info("[Gate] 空仓队列触发, 匹配{}个元素, 当前价:{}", matched.size(), currentPrice);
-
-        synchronized (shortPriceQueue) {
-            shortPriceQueue.removeAll(matched);
-            BigDecimal min = shortPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : shortPriceQueue.get(shortPriceQueue.size() - 1);
-            BigDecimal step = config.getGridRate();
-            for (int i = 0; i < matched.size(); i++) {
-                min = min.multiply(BigDecimal.ONE.subtract(step)).setScale(1, RoundingMode.HALF_UP);
-                shortPriceQueue.add(min);
-                log.info("[Gate] 空队列增加:{}", min);
-            }
-
-            shortPriceQueue.sort((a, b) -> b.compareTo(a));
-
-            log.info("[Gate] 现空队列:{}", shortPriceQueue);
-        }
-
-        synchronized (longPriceQueue) {
-            BigDecimal first = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(0);
-            BigDecimal step = config.getGridRate();
-            for (int i = 1; i <= matched.size(); i++) {
-                BigDecimal elem = first.multiply(BigDecimal.ONE.subtract(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP);
-                if (longEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                        && currentPrice.subtract(longEntryPrice).abs().compareTo(longEntryPrice.multiply(step)) < 0) {
-                    log.info("[Gate] 多队列跳过(price≈longEntry):{}", elem);
-                    continue;
-                }
-                longPriceQueue.add(elem);
-                log.info("[Gate] 多队列增加:{}", elem);
-            }
-            longPriceQueue.sort(BigDecimal::compareTo);
-            while (longPriceQueue.size() > config.getGridQueueSize()) {
-                longPriceQueue.remove(longPriceQueue.size() - 1);
-            }
-            log.info("[Gate] 现多队列:{}", longPriceQueue);
-        }
-
-        if (!isMarginSafe()) {
-            log.warn("[Gate] 保证金超限,跳过空单开仓");
-        } else {
-            executor.openShort(negate(config.getQuantity()), null, null);
-            if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                    && longEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                    && longEntryPrice.compareTo(shortEntryPrice) > 0
-                    && currentPrice.compareTo(shortEntryPrice) > 0
-                    && currentPrice.compareTo(longEntryPrice.multiply(BigDecimal.ONE.subtract(config.getGridRate()))) < 0) {
-                executor.openLong(config.getQuantity(), null, null);
-                log.info("[Gate] 触发价在多/空持仓价之间且多>空且远离多仓均价, 额外开多一次, 当前价:{}", currentPrice);
-            }
-        }
-    }
-
-    /**
-     * 多仓网格处理(价格涨破多仓队列中的低价)。
-     *
-     * <h3>匹配规则</h3>
-     * 遍历多仓队列(升序),收集所有小于当前价的元素为 matched。
-     * 队列为升序排列,一旦遇 price ≥ currentPrice 即停止遍历。
-     *
-     * <h3>执行流程</h3>
-     * <ol>
-     *   <li>匹配队列元素 → 为空则直接返回</li>
-     *   <li>多仓队列:移除 matched 元素,尾部补充新元素(尾价 × (1 + gridRate) 循环递增)</li>
-     *   <li>空仓队列:以空仓队列首元素(最高价)为种子,生成 matched.size() 个递增元素加入</li>
-     *   <li>保证金检查 → 安全则开多一次</li>
-     *   <li>额外反向开空:若多仓均价 > 空仓均价 且 当前价夹在中间且远离空仓均价</li>
-     * </ol>
-     *
-     * <h3>空仓队列转移过滤</h3>
-     * 新增元素若与空仓持仓均价差距小于 gridRate,则跳过该元素(避免在持仓成本附近生成无效网格线)。
-     */
-    private void processLongGrid(BigDecimal currentPrice) {
-        List<BigDecimal> matched = new ArrayList<>();
-        synchronized (longPriceQueue) {
-            for (BigDecimal p : longPriceQueue) {
-                if (p.compareTo(currentPrice) < 0) {
-                    matched.add(p);
-                } else {
-                    break;
-                }
-            }
-        }
-        log.info("[Gate] 原多队列:{}", longPriceQueue);
-        if (matched.isEmpty()) {
-            log.info("[Gate] 多仓队列未触发,  当前价:{}", currentPrice);
-            return;
-        }
-
-        log.info("[Gate] 多仓队列触发, 匹配{}个元素, 当前价:{}", matched.size(), currentPrice);
-
-        synchronized (longPriceQueue) {
-            longPriceQueue.removeAll(matched);
-            BigDecimal max = longPriceQueue.isEmpty() ? matched.get(matched.size() - 1) : longPriceQueue.get(longPriceQueue.size() - 1);
-            BigDecimal step = config.getGridRate();
-            for (int i = 0; i < matched.size(); i++) {
-                max = max.multiply(BigDecimal.ONE.add(step)).setScale(1, RoundingMode.HALF_UP);
-                longPriceQueue.add(max);
-
-                log.info("[Gate] 多队列增加:{}", max);
-            }
-            longPriceQueue.sort(BigDecimal::compareTo);
-
-            log.info("[Gate] 现多队列:{}", longPriceQueue);
-        }
-
-        synchronized (shortPriceQueue) {
-            BigDecimal first = shortPriceQueue.isEmpty() ? matched.get(0) : shortPriceQueue.get(0);
-            BigDecimal step = config.getGridRate();
-            for (int i = 1; i <= matched.size(); i++) {
-                BigDecimal elem = first.multiply(BigDecimal.ONE.add(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP);
-                if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                        && currentPrice.subtract(shortEntryPrice).abs().compareTo(shortEntryPrice.multiply(step)) < 0) {
-                    log.info("[Gate] 空队列跳过(price≈shortEntry):{}", elem);
-                    continue;
-                }
-                shortPriceQueue.add(elem);
-                log.info("[Gate] 空队列增加:{}", elem);
-            }
-            shortPriceQueue.sort((a, b) -> b.compareTo(a));
-            while (shortPriceQueue.size() > config.getGridQueueSize()) {
-                shortPriceQueue.remove(shortPriceQueue.size() - 1);
-            }
-            log.info("[Gate] 现空队列:{}", shortPriceQueue);
-        }
-
-        if (!isMarginSafe()) {
-            log.warn("[Gate] 保证金超限,跳过多单开仓");
-        } else {
-            executor.openLong(config.getQuantity(), null, null);
-            if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                    && longEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                    && longEntryPrice.compareTo(shortEntryPrice) > 0
-                    && currentPrice.compareTo(shortEntryPrice.multiply(BigDecimal.ONE.add(config.getGridRate()))) > 0
-                    && currentPrice.compareTo(longEntryPrice) < 0) {
-                executor.openShort(negate(config.getQuantity()), null, null);
-                log.info("[Gate] 触发价在多/空持仓价之间且多>空且远离空仓均价, 额外开空一次, 当前价:{}", currentPrice);
-            }
-        }
-    }
-
-    // ---- 保证金安全阀 ----
-
-    /**
-     * 保证金安全阀检查。
-     *
-     * <p>实时查询当前保证金占用额(positionInitialMargin),计算其占初始本金的比例。
-     * 比例 ≥ marginRatioLimit(默认 20%)时拒绝开仓,但仍照常更新队列。
-     *
-     * <p>查询失败时默认放行(返回 true),避免因 REST API 异常导致策略完全停滞。
-     *
-     * @return true=安全可开仓 / false=保证金超限跳过开仓
-     */
-    private boolean isMarginSafe() {
-        try {
-            FuturesAccount account = futuresApi.listFuturesAccounts(SETTLE);
-            BigDecimal margin = new BigDecimal(account.getPositionInitialMargin());
-            BigDecimal ratio = margin.divide(initialPrincipal, 4, RoundingMode.HALF_UP);
-            log.debug("[Gate] 保证金比例: {}/{}={}", margin, initialPrincipal, ratio);
-            return ratio.compareTo(config.getMarginRatioLimit()) < 0;
-        } catch (Exception e) {
-            log.warn("[Gate] 查保证金失败,默认放行", e);
-            return true;
-        }
-    }
-
-    // ---- 工具 ----
-
-    /**
-     * 取反字符串数字。如 "1" → "-1","-2" → "2"。
-     * 用于开空单时将正数张数转为负数。
-     */
-    private String negate(String qty) {
-        return qty.startsWith("-") ? qty.substring(1) : "-" + qty;
-    }
-
-    /**
-     * 根据持仓和当前价格计算未实现盈亏。
-     *
-     * <h3>正向合约公式</h3>
-     * <pre>
-     *   多仓: 持仓量 × 合约乘数 × (计价价格 − 开仓均价)
-     *   空仓: 持仓量 × 合约乘数 × (开仓均价 − 计价价格)
-     * </pre>
-     * 计价价格由 {@link GateConfig.PnLPriceMode} 决定:LAST_PRICE 用最新成交价,MARK_PRICE 用标记价格。
-     */
-    private void updateUnrealizedPnl() {
-        BigDecimal price = resolvePnlPrice();
-        if (price == null || price.compareTo(BigDecimal.ZERO) == 0) {
-            return;
-        }
-        BigDecimal multiplier = config.getContractMultiplier();
-        BigDecimal longPnl = BigDecimal.ZERO;
-        BigDecimal shortPnl = BigDecimal.ZERO;
-        if (longPositionSize.compareTo(BigDecimal.ZERO) > 0 && longEntryPrice.compareTo(BigDecimal.ZERO) > 0) {
-            longPnl = longPositionSize.multiply(multiplier).multiply(price.subtract(longEntryPrice));
-        }
-        if (shortPositionSize.compareTo(BigDecimal.ZERO) > 0 && shortEntryPrice.compareTo(BigDecimal.ZERO) > 0) {
-            shortPnl = shortPositionSize.multiply(multiplier).multiply(shortEntryPrice.subtract(price));
-        }
-        unrealizedPnl = longPnl.add(shortPnl);
-
-        log.info("[Gate] 未实现盈亏: {}", unrealizedPnl);
-    }
-
-    /**
-     * 根据配置的 PnLPriceMode 返回计价价格。
-     * MARK_PRICE 模式优先使用标记价格(外部注入),未注入时回退到最新成交价。
-     *
-     * @return 计价价格,可能为 null
-     */
-    private BigDecimal resolvePnlPrice() {
-        if (config.getUnrealizedPnlPriceMode() == GateConfig.PnLPriceMode.MARK_PRICE
-                && markPrice.compareTo(BigDecimal.ZERO) > 0) {
-            return markPrice;
-        }
-        return lastKlinePrice;
-    }
-
-    /** @return 最新 K 线价格(每次 onKline 更新) */
-    public BigDecimal getLastKlinePrice() { return lastKlinePrice; }
-    /** 设置标记价格(外部注入,MARK_PRICE 模式时用于盈亏计算) */
-    public void setMarkPrice(BigDecimal markPrice) { this.markPrice = markPrice; }
-    /** @return 策略是否处于活跃状态(非 STOPPED 且非 WAITING_KLINE) */
-    public boolean isStrategyActive() { return state != StrategyState.STOPPED && state != StrategyState.WAITING_KLINE; }
-    /** @return 累计已实现盈亏(平仓推送驱动累加) */
-    public BigDecimal getCumulativePnl() { return cumulativePnl; }
-    /** @return 当前未实现盈亏(每根 K 线实时计算) */
-    public BigDecimal getUnrealizedPnl() { return unrealizedPnl; }
-    /** @return Gate 用户 ID(用于私有频道订阅 payload) */
-    public Long getUserId() { return userId; }
-    /** @return 当前策略状态 */
-    public StrategyState getState() { return state; }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
deleted file mode 100644
index d4cec97..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateKlineWebSocketClient.java
+++ /dev/null
@@ -1,359 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.wsHandler.GateChannelHandler;
-import com.xcong.excoin.modules.okxNewPrice.utils.SSLConfig;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-import org.java_websocket.handshake.ServerHandshake;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Gate WebSocket 连接管理器。
- *
- * <h3>职责</h3>
- * 负责 TCP 连接的建立、维持和恢复。频道逻辑(订阅/解析)全部委托给 {@link GateChannelHandler} 实现类。
- *
- * <h3>生命周期</h3>
- * <pre>
- *   init()        → connect() → startHeartbeat()
- *   destroy()     → unsubscribe 所有 handler → closeBlocking() → shutdown 线程池
- *   onClose()     → reconnectWithBackoff() (最多 3 次,指数退避)
- * </pre>
- *
- * <h3>消息路由</h3>
- * <pre>
- *   onMessage → handleMessage:
- *     1. futures.pong         → cancelPongTimeout
- *     2. subscribe/unsubscribe → 日志
- *     3. error                → 错误日志
- *     4. update/all           → 遍历 channelHandlers → handler.handleMessage(response)
- * </pre>
- *
- * <h3>心跳机制</h3>
- * 采用双重检测:TCP 层的 WebSocket ping/pong + 应用层 futures.ping/futures.pong。
- * 10 秒未收到任何消息 → 发送 futures.ping;25 秒周期检查。
- *
- * <h3>线程安全</h3>
- * 连接状态用 AtomicBoolean(isConnected, isConnecting, isInitialized)。
- * 消息时间戳用 AtomicReference。心跳任务用 synchronized 保护。
- *
- * @author Administrator
- */
-@SuppressWarnings("ALL")
-@Slf4j
-public class GateKlineWebSocketClient {
-
-    private static final String FUTURES_PING = "futures.ping";
-    private static final String FUTURES_PONG = "futures.pong";
-    private static final int HEARTBEAT_TIMEOUT = 10;
-
-    /** WebSocket 地址,由 GateConfig 提供 */
-    private final String wsUrl;
-
-    /** Java-WebSocket 客户端实例 */
-    private WebSocketClient webSocketClient;
-    /** 心跳检测调度器 */
-    private ScheduledExecutorService heartbeatExecutor;
-    /** 心跳超时 Future */
-    private volatile ScheduledFuture<?> pongTimeoutFuture;
-    /** 最后收到消息的时间戳(毫秒) */
-    private final AtomicReference<Long> lastMessageTime = new AtomicReference<>(System.currentTimeMillis());
-
-    /** 连接状态 */
-    private final AtomicBoolean isConnected = new AtomicBoolean(false);
-    /** 连接中标记,防重入 */
-    private final AtomicBoolean isConnecting = new AtomicBoolean(false);
-    /** 初始化标记,防重复 init */
-    private final AtomicBoolean isInitialized = new AtomicBoolean(false);
-
-    /** 频道处理器列表,通过 addChannelHandler 注册 */
-    private final List<GateChannelHandler> channelHandlers = new ArrayList<>();
-
-    /** 重连等异步任务的缓存线程池(daemon 线程) */
-    private final ExecutorService sharedExecutor = Executors.newCachedThreadPool(r -> {
-        Thread t = new Thread(r, "gate-ws-worker");
-        t.setDaemon(true);
-        return t;
-    });
-
-    public GateKlineWebSocketClient(String wsUrl) {
-        this.wsUrl = wsUrl;
-    }
-
-    /**
-     * 注册频道处理器。需在 init() 前调用。
-     *
-     * @param handler 实现了 {@link GateChannelHandler} 接口的频道处理器
-     */
-    public void addChannelHandler(GateChannelHandler handler) {
-        channelHandlers.add(handler);
-    }
-
-    /**
-     * 初始化:建立 WebSocket 连接 → 启动心跳检测。
-     * 使用 {@code AtomicBoolean} 防重入,同一实例只允许初始化一次。
-     */
-    public void init() {
-        if (!isInitialized.compareAndSet(false, true)) {
-            log.warn("[WS] 已初始化过,跳过重复初始化");
-            return;
-        }
-        connect();
-        startHeartbeat();
-    }
-
-    /**
-     * 销毁:取消所有频道订阅 → 关闭 WebSocket 连接 → 关闭线程池。
-     *
-     * <h3>执行顺序</h3>
-     * 先取消订阅(等待 500ms 确保发送完成),再 closeBlocking 关闭连接,
-     * 最后 shutdown 线程池。先关连接再关线程池,避免 onClose 回调中的重连任务访问已关闭的线程池。
-     */
-    public void destroy() {
-        log.info("[WS] 开始销毁...");
-
-        if (webSocketClient != null && webSocketClient.isOpen()) {
-            for (GateChannelHandler handler : channelHandlers) {
-                handler.unsubscribe(webSocketClient);
-            }
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                log.warn("[WS] 取消订阅等待被中断");
-            }
-        }
-
-        if (webSocketClient != null && webSocketClient.isOpen()) {
-            try {
-                webSocketClient.closeBlocking();
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                log.warn("[WS] 关闭连接时被中断");
-            }
-        }
-
-        if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
-            sharedExecutor.shutdown();
-        }
-
-        shutdownExecutorGracefully(heartbeatExecutor);
-        if (pongTimeoutFuture != null) {
-            pongTimeoutFuture.cancel(true);
-        }
-        shutdownExecutorGracefully(sharedExecutor);
-
-        log.info("[WS] 销毁完成");
-    }
-
-    /**
-     * 建立 WebSocket 连接。使用 SSLContext 配置 TLS 协议。
-     *
-     * <h3>连接成功回调</h3>
-     * <ol>
-     *   <li>设置 isConnected=true,isConnecting=false</li>
-     *   <li>重置心跳计时器</li>
-     *   <li>依次订阅所有已注册的频道处理器</li>
-     *   <li>发送首次 ping</li>
-     * </ol>
-     *
-     * <h3>连接关闭回调</h3>
-     * 设置断连状态 → 取消心跳超时 → 异步触发指数退避重连(最多3次)。
-     *
-     * <h3>线程安全</h3>
-     * 使用 {@code AtomicBoolean.isConnecting} 防止并发重连。
-     */
-    private void connect() {
-        if (isConnecting.get() || !isConnecting.compareAndSet(false, true)) {
-            log.info("[WS] 连接进行中,跳过重复请求");
-            return;
-        }
-        try {
-            SSLConfig.configureSSL();
-            System.setProperty("https.protocols", "TLSv1.2,TLSv1.3");
-            URI uri = new URI(wsUrl);
-            if (webSocketClient != null) {
-                try { webSocketClient.closeBlocking(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
-            }
-            webSocketClient = new WebSocketClient(uri) {
-                @Override
-                public void onOpen(ServerHandshake handshake) {
-                    log.info("[WS] 连接成功");
-                    isConnected.set(true);
-                    isConnecting.set(false);
-                    if (sharedExecutor != null && !sharedExecutor.isShutdown()) {
-                        resetHeartbeatTimer();
-                        for (GateChannelHandler handler : channelHandlers) {
-                            handler.subscribe(webSocketClient);
-                        }
-                        sendPing();
-                    } else {
-                        log.warn("[WS] 应用正在关闭,忽略连接成功回调");
-                    }
-                }
-
-                @Override
-                public void onMessage(String message) {
-                    lastMessageTime.set(System.currentTimeMillis());
-                    handleMessage(message);
-                    resetHeartbeatTimer();
-                }
-
-                @Override
-                public void onClose(int code, String reason, boolean remote) {
-                    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] 重连失败", e); }
-                        });
-                    } else {
-                        log.warn("[WS] 线程池已关闭,不执行重连");
-                    }
-                }
-
-                @Override
-                public void onError(Exception ex) {
-                    log.error("[WS] 发生错误", ex);
-                    isConnected.set(false);
-                }
-            };
-            webSocketClient.connect();
-        } catch (URISyntaxException e) {
-            log.error("[WS] URI格式错误", e);
-            isConnecting.set(false);
-        }
-    }
-
-    /**
-     * 消息分发:先处理系统事件(pong/subscribe/error),
-     * 再把 update/all 事件路由到各 channelHandler。
-     * <p>每个 handler 内部通过 channel 名称做二次匹配,匹配成功返回 true 则停止遍历。
-     */
-    private void handleMessage(String message) {
-        try {
-            JSONObject response = JSON.parseObject(message);
-            String channel = response.getString("channel");
-            String event = response.getString("event");
-
-            if (FUTURES_PONG.equals(channel)) {
-                log.debug("[WS] 收到 pong 响应");
-                cancelPongTimeout();
-                return;
-            }
-            if ("subscribe".equals(event)) {
-                log.info("[WS] {} 订阅成功: {}", channel, response.getJSONObject("result"));
-                return;
-            }
-            if ("unsubscribe".equals(event)) {
-                log.info("[WS] {} 取消订阅成功", channel);
-                return;
-            }
-            if ("error".equals(event)) {
-                JSONObject error = response.getJSONObject("error");
-                log.error("[WS] {} 错误, code:{}, msg:{}",
-                        channel,
-                        error != null ? error.getInteger("code") : "N/A",
-                        error != null ? error.getString("message") : response.getString("msg"));
-                return;
-            }
-            if ("update".equals(event) || "all".equals(event)) {
-                for (GateChannelHandler handler : channelHandlers) {
-                    if (handler.handleMessage(response)) return;
-                }
-            }
-        } catch (Exception e) {
-            log.error("[WS] 处理消息失败: {}", message, e);
-        }
-    }
-
-    // ---- heartbeat ----
-
-    /**
-     * 启动心跳检测器。
-     * 使用单线程 ScheduledExecutor,每 25 秒检查一次心跳超时。
-     */
-    private void startHeartbeat() {
-        if (heartbeatExecutor != null && !heartbeatExecutor.isTerminated()) heartbeatExecutor.shutdownNow();
-        heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(r -> { Thread t = new Thread(r, "gate-ws-heartbeat"); t.setDaemon(true); return t; });
-        heartbeatExecutor.scheduleWithFixedDelay(this::checkHeartbeatTimeout, 25, 25, TimeUnit.SECONDS);
-    }
-
-    /**
-     * 重置心跳计时器:取消旧超时任务,提交新的 10 秒超时检测。
-     */
-    private synchronized void resetHeartbeatTimer() {
-        cancelPongTimeout();
-        if (heartbeatExecutor != null && !heartbeatExecutor.isShutdown()) {
-            pongTimeoutFuture = heartbeatExecutor.schedule(this::checkHeartbeatTimeout, HEARTBEAT_TIMEOUT, TimeUnit.SECONDS);
-        }
-    }
-
-    /**
-     * 检查心跳超时:如果距离上次收到消息超过 10 秒,主动发送 futures.ping。
-     */
-    private void checkHeartbeatTimeout() {
-        if (!isConnected.get()) return;
-        if (System.currentTimeMillis() - lastMessageTime.get() >= HEARTBEAT_TIMEOUT * 1000L) sendPing();
-    }
-
-    /**
-     * 发送应用层 futures.ping 消息。
-     */
-    private void sendPing() {
-        try {
-            if (webSocketClient != null && webSocketClient.isOpen()) {
-                JSONObject pingMsg = new JSONObject();
-                pingMsg.put("time", System.currentTimeMillis() / 1000);
-                pingMsg.put("channel", FUTURES_PING);
-                webSocketClient.send(pingMsg.toJSONString());
-                log.debug("[WS] 发送 ping 请求");
-            }
-        } catch (Exception e) { log.warn("[WS] 发送 ping 失败", e); }
-    }
-
-    /**
-     * 取消心跳超时检测任务。
-     */
-    private synchronized void cancelPongTimeout() {
-        if (pongTimeoutFuture != null && !pongTimeoutFuture.isDone()) pongTimeoutFuture.cancel(true);
-    }
-
-    // ---- reconnect ----
-
-    /**
-     * 指数退避重连。初始延迟 5 秒,每次翻倍,最多重试 3 次。
-     *
-     * @throws InterruptedException 线程被中断
-     */
-    private void reconnectWithBackoff() throws InterruptedException {
-        int attempt = 0, maxAttempts = 3;
-        long delayMs = 5000;
-        while (attempt < maxAttempts) {
-            try { Thread.sleep(delayMs); connect(); return; } catch (Exception e) { log.warn("[WS] 第{}次重连失败", attempt + 1, e); delayMs *= 2; attempt++; }
-        }
-        log.error("[WS] 超过最大重试次数({}),放弃重连", maxAttempts);
-    }
-
-    /**
-     * 优雅关闭线程池:先 shutdown,等待 5 秒,超时则 shutdownNow 强制中断。
-     *
-     * @param executor 需要关闭的线程池
-     */
-    private void shutdownExecutorGracefully(ExecutorService executor) {
-        if (executor == null || executor.isTerminated()) return;
-        try { executor.shutdown(); if (!executor.awaitTermination(5, TimeUnit.SECONDS)) executor.shutdownNow(); }
-        catch (InterruptedException e) { Thread.currentThread().interrupt(); executor.shutdownNow(); }
-    }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
deleted file mode 100644
index 6de0e63..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
+++ /dev/null
@@ -1,248 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import io.gate.gateapi.ApiClient;
-import io.gate.gateapi.api.FuturesApi;
-import io.gate.gateapi.models.FuturesInitialOrder;
-import io.gate.gateapi.models.FuturesOrder;
-import io.gate.gateapi.models.FuturesPriceTrigger;
-import io.gate.gateapi.models.FuturesPriceTriggeredOrder;
-import io.gate.gateapi.models.TriggerOrderResponse;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Gate REST API 执行器。
- *
- * <h3>设计目的</h3>
- * WebSocket 消息在回调线程中处理(如 {@code WebSocketClient} 的 {@code onMessage} 线程)。
- * 下单 REST API 调用可能耗时数百毫秒,若同步执行会阻塞 WS 回调线程,导致心跳超时误判。
- * 本类将所有 REST 调用提交到独立线程池异步执行。
- *
- * <h3>回调设计</h3>
- * 每个下单方法接受 onSuccess/onFailure 两个 Runnable。
- * 基底开仓时 onSuccess 用于标记基底已开,网格触发时通常为 null(成交状态由仓位推送驱动)。
- *
- * <h3>线程模型</h3>
- * <ul>
- *   <li><b>单线程</b>:保证下单顺序(开多→开空→止盈单),避免并发竞争</li>
- *   <li><b>有界队列 64</b>:防止堆积。极端行情下最多累积 64 个任务</li>
- *   <li><b>CallerRunsPolicy</b>:队列满时由提交线程直接同步执行,形成自然背压</li>
- *   <li><b>allowCoreThreadTimeOut</b>:60s 空闲后线程回收,不浪费资源</li>
- * </ul>
- *
- * <h3>调用链</h3>
- * <pre>
- *   GateGridTradeService.onKline → executor.openLong/openShort (基底双开 + 网格触发)
- *   GateGridTradeService.onPositionUpdate → executor.placeTakeProfit (开仓成交后设止盈)
- *   GateGridTradeService.stopGrid → executor.cancelAllPriceTriggeredOrders
- * </pre>
- *
- * @author Administrator
- */
-@Slf4j
-public class GateTradeExecutor {
-
-    private static final String SETTLE = "usdt";
-
-    private final FuturesApi futuresApi;
-    private final String contract;
-
-    /** 交易线程池:单线程 + 有界队列 + 背压策略 */
-    private final ExecutorService executor;
-
-    public GateTradeExecutor(ApiClient apiClient, String contract) {
-        this.futuresApi = new FuturesApi(apiClient);
-        this.contract = contract;
-        this.executor = new ThreadPoolExecutor(
-                1, 1,
-                60L, TimeUnit.SECONDS,
-                new LinkedBlockingQueue<>(64),
-                r -> {
-                    Thread t = new Thread(r, "gate-trade-worker");
-                    t.setDaemon(true);
-                    return t;
-                },
-                new ThreadPoolExecutor.CallerRunsPolicy()
-        );
-        ((ThreadPoolExecutor) executor).allowCoreThreadTimeOut(true);
-    }
-
-    /**
-     * 优雅关闭:等待 10 秒让队列中的任务执行完毕,超时则强制中断。
-     * 关闭后的 REST 调用将通过 CallerRunsPolicy 直接在提交线程执行。
-     */
-    public void shutdown() {
-        executor.shutdown();
-        try {
-            executor.awaitTermination(10, TimeUnit.SECONDS);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            executor.shutdownNow();
-        }
-    }
-
-    /**
-     * 异步 IOC 市价开多。quantity 为正数(如 "1")。
-     *
-     * @param quantity  开仓张数(正数)
-     * @param onSuccess 成交成功回调(可为 null)
-     * @param onFailure 成交失败回调(可为 null)
-     */
-    public void openLong(String quantity, Runnable onSuccess, Runnable onFailure) {
-        openPosition(quantity, "t-grid-long", "开多", onSuccess, onFailure);
-    }
-
-    /**
-     * 异步 IOC 市价开空。quantity 为负数(如 "-1")。
-     *
-     * @param quantity  开仓张数(负数)
-     * @param onSuccess 成交成功回调(可为 null)
-     * @param onFailure 成交失败回调(可为 null)
-     */
-    public void openShort(String quantity, Runnable onSuccess, Runnable onFailure) {
-        openPosition(quantity, "t-grid-short", "开空", onSuccess, onFailure);
-    }
-
-    /**
-     * 通用异步 IOC 市价下单。
-     *
-     * @param size      下单张数(正=开多 / 负=开空)
-     * @param text      订单标记文本(如 "t-grid-long"),用于区分订单来源
-     * @param label     日志标签(如 "开多"/"开空")
-     * @param onSuccess 成功回调
-     * @param onFailure 失败回调
-     */
-    private void openPosition(String size, String text, String label, Runnable onSuccess, Runnable onFailure) {
-        executor.execute(() -> {
-            try {
-                FuturesOrder order = new FuturesOrder();
-                order.setContract(contract);
-                order.setSize(size);
-                order.setPrice("0");
-                order.setTif(FuturesOrder.TifEnum.IOC);
-                order.setText(text);
-                FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, order, null);
-                log.info("[TradeExec] {}成功, 价格:{}, id:{}", label, result.getFillPrice(), result.getId());
-                if (onSuccess != null) {
-                    onSuccess.run();
-                }
-            } catch (Exception e) {
-                log.error("[TradeExec] {}失败", label, e);
-                if (onFailure != null) {
-                    onFailure.run();
-                }
-            }
-        });
-    }
-
-    /**
-     * 异步创建止盈条件单(仓位计划止盈止损)。
-     *
-     * <p>使用 Gate 的 {@code PriceTriggeredOrder} API:服务器监控价格,达到触发价后自动平指定张数。
-     * order_type 使用 {@code plan-close-*-position}(仓位计划止盈止损),
-     * 支持指定 size 部分平仓,多次触发的止盈单互不影响。
-     *
-     * <h3>为何不用 close-*-position</h3>
-     * {@code close-long-position} / {@code close-short-position} 仅支持全部平仓(size=0),
-     * 且双仓模式还需额外设置 {@code auto_size}。网格策略需要指定张数部分平仓,
-     * 因此必须使用 {@code plan-close-long-position} / {@code plan-close-short-position}。
-     *
-     * @param triggerPrice 触发价格
-     * @param rule         触发规则(NUMBER_1: ≥ 触发价,NUMBER_2: ≤ 触发价)
-     * @param orderType    stop 类型(plan-close-long-position / plan-close-short-position)
-     * @param size         平仓张数(正=平空,负=平多)
-     */
-    public void placeTakeProfit(BigDecimal triggerPrice,
-                                 FuturesPriceTrigger.RuleEnum rule,
-                                 String orderType,
-                                 String size) {
-        executor.execute(() -> {
-            FuturesPriceTriggeredOrder order = buildTriggeredOrder(triggerPrice, rule, orderType, size);
-            try {
-                TriggerOrderResponse response = futuresApi.createPriceTriggeredOrder(SETTLE, order);
-                log.info("[TradeExec] 止盈单已创建, 触发价:{}, 类型:{}, size:{}, id:{}",
-                        triggerPrice, orderType, size, response.getId());
-            } catch (Exception e) {
-                log.error("[TradeExec] 止盈单创建失败, 触发价:{}, size:{}, 立即市价止盈", triggerPrice, size, e);
-                marketClose(size);
-            }
-        });
-    }
-
-    /**
-     * 市价止盈:在止盈条件单创建失败时立即市价平仓。
-     * size 与止盈单保持一致(负=平多,正=平空)。
-     */
-    private void marketClose(String size) {
-        try {
-            FuturesOrder order = new FuturesOrder();
-            order.setContract(contract);
-            order.setSize(size);
-            order.setPrice("0");
-            order.setTif(FuturesOrder.TifEnum.IOC);
-            order.setReduceOnly(true);
-            order.setText("t-grid-mkt-close");
-            FuturesOrder result = futuresApi.createFuturesOrder(SETTLE, order, null);
-            log.info("[TradeExec] 市价止盈成功, 价格:{}, size:{}, id:{}", result.getFillPrice(), size, result.getId());
-        } catch (Exception e) {
-            log.error("[TradeExec] 市价止盈也失败, size:{}", size, e);
-        }
-    }
-
-    /**
-     * 异步清除指定合约的所有止盈止损条件单。
-     */
-    public void cancelAllPriceTriggeredOrders() {
-        executor.execute(() -> {
-            try {
-                futuresApi.cancelPriceTriggeredOrderList(SETTLE, contract);
-                log.info("[TradeExec] 已清除所有止盈止损条件单");
-            } catch (Exception e) {
-                log.error("[TradeExec] 清除止盈止损条件单失败", e);
-            }
-        });
-    }
-
-    /**
-     * 构建 FuturesPriceTriggeredOrder 对象。
-     *
-     * <p>策略=0(价格触发),price_type=0(最新价),expiration=0(永不过期),
-     * tif=IOC(立即成交或取消),reduce_only=true(只减仓不开新仓)。
-     *
-     * <h3>size 参数说明</h3>
-     * <ul>
-     *   <li>plan-close-long-position:size 为负,表示平多仓多少张</li>
-     *   <li>plan-close-short-position:size 为正,表示平空仓多少张</li>
-     * </ul>
-     * 每次只平指定张数,不会全平仓位,多个止盈单可并存且互不影响。
-     */
-    private FuturesPriceTriggeredOrder buildTriggeredOrder(BigDecimal triggerPrice,
-                                                            FuturesPriceTrigger.RuleEnum rule,
-                                                            String orderType,
-                                                            String size) {
-        FuturesPriceTrigger trigger = new FuturesPriceTrigger();
-        trigger.setStrategyType(FuturesPriceTrigger.StrategyTypeEnum.NUMBER_0);
-        trigger.setPriceType(FuturesPriceTrigger.PriceTypeEnum.NUMBER_0);
-        trigger.setPrice(triggerPrice.toString());
-        trigger.setRule(rule);
-        trigger.setExpiration(0);
-
-        FuturesInitialOrder initial = new FuturesInitialOrder();
-        initial.setContract(contract);
-        initial.setSize(Long.parseLong(size));
-        initial.setPrice("0");
-        initial.setTif(FuturesInitialOrder.TifEnum.IOC);
-        initial.setReduceOnly(true);
-
-        FuturesPriceTriggeredOrder order = new FuturesPriceTriggeredOrder();
-        order.setTrigger(trigger);
-        order.setInitial(initial);
-        order.setOrderType(orderType);
-        return order;
-    }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientMain.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientMain.java
deleted file mode 100644
index 21c81cf..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientMain.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-/**
- * Gate 网格交易的独立测试入口(main 方法)。
- * 通过 Spring XML 上下文初始化管理器,运行一段时间后手动关闭。
- *
- * @author Administrator
- */
-public class GateWebSocketClientMain {
-    public static void main(String[] args) throws InterruptedException {
-        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
-        GateWebSocketClientManager manager = context.getBean(GateWebSocketClientManager.class);
-
-        Thread.sleep(1200000000L);
-
-        manager.destroy();
-    }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
deleted file mode 100644
index 55a6076..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.xcong.excoin.modules.gateApi;
-
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.CandlestickChannelHandler;
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionClosesChannelHandler;
-import com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionsChannelHandler;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import java.math.BigDecimal;
-
-/**
- * Gate 模块 Spring 入口,组装所有组件并管理生命周期。
- *
- * <h3>启动流程 ({@code @PostConstruct})</h3>
- * <ol>
- *   <li>构建 {@link GateConfig}(Builder 模式,含 API 密钥、合约、策略参数)</li>
- *   <li>创建 {@link GateGridTradeService} → init():切持仓模式、清旧条件单、设杠杆</li>
- *   <li>创建 {@link GateKlineWebSocketClient} → 注册 3 个 Handler → init():建立 WS 连接</li>
- *   <li>gridTradeService.startGrid():激活策略,等待 K 线触发首次双开</li>
- * </ol>
- *
- * <h3>销毁流程 ({@code @PreDestroy})</h3>
- * <ol>
- *   <li>gridTradeService.stopGrid():取消条件单 → 关闭交易线程池</li>
- *   <li>wsClient.destroy():取消订阅 → 断开 WS → 关闭线程池</li>
- * </ol>
- *
- * <h3>配置</h3>
- * 当前在代码中硬编码测试网参数。切换到生产网只需改为 {@code .isProduction(true)}。
- *
- * @author Administrator
- */
-@Slf4j
-@Component
-public class GateWebSocketClientManager {
-
-    /** WebSocket 连接管理器 */
-    private GateKlineWebSocketClient wsClient;
-    /** 网格交易策略服务 */
-    private GateGridTradeService gridTradeService;
-    /** 统一配置 */
-    private GateConfig config;
-
-    @PostConstruct
-    public void init() {
-        log.info("[管理器] 开始初始化...");
-
-        try {
-            //测试盘
-            config = GateConfig.builder()
-                    .apiKey("d90ca272391992b8e74f8f92cedb21ec")
-                    .apiSecret("1861e4f52de4bb53369ea3208d9ede38ece4777368030f96c77d27934c46c274")
-                    .contract("ETH_USDT")
-                    .leverage("100")
-                    .marginMode("CROSS")
-                    .positionMode("dual")
-                    .gridRate(new BigDecimal("0.0015"))
-                    .overallTp(new BigDecimal("5"))
-                    .maxLoss(new BigDecimal("15"))
-                    .quantity("1")
-                    .contractMultiplier(new BigDecimal("0.01"))
-                    .unrealizedPnlPriceMode(GateConfig.PnLPriceMode.LAST_PRICE)
-                    .isProduction(false)
-                    .reopenMaxRetries(3)
-                    .build();
-            //实盘
-            config = GateConfig.builder()
-                    .apiKey("865371cdaccd5d238aceb06a55f0143a")
-                    .apiSecret("49589c30dfdc3acba007eed445a94990c4b0aa5faac9843e32defdd7371f5a50")
-                    .contract("ETH_USDT")
-                    .leverage("100")
-                    .marginMode("CROSS")
-                    .positionMode("dual")
-                    .gridRate(new BigDecimal("0.0035"))
-                    .overallTp(new BigDecimal("1"))
-                    .maxLoss(new BigDecimal("15"))
-                    .quantity("1")
-                    .contractMultiplier(new BigDecimal("0.01"))
-                    .unrealizedPnlPriceMode(GateConfig.PnLPriceMode.LAST_PRICE)
-                    .isProduction(true)
-                    .reopenMaxRetries(3)
-                    .build();
-
-            // 1. 初始化交易服务:查用户ID → 切持仓模式 → 清条件单 → 平已有仓位 → 设杠杆
-            gridTradeService = new GateGridTradeService(config);
-            gridTradeService.init();
-
-            // 2. 创建 WS 客户端并注册 3 个频道处理器
-            wsClient = new GateKlineWebSocketClient(config.getWsUrl());
-            wsClient.addChannelHandler(new CandlestickChannelHandler(config.getContract(), gridTradeService));
-            wsClient.addChannelHandler(new PositionsChannelHandler(
-                    config.getApiKey(), config.getApiSecret(), config.getContract(), gridTradeService));
-            wsClient.addChannelHandler(new PositionClosesChannelHandler(
-                    config.getApiKey(), config.getApiSecret(), config.getContract(), gridTradeService));
-            wsClient.init();
-            log.info("[管理器] WS已连接, 已注册 3 个频道处理器");
-
-            // 3. 激活策略,等待首根 K 线触发基底双开
-            gridTradeService.startGrid();
-        } catch (Exception e) {
-            log.error("[管理器] 初始化失败", e);
-        }
-    }
-
-    /**
-     * 销毁:停止策略 → 关闭交易线程池 → 取消 WS 订阅 → 断开连接 → 关闭 WS 线程池。
-     */
-    @PreDestroy
-    public void destroy() {
-        log.info("[管理器] 开始销毁...");
-        if (gridTradeService != null) {
-            gridTradeService.stopGrid();
-        }
-        if (wsClient != null) {
-            wsClient.destroy();
-        }
-        log.info("[管理器] 销毁完成");
-    }
-
-    public GateKlineWebSocketClient getKlineWebSocketClient() { return wsClient; }
-    public GateGridTradeService getGridTradeService() { return gridTradeService; }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/celue.out b/src/main/java/com/xcong/excoin/modules/gateApi/celue.out
deleted file mode 100644
index 7d06d00..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/celue.out
+++ /dev/null
Binary files differ
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/gate-websocket.txt b/src/main/java/com/xcong/excoin/modules/gateApi/gate-websocket.txt
deleted file mode 100644
index d763d63..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/gate-websocket.txt
+++ /dev/null
@@ -1,5011 +0,0 @@
-v4.0.0 · Stable
-#Gate Futures WebSocket v4.0.0
-Gate 提供简单而强大的 Websocket API,将 Gate BTCUSDT 永续合约交易状态集成到您的业务或应用程序中。
-
-我们在 Python 和 Golang 中有语言绑定,将来还会有更多!您可以在右侧的深色区域中查看代码示例,并且可以通过右上角的选项卡切换示例的编程语言
-
-#服务地址
-我们提供 BTC/USDT 结算永续合约交易服务器地址,您可以根据自己的情况选择其中之一
-
-#BTC Contract
-地址列表:
-
-线上交易: wss://fx-ws.gateio.ws/v4/ws/btc
-模拟盘交易: wss://fx-ws-testnet.gateio.ws/v4/ws/btc
-#USDT Contract
-地址列表:
-
-线上交易: wss://fx-ws.gateio.ws/v4/ws/usdt
-线上SBE: wss://fx-ws.gateio.ws/v4/ws/usdt/sbe
-模拟盘交易: wss://ws-testnet.gate.com/v4/ws/futures/usdt
-建议使用SBE以获取更快的行情和更小的带宽成本
-
-如果你使用老的服务地址(wss://fx-ws.gateio.ws/v4/ws 或 wss://fx-ws-testnet.gateio.ws/v4/ws), 将默认是 BTC 结算的 websocket 服务.
-
-#变更日志
-2026-04-14
-
-部分频道支持SBE数据推送: futures.trades、futures.obu、futures.book_ticker、futures.tickers、futures.candlesticks、futures.order_book、futures.order_book_update、futures.usertrades、futures.positions、futures.orders。
-具体的使用查看SBE 数据推送章节
-2026-03-30
-
-futures.order_place 下单请求:iceberg 字段说明修正为类型 string(原文档为 int64)、可选(原文档为必填)
-2026-02-09
-
-模拟盘部分频道支持SBE数据推送
-正式环境实装另行同步
-2026-02-04
-
-futures.obu 模拟盘新增立即的首次快照推送,该次快照推送将会在订阅请求的响应之前推送。此行为与之前快照在订阅请求的响应之后推送不同,请注意该行为变更。
-正式环境实装另行同步
-2026-01-07
-
-futures.orders 新增字段 market_order_slip_ratio (市价单的预设滑点比例)
-futures.order_place futures.order_batch_place 入参新增字段market_order_slip_ratio (允许自定义市价单的最大滑点)
-2025-12-09
-
-合约的张数支持小数,所有的推送的张数、成交量等均改为字符串(可能是小数)。
-
-如何对接websocket的小数支持:
-
-在请求链接websocket时,加入:"X-Gate-Size-Decimal": "1" 的header即可,推送的张数、成交量等将会是字符串(可能是小数)。
-如果在链接websocket时,不加入:"X-Gate-Size-Decimal": "1" 的header,推送将保持原始的字段类型(整形)。
-请尽快切换到字符串的推送支持,后续整形的推送将会下线(下线时间会另行通知)。
-如果出现小数的size,用户如果还是在使用整形的推送,那么推送出来的size将会是向下取整,例如1.1、1.5、1.7的size推送出去都将会是1。
-将影响到以下的推送频道,和对应的字段。
-
-频道	字段
-futures.trades	size
-futures.tickers	total_size
-futures.book_ticker	A B
-futures.order_book_update	a.s、b.s
-futures.order_book	a.s、b.s
-futures.obu	size 会有小数
-futures.candlesticks	v
-futures.liquidates	left、size、 order_size
-futures.public_liquidates	size
-futures.contract_stats	long_liq_size、short_liq_size、open_interest
-futures.orders	iceberg、left、size
-futures.usertrades	size
-futures.auto_deleverages	position_size、trade_size
-futures.positions	size
-futures.autoorders	position_size、 trade_size
-将影响到以下的API请求频道,主要涉及张数,成交量等字段。
-
-频道	字段
-futures.order_place	size、left
-futures.order_batch_place	size
-futures.order_cancel	size、left
-futures.order_cancel_cp	size、left
-futures.order_amend	size、left
-futures.order_list	size、left
-futures.order_status	size、left
-2025-09-25
-
-新增 仓位 Adl 排名频道 文档
-2025-05-22
-
-新增深度频道V2文档说明
-futures.order_book_update 新增字段 full
-2025-04-25
-
-账户交易API新增通道 futures.order_cancel_ids
-futures.order_book 和 futures.order_book_update 新增深度档位字段 l
-2025-04-18
-
-补充文档代码示例
-2025-03-24
-
-修复了深度频道部分文档的错误描述
-修复了订单频道部分文档的错误描述
-2025-03-21
-
-更新了频道 futures.orders 文档, 新增了 update_id, update_time, biz_info, stop_profit_price 和 stop_loss_price 等字段的说明
-2025-03-12
-
-合约统计信息频道增加 contract 字段
-更新账户交易 API,新增了 x-gate-exptime 字段
-修复了账户交易 API 部分文档描述性错误
-2025-02-19
-
-新增频道 futures.public_liquidates 用于推送合约强平订单的快照信息
-2025-02-10
-
-更新账户交易 API,新增了 x_in_time, x_out_time, conn_trace_id, trace_id 字段
-futures.order_place, futures.order_batch_place, futures.order_cancel, futures.order_cancel_cp 和 futures.order_amend 新增了 x_gate_ratelimit_requests_remain, x_gate_ratelimit_limit 和 x_gat_ratelimit_reset_timestamp 字段
-2024-11-18
-
-在频道 futures.order_book_update 移除 10 档位 1000ms 推送间隔支持
-2023-09-21
-
-在频道futures.trades推送参数中新增is_internal字段
-2023-08-18
-
-添加 WebSocket API 操作
-WebSocket API 允许通过 WebSocket 连接创建、取消、修改、查询订单。
-2023-07-07
-
-在频道futures.order_book_update中添加新的间隔“20ms”,请注意,20ms 的间隔仅支持 20 档位
-2023-06-20
-
-在频道 futures.positions 增加update_id 字段
-2022-12-22
-
-在频道 futures.autoorders 初始结构中添加新字段 auto_size,将字段详细信息添加到 http api
-2022-11-22
-
-在通用的返回结果中添加新字段“time_ms”,以表示创建消息的时间
-2022-08-11
-
-在频道futures.autoorders通知中添加新字段text
-在频道futures.tickers通知中添加新字段low_24h和high_24h
-2022-04-15
-
-在频道futures.balances通知中添加新字段 currency
-2021-03-31
-
-在频道futures.book_ticker和futures.order_book推送中添加毫秒字段t
-2021-03-10
-
-添加新的订单簿频道 futures.book_ticker 以实时推送最佳卖价/买价
-添加新的订单簿频道 futures.order_book_update 以与用户推送订单簿更改 指定更新频率
-添加本地订单簿维护文档
-2021-03-01
-
-在通用的返回结果中添加以_ms结尾的新毫秒精度时间戳
-在futures.book all通知中添加新字段id
-2020-8-08
-
-添加完整代码 demo(golang, python)
-2020-8-07
-
-添加futures.autoorders频道
-2020-7-07
-
-添加futures.order_book频道
-2020-4-30
-
-添加futures.position频道
-2019-11-06
-
-新增 USDT 结算永续合约的 websocket 推送
-为futures.tickers添加volume_24h_base字段、volume_24h_settle字段、volume_24h_quote字段
-删除旧服务器地址(wss://fx-ws.gateio.ws/v4/ws 或 wss://fx-ws-testnet.gateio.ws/v4/ws)
-如果您使用旧的服务器地址(wss://fx-ws.gateio.ws/v4/ws 或 wss://fx-ws-testnet.gateio.ws/v4/ws),我们 将为您使用 BTC 结算永续合约的 websocket 推送
-
-2019-10-22
-
-添加应用层 ping/pong 消息
-2019-04-30
-
-添加index和mark futures.candlesticks 订阅
-为futures.tickers添加funding_rate_indicative字段
-为futures.orders添加 is_reduce_only 和状态字段
-2019-02-13
-
-更改 webSocket 基本 url
-为futures.tickers添加volume_24h_usd字段和volume_24h_btc字段
-2019-01-11
-
-添加futures.position_closes 和 futures.balance 订阅
-删除频道 futures.auto_deleverages 和futures.liquidates的 finish_time 字段
-为频道 futures.auto_deleverages 和futures.liquidates 添加 time字段
-WebSocket 应用示例
-
-# !/usr/bin/env python
-# coding: utf-8
-
-import hashlib
-import hmac
-import json
-import logging
-import time
-import threading
-
-from websocket import WebSocketApp
-
-logging.basicConfig(level=logging.INFO)
-logger = logging.getLogger(__name__)
-
-event = threading.Event()
-
-class GateWebSocketApp(WebSocketApp):
-
-  def __init__(self, url, api_key, api_secret, **kwargs):
-    super(GateWebSocketApp, self).__init__(url, **kwargs)
-    self._api_key = api_key
-    self._api_secret = api_secret
-
-  def _send_ping(self):
-    while not event.wait(10):
-      self.last_ping_tm = time.time()
-      if self.sock:
-        try:
-          self.sock.ping()
-        except Exception as ex:
-          logger.warning("send_ping routine terminated: {}".format(ex))
-          break
-        try:
-          self._request("futures.ping", auth_required=False)
-        except Exception as e:
-          raise e
-
-  def _request(self, channel, event=None, payload=None, auth_required=True):
-    current_time = int(time.time())
-    data = {
-      "time": current_time,
-      "channel": channel,
-      "event": event,
-      "payload": payload,
-    }
-    if auth_required:
-      message = 'channel=%s&event=%s&time=%d' % (channel, event, current_time)
-      data['auth'] = {
-        "method": "api_key",
-        "KEY": self._api_key,
-        "SIGN": self.get_sign(message),
-      }
-    data = json.dumps(data)
-    logger.info('request: %s', data)
-    self.send(data)
-
-  def get_sign(self, message):
-    h = hmac.new(self._api_secret.encode("utf8"), message.encode("utf8"), hashlib.sha512)
-    return h.hexdigest()
-
-  def subscribe(self, channel, payload=None, auth_required=True):
-    self._request(channel, "subscribe", payload, auth_required)
-
-  def unsubscribe(self, channel, payload=None, auth_required=True):
-    self._request(channel, "unsubscribe", payload, auth_required)
-
-
-def on_message(ws, message):
-  # type: (GateWebSocketApp, str) -> None
-  # handle message received
-  logger.info("message received from server: {}".format(message))
-
-
-def on_open(ws):
-  # type: (GateWebSocketApp) -> None
-  # subscribe to channels interested
-  logger.info('websocket connected')
-  ws.subscribe("futures.tickers", ['BTC_USDT'], False)
-
-# custom header
-custom_headers = {
-    "X-Gate-Size-Decimal": "1"
-}
-
-if __name__ == "__main__":
-  logging.basicConfig(format="%(asctime)s - %(message)s", level=logging.DEBUG)
-  app = GateWebSocketApp("wss://fx-ws.gateio.ws/v4/ws/usdt",
-                         "YOUR_API_KEY",
-                         "YOUR_API_SECRET",
-                         on_open=on_open,
-                         on_message=on_message,
-                         header=custom_headers)
-  app.run_forever(ping_interval=5)
-Copy
-#Websocket API 概述
-#事件
-每个通用 订阅频道/channel(例如ticker、order_book等)都支持一些不同的事件消息,它们是:
-
-subscribe (推荐使用)
-
-订阅,接受服务器的新数据通知。
-
-unsubscribe
-
-如果取消订阅,服务器将不会发送新数据通知。
-
-update
-
-服务器将向客户端发送新的订阅数据(增量数据)。
-
-all
-
-如果有新订阅的数据(所有数据)可用,服务器将向客户端发送通知。
-
-#请求
-每个请求都遵循通用格式,其中包含time、channel、event和payload。
-
-请求
-名称	类型	必选	描述
-id	Integer	否	可选的请求 ID,将由服务器发回,以帮助您识别服务器响应哪个请求
-time	Integer	是	请求时间
-channel	String	是	请求 subscribe/unsubscribe 频道
-auth	String	否	请求身份验证信息,请参阅身份验证部分了解详细信息
-event	String	是	请求event (subscribe/unsubscribe/update/all/api)
-payload	Array	是	请求详细参数
-#响应
-与请求类似,响应遵循以下通用格式,其中包含: time, channel, event , error 和 result.
-
-响应
-名称	类型	必选	描述
-time	Integer	是	响应时间
-time_ms	Integer	是	毫秒响应时间
-channel	String	是	响应频道
-event	String	是	响应频道事件 (update/all)
-error	Object	是	响应错误
-result	Any	是	返回来自服务端的新数据通知 或 对客户端请求的响应。如果有错误返回则error 不为空,没有错误则此字段为空。
-注意:如果它是服务端发起的数据更新通知 那么 result 的类型是基于 channel 的,不同 channel 的 result 类型有所不同。
-
-但如果是对客户端订阅请求的响应,那么 result 为固定的 {"status": "success"}。 验证订阅请求是否成功,您只需要检查 error 字段是否为空即可,不需要再解析 result 字段。
-
-为了简单起见,下面的频道(channel)描述只给出对应频道的 payload 格式。
-
-#错误
-如果出现错误,您会收到error字段,其中包含错误代码和错误的类型。
-
-错误
-Code	Message
-1	invalid argument struct
-2	invalid argument
-3	service error
-4	authentication fail
-#鉴权
-如果频道是私有的,则请求体需要携带认证信息, 例如futures.usertrades
-
-WebSocket 认证使用与 HTTP API 相同的签名计算方法,但具有 以下差异:
-
-签名字符串拼接方式:channel=<channel>&event=<event>&time=<time>, 其中<channel>、<event>、<time>是对应的请求信息
-身份验证信息在请求正文中的auth字段中发送。
-您可以登录账户获取永续合约账户的 api_key 和 secret。
-
-名称	类型	描述
-method	String	验证方式:api_key
-KEY	String	apiKey 的值
-SIGN	String	签名结果
-代码示例
-
-# example WebSocket signature calculation implementation in Python
-import hmac, hashlib, json, time
-
-
-def gen_sign(channel, event, timestamp):
-    # GateAPIv4 key pair
-    api_key = 'YOUR_API_KEY'
-    api_secret = 'YOUR_API_SECRET'
-
-    s = 'channel=%s&event=%s&time=%d' % (channel, event, timestamp)
-    sign = hmac.new(api_secret.encode('utf-8'), s.encode('utf-8'), hashlib.sha512).hexdigest()
-    return {'method': 'api_key', 'KEY': api_key, 'SIGN': sign}
-
-
-request = {
-    'id': int(time.time() * 1e6),
-    'time': int(time.time()),
-    'channel': 'futures.orders',
-    'event': 'subscribe',
-    'payload': ["20011", "BTC_USD"]
-}
-request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
-print(json.dumps(request))
-Copy
-#SBE 数据推送
-#对接SBE
-使用地址,在现有的地址后添加/sbe:
-prod: wss://fx-ws.gateio.ws/v4/ws/usdt/sbe
-testnet: wss://ws-testnet.gate.com/v4/ws/futures/usdt/sbe
-schema地址:
-prod: gate_fex_ws_prod_latest.xml(opens new window)
-testnet: gate_fex_ws_testnet_latest.xml(opens new window)
-如果需要指定sbe_schema_id,则通过query的形式传入sbe_schema_id的参数,例如:wss://fx-ws.gateio.ws/v4/ws/usdt/sbe?sbe_schema_id=1
-目前支持的sbe_schema_id为0和1;sbe_schema_id为0用于客户端测试sbe schema不兼容升级的逻辑
-不传入sbe_schema_id则默认使用最新的schema版本
-传入不合法的sbe_schema_id在连接之后会返回系统通知,并将sbe_schema_id调整为最新的schema版本
-传入旧版本的sbe_schema_id在连接之后会返回系统通知,提醒更新新版本的SBE schema,依旧使用客户端指定的旧版本schema
-无效的sbe_schema_id的系统通知
-
-{
-  "time": 1770600979,
-  "time_ms": 1770600979609,
-  "channel": "futures.system",
-  "event": "update",
-  "result": {
-    "type": "invalid_sbe_schema_id",
-    "msg": "Your sbe_schema_id '011' does not exist, it has been adjusted to the default sbe_schema_id '1'."
-  }
-}
-Copy
-过时的sbe_schema_id的系统通知
-
-{
-  "time": 1770601096,
-  "time_ms": 1770601096665,
-  "channel": "futures.system",
-  "event": "update",
-  "result": {
-    "type": "outdated_sbe_schema_id",
-    "msg": "Your sbe_schema_id '0' is outdated, please upgrade to the latest version '1'."
-  }
-}
-Copy
-#SBE使用说明
-使用JSON进行请求和首次响应;使用SBE作为数据推送;
-同一条连接上同时存在JSON和SBE的消息,请使用opcode来区分数据:opcode为1代表JSON,opcode为2代表SBE。
-SBE 的解码:
-MessageHeader:每条 SBE 二进制帧均为「MessageHeader + 消息体」。Header 中包含 blockLength、templateId、schemaId、version,解码时必须先读 Header,再根据 schemaId 和 templateId 选择对应 Schema 与消息类型解码消息体。
-解码流程建议:
-读取 MessageHeader(固定长度),得到 schemaId、templateId、blockLength、version。
-根据 schemaId 选择解码器:0 → 使用旧版本进行解码;1 → 使用新版本进行解码。
-根据 templateId 确定具体消息类型(如 PublicTrade、OrderBook、Bbo 等),再按该 Schema 的布局解码消息体。
-使用 SBE 时,仅可订阅以下频道,其余频道不支持 SBE 推送。后续将扩展到其余频道。
-订阅不支持SBE的频道时,将返回订阅失败的消息
-通道名	说明
-futures.trades	公共成交
-futures.order_book	订单簿(深度)
-futures.order_book_update	订单簿增量更新
-futures.book_ticker	最优买卖(BBO)
-futures.obu	订单簿增量(OBU)
-futures.candlesticks	K 线
-futures.tickers	行情
-futures.usertrades	用户成交
-futures.positions	持仓
-futures.orders	订单
-不支持sbe将返回订阅失败:
-
-{
-  "time": 1770603321,
-  "time_ms": 1770603321767,
-  "conn_id": "57a8765578ea837e",
-  "trace_id": "3c75ba05569b3b292a2f36cfdd90d868",
-  "channel": "futures.autoorders",
-  "event": "subscribe",
-  "payload": [
-    "15760812",
-    "!all"
-  ],
-  "error": {
-    "code": 2,
-    "message": "channel futures.autoorders does not support SBE"
-  },
-  "result": {
-    "status": "fail"
-  }
-}
-Copy
-#System API
-提供系统状态检查,如 ping/pong.
-
-#Ping/Pong
-检查服务器/客户端连接.
-
-Gate websocket 使用协议层 ping/pong 消息。服务器会发起 ping 操作。如果客户端没有回复,客户端将被断开。
-
-websocket rfc 协议(opens new window)
-
-如果想主动检测连接状态,可以发送应用层 ping 消息,并接收 pong 消息。
-
-#请求参数
-频道
-
-futures.ping
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.ping"}')
-print(ws.recv())
-Copy
-futures.ping操作返回 JSON 结构如下:
-
-{
-  "time": 1545404023,
-  "time_ms": 1545404023123,
-  "channel": "futures.pong",
-  "event": "",
-  "result": null
-}
-Copy
-#服务升级通知
-服务在即将关闭进行升级时,会向当前连接主动推送一条系统通知,客户端收到后应尽快重连。
-
-服务端推送格式(SystemNotifyDTO):
-
-字段	类型	说明
-type	String	通知类型,如 upgrade
-msg	String	提示文案
-data	Object	可选,扩展数据
-示例(服务升级):
-
-{
-  "type": "upgrade",
-  "msg": "The connection will soon be closed for a service upgrade. Please reconnect."
-}
-#ticker 频道
-ticker是合约状态的高级概述。它向你展示了最高的, 最低的、最后的交易价格。它还包括每日交易量和价格等信息
-
-#订阅操作
-订阅永续合约 24hr 价格变动情况.
-
-#请求参数
-channel
-
-futures.tickers
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-payload	Array	是	合约列表
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.tickers","event": "subscribe", "payload" : ["BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的订阅请求返回 JSON 结构如下:
-
-{
-  "time": 1545404023,
-  "time_ms": 1545404023123,
-  "channel": "futures.tickers",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#ticker 推送
-永续合约 24hr 价格变动情况推送
-
-#推送参数
-channel
-
-futures.tickers
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-contract	String	合约名称
-last	String	最新成交价
-change_percentage	String	涨跌幅
-funding_rate	String	资金费率
-funding_rate_indicative	String	下一周期预测资金费率(已弃用,改用funding_rate)
-mark_price	String	标记价格
-index_price	String	指数价格
-total_size	String	总数量
-volume_24h	String	24 小时成交量
-quanto_base_rate	String	双币种合约中基础货币与结算货币的汇率。不存在于其他类型的合同中
-volume_24h_btc	String	近 24 小时 BTC 交易量(已弃用,请使用volume_24h_base、volume_24h_quote、volume_24h_settle代替)
-volume_24h_usd	String	近 24 小时美元交易量(已弃用,请使用volume_24h_base、volume_24h_quote、volume_24h_settle 代替)
-volume_24h_quote	String	近 24 小时交易量,以计价货币计
-volume_24h_settle	String	近 24 小时交易量,以结算货币计
-volume_24h_base	String	近 24 小时交易量,以基础货币计
-low_24h	String	近 24 小时最低交易价
-high_24h	String	近 24 小时最高交易价
-{
-  "time": 1541659086,
-  "time_ms": 1541659086123,
-  "channel": "futures.tickers",
-  "event": "update",
-  "result": [
-    {
-      "contract": "BTC_USD",
-      "last": "118.4",
-      "change_percentage": "0.77",
-      "funding_rate": "-0.000114",
-      "funding_rate_indicative": "0.01875",
-      "mark_price": "118.35",
-      "index_price": "118.36",
-      "total_size": "73648",
-      "volume_24h": "745487577",
-      "volume_24h_btc": "117",
-      "volume_24h_usd": "419950",
-      "quanto_base_rate": "",
-      "volume_24h_quote": "1665006",
-      "volume_24h_settle": "178",
-      "volume_24h_base": "5526",
-      "low_24h": "99.2",
-      "high_24h": "132.5"
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅
-
-#请求参数
-channel
-
-futures.tickers
-
-event
-
-unsubscribe
-
-代码示例
-
-import json
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": 123456,
-  "channel": "futures.tickers",
-  "event": "unsubscribe",
-  "payload": ["BTC_USD"]
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545404900,
-  "time_ms": 1545404900123,
-  "channel": "futures.tickers",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#公有成交频道
-每当 Gate 发生交易时,该频道都会发送交易消息。它包括价格、金额、时间和类型等交易信息
-
-#公有成交订阅
-订阅公有成交更新通知
-
-#请求参数
-channel
-
-futures.trades
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-payload	Array	是	合约列表
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.trades","event": "subscribe", "payload" : ["BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545405058,
-  "time_ms": 1545405058123,
-  "channel": "futures.trades",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#公有成交推送
-通知最新交易更新
-
-#推送参数
-channel
-
-futures.trades
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-contract	string	合约名称
-size	string/int	交易数量
-id	int	交易 ID
-create_time	int	交易消息创建时间
-create_time_ms	int	交易消息创建时间(以毫秒为单位)
-price	string	交易价格
-is_internal	bool	是否为内部成交。内部成交是指保险资金和 ADL 用户对强平指令的接管。由于不是市场深度上的正常撮合,交易价格可能会出现偏差,不会记录在 K 线上。如果不是内部交易,则该字段不会被返回。
-size 正数表示买家,负数表示卖家
-
-{
-  "channel": "futures.trades",
-  "event": "update",
-  "time": 1541503698,
-  "time_ms": 1541503698123,
-  "result": [
-    {
-      "size": "-108",
-      "id": 27753479,
-      "create_time": 1545136464,
-      "create_time_ms": 1545136464123,
-      "price": "96.4",
-      "contract": "BTC_USD",
-      "is_internal": true
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅公有成交更新通知
-
-#请求参数
-channel
-
-futures.trades
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send(
-  '{"time" : 123456, "channel" : "futures.trades", "event": "subscribe", "payload" : ["BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545404900,
-  "time_ms": 1545404900123,
-  "channel": "futures.trades",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#深度频道
-order_book 频道允许您跟踪 Gate 订单簿深度的状态。它以价格聚合的方式提供,可自定义精度。
-
-共有三种不同的订单簿渠道可供订阅:
-
-futures.order_book
-
-全量频道,定期使用all推送完整的有限级别订单簿.
-
-futures.book_ticker
-
-实时推送最佳买价和卖价.
-
-futures.order_book_update
-
-以指定的更新频率向用户订单簿推送订单簿的更新内容.
-
-不建议通过futures.order_book接收订单簿更新,使用 futures.order_book_update 可以以更少的流量提供更及时的更新
-
-如何维护本地订单簿:
-
-订阅 futures.order_book_update 并指定级别和更新频率,例如 ["BTC_USDT", "100ms", "100"] 每 100ms 推送 BTC_USDT 订单簿前 100 个级别的更新
-缓存 WebSocket 通知。每个通知都使用“U”和“u”来告诉第一个和最后一个 自上次通知以来更新 ID。
-使用 REST API 检索基本订单簿,并确保记录了订单簿 ID(参考 如下面的“baseID”) 例如https://api.gateio.ws/api/v4/futures/usdt/order_book?contract=BTC_USDT&limit=10&with_id=true 获取 BTC_USDT 的 10 级基础订单簿
-迭代缓存的 WebSocket 通知,找到第一个包含 baseID 的通知, 即 U <= baseId+1 和 u >= baseId+1,然后开始从中消费。请注意,size为 通知都是全量的 size,即应该使用它们覆盖替换原始的size。 如果 size 等于 0,则从订单簿中删除价格。
-转储所有满足 u < baseID+1 的通知。如果 baseID+1 < 第一个通知 U,则 意味着当前的基本订单簿落后于通知。从步骤 3 开始检索更新的内容基本订单簿。
-如果后续发现满足 U > baseID+1 的通知,则说明有更新 丢失的。从步骤 3 重建本地订单簿。
-注意:
-
-即使 WebSocket 推送中的 a, b 或者 asks, bids 为空,用户也需要更新本地订单簿的 id 和 timestamp,以确保本地订单簿与服务器保持一致。
-WebSocket 订阅的 level(档位数)应与 REST 快照的 limit 一致,否则可能导致增量更新无法覆盖快照档位,造成本地订单簿错位或不完整。
-#深度全量更新频道
-订阅深度.
-
-#请求参数
-channel
-
-futures.order_book
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-contract	String	是	合约名称
-limit	String	是	深度层级: 100, 50, 20, 10, 5, 1
-interval	String	是	价格合并精度: "0"
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.order_book","event": "subscribe", "payload" : ["BTC_USD", "20", "0"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545405058,
-  "time_ms": 1545405058123,
-  "channel": "futures.order_book",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#全量深度推送
-全量深度更新推送
-
-#推送参数
-channel
-
-futures.order_book
-
-event
-
-all
-
-params
-
-推送参数
-名称	类型	描述
-result	object	深度信息
-»t	Integer	深度生成时间戳(以毫秒为单位)
-»contract	String	合约名称
-»id	Integer	深度 ID
-»asks	Array	深度卖方的档位列表
-»»p	String	档位价格
-»»s	String	档位的数量
-»bids	Array	深度买方的档位列表
-»»p	String	档位价格
-»»s	String	档位的数量
-»l	String	深度层级(例如 100 即代表 100 层的深度更新)
-{
-  "channel": "futures.order_book",
-  "event": "all",
-  "time": 1541500161,
-  "time_ms": 1541500161123,
-  "result": {
-    "t": 1541500161123,
-    "contract": "BTC_USD",
-    "id": 93973511,
-    "asks": [
-      {
-        "p": "97.1",
-        "s": "2245"
-      },
-      {
-        "p": "97.1",
-        "s": "2245"
-      }
-    ],
-    "bids": [
-      {
-        "p": "97.1",
-        "s": "2245"
-      },
-      {
-        "p": "97.1",
-        "s": "2245"
-      }
-    ],
-    "l": "20"
-  }
-}
-Copy
-#全量深度取消订阅
-取消订阅指定市场的深度
-
-#请求参数
-channel
-
-futures.order_book
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.order_book","event": "unsubscribe", "payload" : ["BTC_USD", "20", "0"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545445847,
-  "time_ms": 1545445847123,
-  "channel": "futures.order_book",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#最佳买卖价订阅
-订阅深度最佳买卖价
-
-#请求参数
-channel
-
-futures.book_ticker
-
-event
-
-subscribe
-
-params
-
-payload是一个包含合约市场的列表.
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send('{"time" : 123456, "channel" : "futures.book_ticker","event": "subscribe", "payload" : ["BTC_USDT"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545405058,
-  "time_ms": 1545405058123,
-  "channel": "futures.book_ticker",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#最佳买卖价的推送
-如果 a 为空字符串,则表示空买价;如果 b 为空字符串,则表示空卖价。
-
-最新买卖价的推送
-
-#推送参数
-channel
-
-futures.book_ticker
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	object	深度的最佳买卖价
-»t	Integer	最佳买卖价行情生成的时间戳(以毫秒为单位)
-»u	Integer	深度的 ID
-»s	String	合约名称
-»b	String	最佳买方的价格,如果没有买方,则为空串
-»B	String/Integer	最佳买方的数量,如果没有买方,则为 0
-»a	String	最佳卖方的价格,如果没有卖方,则为空串
-»A	String/Integer	最佳卖方的数量,如果没有卖方,则为 0
-{
-  "time": 1615366379,
-  "time_ms": 1615366379123,
-  "channel": "futures.book_ticker",
-  "event": "update",
-  "result": {
-    "t": 1615366379123,
-    "u": 2517661076,
-    "s": "BTC_USD",
-    "b": "54696.6",
-    "B": "37000",
-    "a": "54696.7",
-    "A": "47061"
-  }
-}
-Copy
-#最佳买卖价的取消订阅
-取消指定合约市场的最佳买卖订阅
-
-#请求
-channel
-
-futures.book_ticker
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send('{"time" : 123456, "channel" : "futures.book_ticker","event": "unsubscribe", "payload" : ["BTC_USDT"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545445847,
-  "time_ms": 1545445847123,
-  "channel": "futures.book_ticker",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#合约深度更新推送订阅
-订阅深度更新推送
-
-#请求参数
-channel
-
-futures.order_book_update
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-contract	String	是	合约名称
-frequency	String	是	更新频率,20ms or 100ms
-level	String	否	可选的深度层级。允许以下层级:100、50、20;20ms频率 只支持 20层
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send('{"time" : 123456, "channel" : "futures.order_book_update","event": "subscribe", "payload" : ["BTC_USDT", "100ms", "100"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545405058,
-  "time_ms": 1545405058123,
-  "channel": "futures.order_book_update",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#深度更新推送
-深度更新推送
-
-#推送参数
-channel
-
-futures.order_book_update
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Object	自上次更新以来发生变更要价和出价
-»t	Integer	订单簿生成时间戳(以毫秒为单位)
-»full	Boolean	true 代表全量的深度(假设订阅 level 为 100,推送出来则是 100 层的深度);用户接收到之后需要替换本地深度;false 代表增量的深度,为 false 时,不传输该字段
-»s	String	合约名称
-»U	Integer	本次更新开始的订单簿更新 ID
-»u	Integer	本次更新结束的订单簿更新 ID
-»b	Array	买方变动列表
-»»p	String	变更的档位价格
-»»s	String/Integer	档位的待成交数量。如果为 0,则从订单簿中删除该价格
-»a	Array	卖方变动列表
-»»p	String	变更的档位价格
-»»s	String/Integer	档位的待成交数量。如果为 0,则从订单簿中删除该价格
-»l	String	深度层级(例如 100 即代表 100 层的深度更新)
-{
-  "time": 1615366381,
-  "time_ms": 1615366381123,
-  "channel": "futures.order_book_update",
-  "event": "update",
-  "result": {
-    "t": 1615366381417,
-    "s": "BTC_USD",
-    "U": 2517661101,
-    "u": 2517661113,
-    "b": [
-      {
-        "p": "54672.1",
-        "s": "0"
-      },
-      {
-        "p": "54664.5",
-        "s": "58794"
-      }
-    ],
-    "a": [
-      {
-        "p": "54743.6",
-        "s": "0"
-      },
-      {
-        "p": "54742",
-        "s": "95"
-      }
-    ],
-    "l": "100"
-  }
-}
-Copy
-#深度更新取消订阅
-取消指定合约的市场的深度更新订阅
-
-#请求参数
-channel
-
-futures.order_book_update
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send(
-  '{"time" : 123456, "channel" : "futures.order_book_update", "event": "unsubscribe", "payload" : ["BTC_USDT", "100ms"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545445847,
-  "time_ms": 1545445847123,
-  "channel": "futures.order_book_update",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#深度频道V2
-提供一种更快更新的获取深度信息的方法.
-
-#维护本地深度
-说明:
-
-全量深度推送(full=true): 当频道推送的深度为全量深度时,需要将该深度数据完整替换本地深度,并将深度ID更新为消息中的字段 u。服务端可能会重复推送全量深度。
-订阅该频道时,首次推送为全量深度。
-增量深度推送(full=false): 增量消息中不会显示 full 字段,此时消息包含字段 U(深度起始ID)和 u(深度结束ID)。
-如果 U = 本地深度ID + 1,则表示深度连续更新:
-将本地深度ID替换为消息中的 u。
-若更新中的 a 和 b 不为空,分别按价格更新对应的买、卖深度数量(level[0] 为价格,level[1] 为数量)。当数量 level[1]= "0" 时,需移除对应档位。
-若 U ≠ 本地深度ID + 1,则深度数据不连续,需要取消订阅该市场,并重新订阅以获取初始化深度。
-订阅限制: 针对同一合约的同一深度流,一个链接只允许订阅一次,重复订阅会返回错误。失败示例:
-{
-  "time": 1747391482,
-  "time_ms": 1747391482960,
-  "id": 1,
-  "conn_id": "d9db9373dc5e081e",
-  "trace_id": "ee001938590e183db957bd5ba71651c0",
-  "channel": "futures.obu",
-  "event": "subscribe",
-  "payload": [
-    "ob.BTC_USDT.400"
-  ],
-  "error": {
-    "code": 2,
-    "message": "Alert sub ob.BTC_USDT.400"
-  },
-  "result": {
-    "status": "fail"
-  }
-}
-Copy
-#深度频道V2订阅
-#请求参数
-channel
-
-futures.obu
-
-event
-
-subscribe
-
-params
-
-payload是一个包含流名称的列表. 格式为: ob.{symbol}.{level}; 例如 ob.BTC_USDT.400、ob.BTC_USDT.50
-
-其中level枚举为:400、50;更新频率: 400档为100ms;50档为20ms;
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/usdt")
-ws.send('{"time" : 123456, "channel" : "futures.obu",
-        "event": "subscribe", "payload" : ["ob.BTC_USDT.400"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1747391482,
-  "time_ms": 1747391482384,
-  "id": 1,
-  "conn_id": "d9db9373dc5e081e",
-  "trace_id": "ee001938590e183db957bd5ba71651c0",
-  "channel": "futures.obu",
-  "event": "subscribe",
-  "payload": [
-    "ob.BTC_USDT.400"
-  ],
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#深度v2订阅推送
-深度频道V2的消息推送
-
-#推送参数
-channel
-
-futures.obu
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Object	自上次更新以来发生变更要价和出价
-»t	Integer	订单簿生成时间戳(以毫秒为单位)
-»full	Boolean	true 代表全量的深度;false 代表增量的深度,为 false 时,不传输该字段
-»s	String	深度流的名称
-»U	Integer	本次更新开始的订单簿更新 ID
-»u	Integer	本次更新结束的订单簿更新 ID
-»b	Array[OrderBookArray]	自上次更新以来的 bids 更新
-»» OrderBookArray	Array[String]	[Price, Amount] 数组对, Amount=0应当从本地深度中移除
-»a	Array[OrderBookArray]	自上次更新以来的 asks 更新
-»» OrderBookArray	Array[String]	[Price, Amount] 数组对, Amount=0应当从本地深度中移除
-全量推送示例:
-
-{
-	"channel": "futures.obu",
-	"result": {
-		"t": 1743673026995,
-		"full": true,
-		"s": "ob.BTC_USDT.400",
-		"u": 79072179673,
-		"b": [
-			["83705.9", "30166"]
-		],
-		"a": [
-			["83706", "4208"]
-		]
-	},
-	"time_ms": 1743673026999
-}
-Copy
-增量推送示例:
-
-{
-	"channel": "futures.obu",
-	"result": {
-		"t": 1743673027017,
-		"s": "ob.BTC_USDT.400",
-		"U": 79072179674,
-		"u": 79072179694,
-		"b": [
-			["83702.2", "62"],
-			["83702.1", "0"],
-			["83702", "0"],
-			["83685.6", "120"],
-			["83685", "239"]
-		]
-	},
-	"time_ms": 1743673027020
-}
-Copy
-#深度频道V2取消订阅
-取消指定合约的市场的深度频道V2订阅
-
-#请求参数
-channel
-
-futures.obu
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send(
-  '{"time" : 123456, "channel" : "futures.obu", "event": "unsubscribe", "payload" : ["ob.BTC_USDT.400"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1743673617,
-  "time_ms": 1743673617242,
-  "id": 1,
-  "conn_id": "7b06ff199a98ab0e",
-  "trace_id": "8f86e4021a84440e502f73fde5b94918",
-  "channel": "futures.obu",
-  "event": "unsubscribe",
-  "payload": ["ob.BTC_USDT.400"],
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#K 线频道
-提供一种访问 K 线信息的方法.
-
-#K 线订阅
-如果在contract前面加上mark_,则将订阅合约的标记价格 K 线;如果 前缀为“index_”,将订阅指数价格 K 线.
-
-#请求参数
-channel
-
-futures.candlesticks
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	描述
-interval	String	Interval : "10s", "1m", "5m", "15m", "30m", "1h", "4h", "8h", "1d", "7d"
-contract	String	合约名称
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.candlesticks","event": "subscribe", "payload" : ["1m", "BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545445847,
-  "time_ms": 1545445847123,
-  "channel": "futures.candlesticks",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#k 线消息推送
-k 线的消息推送
-
-#推送参数
-channel
-
-futures.candlesticks
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-t	Integer	时间
-o	String	开盘价格
-c	String	收盘价格
-h	String	最高价格
-l	String	最低价格
-v	String/Integer	成交量
-n	String	合约名称
-a	String	成交原始币种数量
-w	Boolean	true 表示窗口已关闭。注:可能会缺失 true 的消息,但不影响数据的完整性
-{
-  "time": 1542162490,
-  "time_ms": 1542162490123,
-  "channel": "futures.candlesticks",
-  "event": "update",
-  "result": [
-    {
-      "t": 1545129300,
-      "v": "27525555",
-      "c": "95.4",
-      "h": "96.9",
-      "l": "89.5",
-      "o": "94.3",
-      "n": "1m_BTC_USD",
-      "a": "314732.87412",
-      "w": false
-    },
-    {
-      "t": 1545129300,
-      "v": "27525555",
-      "c": "95.4",
-      "h": "96.9",
-      "l": "89.5",
-      "o": "94.3",
-      "n": "1m_BTC_USD",
-      "a": "314732.87412",
-      "w": true
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅指定市场 K 线信息
-
-#请求参数
-channel
-
-futures.candlesticks
-
-event
-
-unsubscribe
-
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send(
-  '{"time" : 123456, "channel" : "futures.candlesticks", "event": "unsubscribe", "payload" : ["1m", "BTC_USD"]}')
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545445847,
-  "time_ms": 1545445847123,
-  "channel": "futures.candlesticks",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#公共强平订单频道
-提供一种接收Gate强平订单信息的方式,每个合约每1秒最多推一条强平订单数据
-
-#公共强平订单订阅
-如果您想订阅所有合约中的强平订单推送,请在订阅请求列表中使用 !all
-
-订阅公共强平订单推送
-
-#请求参数
-channel
-
-futures.public_liquidates
-
-event
-
-subscribe
-
-params
-
-名称	类型	必选	描述
-contract	String	是	合约名称列表
-代码示例
-
-import json
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": 123456,
-    "channel": "futures.public_liquidates",
-    "event": "subscribe",
-    "payload": ["BTC_USD","ETH_USD"],
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-    "time": 1545459681,
-    "time_ms": 1545459681123,
-    "channel": "futures.public_liquidates",
-    "event": "subscribe",
-    "result": {
-        "status": "success"
-    }
-}
-Copy
-#公共强平订单推送
-推送公共强制平仓更新
-
-#推送参数
-channel
-
-futures.public_liquidates
-
-event
-
-update
-
-params
-
-名称	类型	描述
-result	Array	Array of objects
-名称	类型	描述
-price	Float	订单价格
-size	String/Integer	强平订单数量
-time_ms	Integer	时间(以毫秒为单位)
-contract	String	合约名称
-{
-    "channel": "futures.public_liquidates",
-    "event": "update",
-    "time": 1541505434,
-    "time_ms": 1541505434123,
-    "result": [
-        {
-        "price": 215.1,
-        "size": "-124",
-        "time_ms": 1541486601123,
-        "contract": "BTC_USD",
-        }
-    ]
-}
-Copy
-#取消订阅
-取消订阅公共强平订单更新
-
-#请求参数
-channel
-
-futures.public_liquidates
-
-event
-
-unsubscribe
-
-代码示例
-
-import json
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": 123456,
-    "channel": "futures.public_liquidates",
-    "event": "unsubscribe",
-    "payload": ["BTC_USD"],
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
- {
-    "time": 1545459681,
-    "time_ms": 1545459681123,
-     "channel": "futures.public_liquidates",
-     "event": "unsubscribe",
-     "result": {
-        "status": "success"
-     }
-}
-Copy
-#合约统计信息频道
-contract_stats 通道允许您获取合约统计信息
-
-#订阅操作
-订阅合约统计信息
-
-#请求参数
-channel
-
-futures.contract_stats
-
-event
-
-subscribe
-
-params
-
-名称	类型	必选	描述
-contract	String	Yes	合约名称
-interval	String	Yes	Interval : "1m", "5m", "15m", "30m", "1h", "4h", "8h", "1d", "3d", "7d"
-代码示例
-
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-ws.send('{"time" : 123456, "channel" : "futures.contract_stats","event": "subscribe", "payload" : ["BTC_USD","1m"]}')
-print(ws.recv())
-Copy
-上面的订阅请求返回 JSON 结构如下:
-
-{
-  "time": 1545404023,
-  "time_ms": 1545404023123,
-  "channel": "futures.contract_stats",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#contract_stats 推送
-合约统计信息推送
-
-#推送参数
-channel
-
-futures.contract_stats
-
-event
-
-update
-
-params
-
-名称	类型	描述
-result	Array	Array of objects
-名称	类型	描述
-time	Integer	统计时间(时间戳)
-contract	string	合约名称
-mark_price	Float	当前标记价格
-lsr_taker	Float	多空吃单比
-lsr_account	Float	多空持仓用户比
-long_liq_size	string/Integer	做多爆仓量(张)
-long_liq_amount	Float	做多爆仓量(交易币种)
-long_liq_usd	Float	做多爆仓量(计价币种)
-short_liq_size	string/Integer	做空爆仓量(张)
-short_liq_amount	Float	做空爆仓量(交易币种)
-short_liq_usd	Float	做空爆仓量(计价币种)
-open_interest	string/Integer	总持仓量(张)
-open_interest_usd	Float	总持仓量(计价币种)
-top_lsr_account	Float	大户多空账户比
-top_lsr_size	Float	大户多空持仓比
-{
-  "time": 1541659086,
-  "time_ms": 1541659086123,
-  "channel": "futures.contract_stats",
-  "event": "update",
-  "result": [
-    {
-      "time": 1603865400,
-      "contract":"BTC_USDT",
-      "lsr_taker": 100,
-      "lsr_account": 0.5,
-      "long_liq_size": "0",
-      "short_liq_size": "0",
-      "open_interest": "124724",
-      "short_liq_usd": 0,
-      "mark_price": "8865",
-      "top_lsr_size": 1.02,
-      "short_liq_amount": 0,
-      "long_liq_amount": 0,
-      "open_interest_usd": 1511,
-      "top_lsr_account": 1.5,
-      "long_liq_usd": 0
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅
-
-#请求参数
-channel
-
-futures.contract_stats
-
-event
-
-unsubscribe
-
-params
-
-名称	类型	必选	描述
-contract	String	Yes	合约名称
-interval	String	Yes	Interval : "1m", "5m", "15m", "30m", "1h", "4h", "8h", "1d", "3d", "7d"
-注意:contract为unsub_all,表示全部取消
-
-代码示例
-
-import json
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": 123456,
-    "channel": "futures.contract_stats",
-    "event": "unsubscribe",
-    "payload": ["BTC_USD","1m"]
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的请求返回 JSON 结构如下:
-
-{
-  "time": 1545404900,
-  "time_ms": 1545404900123,
-  "channel": "futures.contract_stats",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#订单频道
-提供接收用户订单的推送
-
-需要认证.
-
-#订单订阅
-如果您想订阅所有合约中的订单更新,请在合约列表中使用 !all。
-
-订阅订单更新推送
-
-#请求参数
-channel
-
-futures.orders
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-user id	String	是	用户 ID
-contract	String	是	合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": int(time.time()),
-  "channel": "futures.orders",
-  "event": "subscribe",
-  "payload": ["20011", "BTC_USD"],
-  "auth": {
-    "method": "api_key",
-    "KEY": "xxxx",
-    "SIGN": "xxxx"
-  }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.orders",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#订单推送
-下单、更新或完成时通知用户订单信息
-
-#推送参数
-channel
-
-futures.orders
-
-event
-
-update
-
-params
-
-推送结果参数含义请参考http接口.
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-create_time	Integer	订单创建时间(已弃用)
-create_time_ms	Integer	订单创建时间戳(以毫秒为单位)
-fill_price	Float	订单成交价格
-finish_as	String	订单是如何完成的。
-- filled:全部成交
-- cancelled:手动取消
-- liquidated:因清算而取消
-- ioc:生效时间为 IOC,立即完成
-- auto_deleveraging:ADL 完成
-- reduce_only:因减仓设置而增仓而取消
-- position_close:因平仓而取消
-- stp:订单发生自成交限制而被撤销
-- _new:新建
-- _update:成交或部分成交或更新订单
-- reduce_out: 只减仓被排除的不容易成交的挂单
-iceberg	String/Integer	冰山下单显示的数量,不指定或传 0 都默认为普通下单。目前不支持全部冰山。
-id	Integer	订单 ID
-is_close	Bool	该订单是否为 close position
-is_liq	Bool	该订单是否为 liquidation
-left	String/Integer	剩余可交易数量
-mkfr	Float	Maker 费用
-is_reduce_only	Bool	该订单是否为 reduce-only
-status	String	订单状态
-- open: 等待交易
-- finished: 完成
-tkfr	Float	taker 费用
-price	Float	订单价格。 0 表示市价订单,tif 设置为 ioc
-refu	Integer	推荐用户 ID
-refr	Float	
-size	String/Integer	订单大小。指定正数进行出价,指定负数进行询问
-text	String	用户定义的信息
-tif	String	有效时间
-- gtc:GoodTillCancelled
-- ioc:ImmediateOrCancelled,仅接受者
-- poc:PendingOrCancelled,只进行后订单,始终享受挂单费用
-- fok: FillOrKill,完全填充或不填充
-type=market 时仅支持 ioc 和 fok
-finish_time	Integer	订单结束 unix 时间戳(以秒为单位),未结束订单此字段返回0
-finish_time_ms	Integer	订单结束 unix 时间戳(以毫秒为单位),未结束订单此字段返回0
-user	String	用户 ID
-contract	String	合约名称
-stp_id	String	同一 stp_id 组内的用户之间的订单不允许自交易
-1.如果匹配的两个订单的 stp_id 非零且相等,则不会被执行。而是根据 taker 的 stp_act 执行相应的策略。
-2.对于未设置 STP 组的订单,stp_id 默认返回 0
-stp_act	String	自我交易预防行动。用户可以通过该字段设置自我交易防范策略
-1.用户加入 STP Group 后,可以通过 stp_act 来限制用户的自我交易防范策略。如果不传 stp_act,则默认为 cn 策略。
-2.当用户没有加入 STP 组时,传递 stp_act 参数时会返回错误。
-3.如果用户下单时没有使用'stp_act','stp_act'将返回'-'
-- cn: 取消最新订单,取消新订单并保留旧订单
-- co: 取消最旧订单,取消旧订单并保留新订单
-- cb:取消两者,新旧订单都会被取消
-amend_text	String	用户修改订单时备注的自定义数据
-update_id	Integer	更新id
-update_time	Integer	更新时间 (毫秒时间戳)
-biz_info	String	用户可以备注这次修改的信息
-stop_profit_price	String	止盈价格
-stop_loss_price	String	止损价格
-market_order_slip_ratio	String	该笔市价单的预设的最大滑点比率(不代表实际的滑点),0.03代表3%的最大滑点
-{
-  "channel": "futures.orders",
-  "event": "update",
-  "time": 1541505434,
-  "time_ms": 1541505434123,
-  "result": [
-    {
-      "contract": "BTC_USD",
-      "create_time": 1628736847,
-      "create_time_ms": 1628736847325,
-      "fill_price": 40000.4,
-      "finish_as": "filled",
-      "finish_time": 1628736848,
-      "finish_time_ms": 1628736848321,
-      "iceberg": "0",
-      "id": 4872460,
-      "is_close": false,
-      "is_liq": false,
-      "is_reduce_only": false,
-      "left": "0",
-      "mkfr": -0.00025,
-      "price": 40000.4,
-      "refr": 0,
-      "refu": 0,
-      "size": "1",
-      "status": "finished",
-      "text": "-",
-      "tif": "gtc",
-      "tkfr": 0.0005,
-      "user": "110xxxxx",
-      "update_id": 1,
-      "update_time": 1541505434123,
-      "stop_loss_price": "",
-      "stop_profit_price": "",
-      "market_order_slip_ratio": "0.03"
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅订单更新通知
-
-#请求参数
-channel
-
-futures.orders
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": int(time.time()),
-  "channel": "futures.orders",
-  "event": "unsubscribe",
-  "payload": ["20011", "BTC_USD"],
-  "auth": {
-    "method": "api_key",
-    "KEY": "xxxx",
-    "SIGN": "xxxx"
-  }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.orders",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#用户私有成交频道
-提供接收用户交易的方式
-
-需要认证
-
-#用户私有成交订阅
-如果您想订阅所有的市场交易更新,请在请求参数列表中使用!all。
-
-订阅私有成交更新
-
-#请求参数
-channel
-
-futures.usertrades
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-user id	String	是	用户 ID
-contract	String	是	合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": int(time.time()),
-  "channel": "futures.usertrades",
-  "event": "subscribe",
-  "payload": ["20011", "BTC_USD"],
-  "auth": {
-    "method": "api_key",
-    "KEY": "xxxx",
-    "SIGN": "xxxx"
-  }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.usertrades",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#用户私有成交推送
-推送用户私有成交更新
-
-#推送参数
-channel
-
-futures.usertrades
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-contract	String	合约名称
-create_time	Integer	创建时间
-create_time_ms	Integer	创建时间(以毫秒为单位)
-id	String	交易 ID
-order_id	String	订单 ID
-price	String	交易价格
-size	String/Integer	交易数量
-role	String	用户角色 (maker/taker)
-text	String	订单自定义信息,用户可以用该字段设置自定义 ID,用户自定义字段必须满足以下条件:
-
-1. 必须以 t- 开头
-2. 不计算 t- ,长度不能超过 28 字节
-3. 输入内容只能包含数字、字母、下划线(_)、中划线(-) 或者点(.)
-
-除用户自定义信息以外,以下为内部保留字段,标识订单来源:
-
-- web: 网页
-- api: API 调用
-- app: 移动端
-- auto_deleveraging: 自动减仓
-- liquidation: 老经典模式仓位强制平仓
-- liq-xxx: a. 新经典模式仓位强制平仓,包含逐仓、单向全仓、双向全仓非对冲仓位强平。 b. 统一账户单币种保证金模式逐仓强制平仓
-- hedge-liq-xxx: 新经典模式双向全仓对冲部分强制平仓,即同时平多空仓位
-- pm_liquidate: 统一账户跨币种保证金模式强制平仓
-- comb_margin_liquidate: 统一账户组合保证金模式强制平仓
-- scm_liquidate: 统一账户单币种保证金模式仓位强制平仓
-- insurance: 保险
-- clear: 合约下架清退
-fee	Float	手续费
-point_fee	Float	点卡手续费
-{
-  "time": 1543205083,
-  "time_ms": 1543205083123,
-  "channel": "futures.usertrades",
-  "event": "update",
-  "result": [
-    {
-      "id": "3335259",
-      "create_time": 1628736848,
-      "create_time_ms": 1628736848321,
-      "contract": "BTC_USD",
-      "order_id": "4872460",
-      "size": "1",
-      "price": "40000.4",
-      "role": "maker",
-      "text": "api",
-      "fee": 0.0009290592,
-      "point_fee": 0
-    }
-  ]
-}
-Copy
-#取消订阅
-取消私有成交订阅
-
-#请求参数
-channel
-
-futures.usertrades
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": int(time.time()),
-  "channel": "futures.usertrades",
-  "event": "unsubscribe",
-  "payload": ["20011", "BTC_USD"],
-  "auth": {
-    "method": "api_key",
-    "KEY": "xxxx",
-    "SIGN": "xxxx"
-  }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.usertrades",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#强制平仓频道
-提供一种接收用户强制平仓信息的方式
-
-需要认证
-
-#清算订阅
-如果您想订阅所有合约中的强制平仓推送,请在订阅请求列表中使用 !all
-
-订阅用户强制平仓推送
-
-#请求参数
-channel
-
-futures.liquidates
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-user id	String	是	用户 ID
-contract	String	是	合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": int(time.time()),
-  "channel": "futures.liquidates",
-  "event": "subscribe",
-  "payload": ["20011", "BTC_USD"],
-  "auth": {
-    "method": "api_key",
-    "KEY": "xxxx",
-    "SIGN": "xxxx"
-  }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.liquidates",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#强制平仓推送
-推送强制平仓更新
-
-#推送参数
-channel
-
-futures.liquidates
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-entry_price	Float	平均入场价
-fill_price	Float	平均执行价格
-leverage	Float	杠杆大小
-liq_price	Float	清算价格
-margin	Float	Margin
-mark_price	Float	标记价格
-order_id	Integer	订单 ID
-order_price	Float	订单价格
-left	String/Integer	订单未完成数量
-size	Integer	原始订单数量
-time	Integer	时间
-time_ms	Integer	时间(以毫秒为单位)
-user	String	用户 ID
-contract	String	合约名称
-{
-  "channel": "futures.liquidates",
-  "event": "update",
-  "time": 1541505434,
-  "time_ms": 1541505434123,
-  "result": [
-    {
-      "entry_price": 209,
-      "fill_price": 215.1,
-      "left": 0,
-      "leverage": 0.0,
-      "liq_price": 213,
-      "margin": 0.007816722941,
-      "mark_price": 213,
-      "order_id": 4093362,
-      "order_price": 215.1,
-      "size": "-124",
-      "time": 1541486601,
-      "time_ms": 1541486601123,
-      "contract": "BTC_USD",
-      "user": "1040xxxx"
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅清算更新
-
-#请求参数
-channel
-
-futures.liquidates
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": int(time.time()),
-  "channel": "futures.liquidates",
-  "event": "unsubscribe",
-  "payload": ["20011", "BTC_USD"],
-  "auth": {
-    "method": "api_key",
-    "KEY": "xxxx",
-    "SIGN": "xxxx"
-  }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.liquidates",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#自动减仓频道
-提供一种接收用户自动减仓信息的方法
-
-需要认证
-
-#自动减仓订阅
-如果您想订阅所有合约的自动减仓更新,请在请求参数列表中使用!all
-
-订阅用户自动减仓更新
-
-#请求参数
-channel
-
-futures.auto_deleverages
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-user id	String	是	用户 ID
-contract	String	是	合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": int(time.time()),
-  "channel": "futures.auto_deleverages",
-  "event": "subscribe",
-  "payload": ["20011", "BTC_USD"],
-  "auth": {
-    "method": "api_key",
-    "KEY": "xxxx",
-    "SIGN": "xxxx"
-  }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.auto_deleverages",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#自动减仓推送
-自动减仓消息
-
-#推送参数
-channel
-
-futures.auto_deleverages
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-entry_price	Float	入场价格
-fill_price	Float	执行价格
-position_size	Integer	持仓规模
-trade_size	Integer	交易数量
-time	Integer	时间
-time_ms	Integer	时间(以毫秒为单位)
-user	String	用户 ID
-contract	String	合约名称
-{
-  "channel": "futures.auto_deleverages",
-  "event": "update",
-  "time": 1541505434,
-  "time_ms": 1541505434123,
-  "result": [
-    {
-      "entry_price": 209,
-      "fill_price": 215.1,
-      "position_size": "10",
-      "trade_size": "10",
-      "time": 1541486601,
-      "time_ms": 1541486601123,
-      "contract": "BTC_USD",
-      "user": "1040"
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅自动减仓
-
-#请求参数
-channel
-
-futures.auto_deleverages
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": int(time.time()),
-  "channel": "futures.auto_deleverages",
-  "event": "unsubscribe",
-  "payload": ["20011", "BTC_USD"],
-  "auth": {
-    "method": "api_key",
-    "KEY": "xxxx",
-    "SIGN": "xxxx"
-  }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.auto_deleverages",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#平仓频道
-提供一种接收用户仓位平仓信息的方法
-
-需要认证
-
-#平仓订阅
-如果您想订阅所有合约的平仓更新,请在合约列表中使用 !all
-
-订阅用户平仓信息更新
-
-#请求参数
-channel
-
-futures.position_closes
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-user id	String	是	用户 ID
-contract	String	是	合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-  "time": int(time.time()),
-  "channel": "futures.position_closes",
-  "event": "subscribe",
-  "payload": ["20011", "BTC_USD"],
-  "auth": {
-    "method": "api_key",
-    "KEY": "xxxx",
-    "SIGN": "xxxx"
-  }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.position_closes",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#平仓信息推送
-平仓信息推送
-
-#推送参数
-channel
-
-futures.position_closes
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-contract	String	合约名称
-pnl	Number	利润损失
-side	String	方向 (long or short)
-text	String	附带信息
-time	Integer	时间
-time_ms	Integer	时间(以毫秒为单位)
-user	String	用户 ID
-{
-  "channel": "futures.position_closes",
-  "event": "update",
-  "time": 1541505434,
-  "time_ms": 1541505434123,
-  "result": [
-    {
-      "contract": "BTC_USD",
-      "pnl": -0.000624354791,
-      "side": "long",
-      "text": "web",
-      "time": 1547198562,
-      "time_ms": 1547198562123,
-      "user": "211xxxx"
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅平仓更新
-
-#请求参数
-channel
-
-futures.position_closes
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.position_closes",
-    "event": "unsubscribe",
-    "payload": ["20011", "BTC_USD"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.position_closes",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#余额频道
-提供一种接收用户余额信息的方法
-
-需要认证
-
-#余额信息订阅
-订阅用户余额更新
-
-#请求参数
-channel
-
-futures.balances
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-user id	String	是	用户 ID
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.balances",
-    "event": "subscribe",
-    "payload": ["20011"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.balances",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#余额更新推送
-通知余额更新信息
-
-#推送参数
-channel
-
-futures.balances
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-balance	Number	余额最终数量
-change	Number	余额变化数量
-text	String	附带信息
-time	Integer	时间
-time_ms	Integer	时间(以毫秒为单位)
-type	String	变更类型:
-dnw: 出入金
-pnl:盈亏
-refr: 推荐人费用
-fund: 资金费用
-cross_settle: 统一账户结算
-point_dnw: 点卡出入金
-point_fee: 点卡手续费
-point_refr: 点卡推荐人费用
-bonus_dnw: 体验金出入金
-pv_dnw: 仓位体验券充值提现
-fee: 手续费
-user	String	用户 ID
-currency	String	币种
-{
-  "channel": "futures.balances",
-  "event": "update",
-  "time": 1541505434,
-  "time_ms": 1541505434123,
-  "result": [
-    {
-      "balance": 9.998739899488,
-      "change": -0.000002074115,
-      "text": "BTC_USD:3914424",
-      "time": 1547199246,
-      "time_ms": 1547199246123,
-      "type": "fee",
-      "user": "211xxx",
-      "currency": "btc"
-    }
-  ]
-}
-Copy
-#取消订阅
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.balances",
-    "event": "unsubscribe",
-    "payload": ["20011"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.balances",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#降低风险率频道
-推送用户降低风险率信息
-
-需要认证
-
-#降低风险率订阅
-如果您想订阅所有合约的降低风险率更新,请在合约列表中使用 !all。
-
-订阅用户降低风险率更新
-
-#请求参数
-channel
-
-futures.reduce_risk_limits
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-user id	String	是	用户 ID
-contract	String	是	合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.reduce_risk_limits",
-    "event": "subscribe",
-    "payload": ["20011", "BTC_USD"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.reduce_risk_limits",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#降低风险率推送
-通知降低风险限制更新
-
-#推送参数
-channel
-
-futures.reduce_risk_limits
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-cancel_orders	Integer	Cancel orders
-contract	String	合约名称
-leverage_max	Integer	最大杠杆
-liq_price	Float	清算价格
-maintenance_rate	Float	Maintenance rate
-risk_limit	Integer	风险限额
-time	Integer	时间
-time_ms	Integer	时间(以毫秒为单位)
-user	String	用户 ID
-{
-  "time": 1551858330,
-  "time_ms": 1551858330123,
-  "channel": "futures.reduce_risk_limits",
-  "event": "update",
-  "result": [
-    {
-      "cancel_orders": 0,
-      "contract": "ETH_USD",
-      "leverage_max": 10,
-      "liq_price": 136.53,
-      "maintenance_rate": 0.09,
-      "risk_limit": 450,
-      "time": 1551858330,
-      "time_ms": 1551858330123,
-      "user": "20011"
-    }
-  ]
-}
-Copy
-#取消订阅
-退订降低风险限制更新
-
-#请求参数
-channel
-
-futures.reduce_risk_limits
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.reduce_risk_limits",
-    "event": "unsubscribe",
-    "payload": ["20011", "BTC_USD"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-#仓位频道
-提供一种接收用户仓位信息的方法
-
-需要认证
-
-#仓位订阅
-如果您想订阅所有合约的持仓更新,请在合约列表中使用 !all
-
-订阅用户仓位更新
-
-#请求参数
-channel
-
-futures.positions
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-user id	String	是	用户 ID (该字段已废弃,仅做占位符使用)
-contract	String	是	合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.positions",
-    "event": "subscribe",
-    "payload": ["20011", "BTC_USD"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.positions",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#仓位信息推送
-推送仓位更新.
-
-#推送参数
-channel
-
-futures.positions
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-contract	String	合约名称
-cross_leverage_limit	Float	全仓模式下的杠杆倍数
-entry_price	Float	开仓价格
-history_pnl	Float	已平仓的仓位总盈亏
-history_point	Float	已平仓的点卡总盈亏
-last_close_pnl	Float	最近一次平仓的盈亏
-leverage	Integer	杠杆倍数,0代表全仓,正数代表逐仓
-leverage_max	Integer	当前风险限额下,允许的最大杠杆倍数
-liq_price	Float	爆仓价格
-maintenance_rate	Float	当前风险限额下,维持保证金比例
-margin	Float	保证金
-realised_pnl	Float	已实现盈亏
-realised_point	Float	点卡已实现盈亏
-risk_limit	Integer	风险限额
-size	String/Integer	合约 size
-time	Integer	更新 unix 时间戳
-time_ms	Integer	更新 unix 时间戳(以毫秒为单位)
-user	String	用户 ID
-update_id	Integer	消息序列号,每次推送 order 之后会自增 1
-{
-  "time": 1588212926,
-  "time_ms": 1588212926123,
-  "channel": "futures.positions",
-  "event": "update",
-  "result": [
-    {
-      "contract": "BTC_USD",
-      "cross_leverage_limit": 0,
-      "entry_price": 40000.36666661111,
-      "history_pnl": -0.000108569505,
-      "history_point": 0,
-      "last_close_pnl": -0.000050123368,
-      "leverage": 0,
-      "leverage_max": 100,
-      "liq_price": 0.1,
-      "maintenance_rate": 0.005,
-      "margin": 49.999890611186,
-      "mode": "single",
-      "realised_pnl": -1.25e-8,
-      "realised_point": 0,
-      "risk_limit": 100,
-      "size": "3",
-      "time": 1628736848,
-      "time_ms": 1628736848321,
-      "user": "110xxxxx",
-      "update_id": 170919
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅仓位更新
-
-#请求参数
-channel
-
-futures.positions
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.positions",
-    "event": "unsubscribe",
-    "payload": ["20011", "BTC_USD"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.positions",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#仓位 Adl 排名频道
-推送用户仓位 adl 排名信息的频道
-
-需要认证
-
-#仓位 adl 订阅
-如果您想订阅所有合约的 adl 更新,请在合约列表中使用 !all
-
-订阅用户仓位 adl 更新
-
-#请求参数
-channel
-
-futures.position_adl_rank
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-contract	String	是	合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://ws-testnet.gate.com/v4/ws/futures/usdt")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.position_adl_rank",
-    "event": "subscribe",
-    "payload": ["BTC_USDT"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.position_adl_rank",
-  "event": "subscribe",
-  "payload": [
-    "BTC_USDT"
-  ],
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#仓位 adl 信息推送
-推送仓位更新.
-
-#推送参数
-channel
-
-futures.position_adl_rank
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-contract	String	合约名称
-mode	String	持仓模式
-rank_division	Integer	排名区间(1~6,1为最优先被ADL的区间,5为最靠后被ADL的区间。6:爆仓中不参与ADL排序)
-time_ms	Integer	消息推送的毫秒时间戳
-user_id	Integer	用户 ID
-{
-    "time": 1588212926,
-    "time_ms": 1588212926123,
-    "channel": "futures.position_adl_rank",
-    "event": "update",
-    "result": [
-        {
-            "contract": "BTC_USDT",
-            "mode": "single",
-            "rank_division": 1,
-            "time_ms": 1588212926119,
-            "user_id": 2124426495
-        }
-    ]
-}
-Copy
-#取消订阅
-取消订阅仓位更新
-
-#请求参数
-channel
-
-futures.position_adl_rank
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://ws-testnet.gate.com/v4/ws/futures/usdt")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.position_adl_rank",
-    "event": "unsubscribe",
-    "payload": ["BTC_USDT"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.position_adl_rank",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#自动订单频道
-提供一种接收用户自动订单信息的方法
-
-需要认证
-
-#自动订单订阅
-如果您想订阅所有合约中的自动订单更新,请在合约列表中使用!all
-
-订阅用户自动订单更新
-
-#请求参数
-channel
-
-futures.autoorders
-
-event
-
-subscribe
-
-params
-
-请求参数
-名称	类型	必选	描述
-contract	String	是	合约名称
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.autoorders",
-    "event": "subscribe",
-    "payload": ["BTC_USDT"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }
-}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.autoorders",
-  "event": "subscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#自动订单消息推送
-通知自动订单更新
-
-#推送参数
-channel
-
-futures.autoorders
-
-event
-
-update
-
-params
-
-推送参数
-名称	类型	描述
-result	Array	Array of objects
-推送参数
-名称	类型	描述
-user	Number	用户 ID
-trigger	Object	
-initial	Object	
-id	Number	自动订单 ID
-trade_id	Number	交易 ID
-status	String	订单状态
-reason	String	变更原因
-create_time	Number	创建时间
-name	String	名称
-is_stop_order	boolean	是否停止
-stop_trigger	Object	
-order_type	String	止盈/止损类型,详情参见 http api
-me_order_id	Number	订单止盈/止损对应订单 ID.
-{
-  "time": 1596798126,
-  "time_ms": 1596798126123,
-  "channel": "futures.autoorders",
-  "event": "update",
-  "result": [
-    {
-      "user": 123456,
-      "trigger": {
-        "strategy_type": 0,
-        "price_type": 0,
-        "price": "10000",
-        "rule": 2,
-        "expiration": 86400
-      },
-      "initial": {
-        "contract": "BTC_USDT",
-        "size": "10",
-        "price": "10000",
-        "tif": "gtc",
-        "text": "web",
-        "iceberg": "0",
-        "is_close": false,
-        "is_reduce_only": false,
-        "auto_size": ""
-      },
-      "id": 9256,
-      "trade_id": 0,
-      "status": "open",
-      "reason": "",
-      "create_time": 1596798126,
-      "name": "price_autoorders",
-      "is_stop_order": false,
-      "stop_trigger": {
-        "rule": 0,
-        "trigger_price": "",
-        "order_price": ""
-      },
-      "order_type": "close-long-order",
-      "me_order_id": "213867453823"
-    }
-  ]
-}
-Copy
-#取消订阅
-取消订阅自动订单更新
-
-#请求参数
-channel
-
-futures.autoorders
-
-event
-
-unsubscribe
-
-代码示例
-
-import json, time
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws-testnet.gateio.ws/v4/ws/btc")
-req = {
-    "time": int(time.time()),
-    "channel": "futures.autoorders",
-    "event": "unsubscribe",
-    "payload": ["BTC_USDT"],
-    "auth": {
-        "method": "api_key",
-        "KEY": "xxxx",
-        "SIGN": "xxxx"
-    }}
-ws.send(json.dumps(req))
-print(ws.recv())
-Copy
-上面的命令返回 JSON 结构如下:
-
-{
-  "time": 1545459681,
-  "time_ms": 1545459681123,
-  "channel": "futures.autoorders",
-  "event": "unsubscribe",
-  "result": {
-    "status": "success"
-  }
-}
-Copy
-#账户交易 API
-#Websocket 交易 API
-WebSocket API 允许通过 WebSocket 连接下单、取消、修改、查询订单.
-
-#Websocket API 客户端请求
-客户端发起的 api 请求遵循通用的 JSON 格式, 包含以下字段:
-
-名称	类型	必选	描述
-time	Integer	是	请求时间(以秒为单位)。请求时间和服务器时间之间的差距不得超过 60 秒
-id	Integer	否	可选的请求 ID,将由服务器发回,以帮助您识别服务器响应哪个请求
-channel	String	是	要访问的 WebSocket 频道
-event	String	是	固定为api
-payload	Object	是	可选请求详细参数
-»req_id	String	是	消息的唯一标识符由客户端提供,将在响应消息中返回,用于标识相应的请求。
-»timestamp	String	是	签名时间(秒)
-»api_key	String	是	Gate APIv4 APIKey
-»signature	String	是	使用 GateAPIv4 密钥和请求信息生成的身份验证签名,
-详细信息请参见[Websocket API 身份验证](#Websocket API 身份验证)部分
-»req_param	[]Byte	是	请求 api 参数
-请注意,payload.req_param 的类型是与频道(channel字段)绑定的,频道不同payload.req_param 的字段也不同,以 futures.order_place 为例,payload.req_param 与 apiv4 /futures/{settle}/orders (opens new window)。 例如,您可以对 BTC_USDT 下限价单
-
-代码示例
-
-#!/usr/bin/python
-
-import time
-import json
-import hmac
-import hashlib
-import websocket
-import threading
-
-
-API_KEY = "xxxxx"
-SECRET = "xxxxx"
-WS_URL = "wss://fx-ws.gateio.ws/v4/ws/usdt"
-CHANNEL_LOGIN = "futures.login"
-CHANNEL_ORDER_PLACE = "futures.order_place"
-
-def get_ts():
-    return int(time.time())
-
-def get_ts_ms():
-    return int(time.time() * 1000)
-
-def get_signature(secret, channel, request_param_bytes, ts):
-    key = f"api\n{channel}\n{request_param_bytes.decode()}\n{ts}"
-    return hmac.new(secret.encode(), key.encode(), hashlib.sha512).hexdigest()
-
-def build_login_request():
-    ts = get_ts()
-    req_id = f"{get_ts_ms()}-1"
-    request_param = b""
-
-    sign = get_signature(SECRET, CHANNEL_LOGIN, request_param, ts)
-
-    payload = {
-        "api_key": API_KEY,
-        "signature": sign,
-        "timestamp": str(ts),
-        "req_id": req_id
-    }
-
-    return {
-        "time": ts,
-        "channel": CHANNEL_LOGIN,
-        "event": "api",
-        "payload": payload
-    }
-
-
-def build_order_request():
-    ts = get_ts()
-    req_id = f"{get_ts_ms()}-2"
-    order_param = {
-        "contract": "BTC_USDT",
-        "size": 6024,
-        "iceberg": 0,
-        "price": "3765",
-        "tif": "gtc",
-        "text": "t-my-custom-id",
-        "stp_act": "-"
-    }
-
-
-    payload = {
-        "req_id": req_id,
-        "req_param": order_param
-    }
-
-    return {
-        "time": ts,
-        "channel": CHANNEL_ORDER_PLACE,
-        "event": "api",
-        "payload": payload
-    }
-
-
-def on_message(ws, message):
-    print(f"recv: {message}")
-
-def on_error(ws, error):
-    print(f"error: {error}")
-
-def on_close(ws, close_status_code, close_msg):
-    print("connection closed")
-
-def on_open(ws):
-    print("WebSocket opened")
-
-    login_payload = build_login_request()
-    print("login payload:", login_payload)
-    ws.send(json.dumps(login_payload))
-
-    def delayed_order():
-        time.sleep(2)
-        order_payload = build_order_request()
-        print("order payload:", order_payload)
-        ws.send(json.dumps(order_payload))
-
-    threading.Thread(target=delayed_order).start()
-
-custom_headers = {
-    "X-Gate-Size-Decimal": "1"
-}
-
-if __name__ == "__main__":
-    ws = websocket.WebSocketApp(
-        WS_URL,
-        on_message=on_message,
-        on_error=on_error,
-        on_close=on_close,
-        on_open=on_open,
-        header=custom_headers
-    )
-    ws.run_forever()
-
-Copy
-{
-  "time": 1680772890,
-  "channel": "futures.order_place",
-  "event": "api",
-  "payload": {
-    "req_id": "xxxx",
-    "req_param": {
-      "contract": "BTC_USDT",
-      "size": "10",
-      "price": "80048.240000",
-      "tif": "gtc",
-      "text": "t-my-custom-id"
-    }
-  }
-}
-Copy
-#Websocket API 服务响应
-服务器响应包括对客户端请求的 ack 响应和 api 结果消息推送。 服务器响应遵循通用的 JSON 格式,其中包含以下字段:
-
-名称	类型	描述
-request_id	String	对应的请求 ID
-header	Map	响应元信息
-»response_time	String	响应发送时间(毫秒)
-»channel	String	请求频道
-»event	String	请求event
-»client_id	String	唯一的客户端 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»x_gate_ratelimit_requests_remain	Integer	(仅涉及下单/改单/撤单)当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit	Integer	(仅涉及下单/改单/撤单)当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp	Integer	(仅涉及下单/改单/撤单)已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-data	Object	请求响应的数据
-»result	Object	如果这是 ack 响应,则结果是请求的payload,否则结果是 api 的响应
-»errs	Object	仅当请求失败时可用
-»»label	String	错误类型
-»»message	String	详细错误信息
-服务器回声确认响应示例(目前仅在下单请求中有回声响应)
-
-{
-  "request_id": "request-id-1",
-  "ack": true,
-  "header": {
-    "response_time": "1681195121499",
-    "status": "200",
-    "channel": "futures.order_place",
-    "event": "api",
-    "client_id": "::1-0x140031563c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_requests_remain": 99,
-    "x_gate_ratelimit_limit": 100,
-    "x_gate_ratelimit_reset_timestamp": 1681195121499
-  },
-  "data": {
-    "result": {
-      "req_id": "request-id-1",
-      "req_param": {
-        "contract": "BTC_USDT",
-        "size": "10",
-        "price": "31503.280000",
-        "tif": "gtc",
-        "text": "t-my-custom-id"
-      }
-    }
-  }
-}
-Copy
-服务器 API 响应示例
-
-{
-  "request_id": "request-id-1",
-  "ack": false,
-  "header": {
-    "response_time": "1681195121639",
-    "status": "200",
-    "channel": "futures.order_place",
-    "event": "api",
-    "client_id": "::1-0x140031563c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_requests_remain": 99,
-    "x_gate_ratelimit_limit": 100,
-    "x_gate_ratelimit_reset_timestamp": 1681195121639
-  },
-  "data": {
-    "result": {
-      "id": 74046511,
-      "user": 6790020,
-      "create_time": 1681195121.754,
-      "finish_time": 1681195121.754,
-      "finish_as": "filled",
-      "status": "finished",
-      "contract": "BTC_USDT",
-      "size": "10",
-      "price": "31503.3",
-      "tif": "gtc",
-      "fill_price": "31500",
-      "text": "t-my-custom-id",
-      "tkfr": "0.0003",
-      "mkfr": "0",
-      "stp_id": 2,
-      "stp_act": "cn",
-      "amend_text": "-"
-    }
-  }
-}
-Copy
-#错误
-错误响应详情具有以下格式:
-
-
-名称	类型	描述
-label	String	错误类型
-message	String	详细错误信息
-限频相关的错误码说明:
-
-错误码	描述
-100	限流内部异常错误
-311	合约限流
-312	合约成交比率限流
-错误响应通知示例
-
-{
-  "request_id": "request-id-1",
-  "ack": false,
-  "header": {
-    "response_time": "1681195360034",
-    "status": "401",
-    "channel": "futures.login",
-    "event": "api",
-    "client_id": "::1-0x140001a2600",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d"
-  },
-  "data": {
-    "errs": {
-      "label": "INVALID_KEY",
-      "message": "Invalid key provided"
-    }
-  }
-}
-Copy
-Error 推送示例(限速)
-
-{
-  "request_id": "xxxx",
-  "header": {
-    "response_time": "1677816784084",
-    "status": "429",
-    "channel": "futures.order_place",
-    "event": "api",
-    "client_id": "::1-0x14002ba2300",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_limit": 100,
-    "x_gate_ratelimit_reset_timestamp": 1677816785084
-  },
-  "data": {
-    "errs": {
-      "label": "TOO_MANY_REQUESTS",
-      "message": "Request Rate limit Exceeded (311)"
-    }
-  }
-}
-Copy
-#登录
-注意:您使用的 GateAPIv4 密钥对必须具有合约账户对应的权限(例如:order-place 频道必须具有合约账户写入权限), 如果启用了密钥的白名单,则您的出站 IP 地址必须在密钥的 IP 白名单中.
-
-#登录请求
-客户端 API 请求
-
-payload参数:
-
-名称	类型	必选	描述
-req_id	string	是	请求 id,将由服务器发回,以帮助您识别服务器响应哪个请求,
-它与外部的id不同
-api_key	string	是	Apiv4 key
-req_header	object	是	Apiv4 自定义 header
-signature	string	是	Apiv4 签名
-timestamp	string	是	Unix 时间戳(以秒为单位)
-WebSocket api 操作认证使用与 Gate APIv4 API 相同的签名计算方法,即 HexEncode(HMAC_SHA512(secret,signature_string)),但有以下区别:
-
-签名字符串拼接方式:<event>\n<channel>\n<req_param>\n<timestamp>, 其中<event>、<channel>、<req_param>、<timestamp>是对应的请求信息
-login频道中的 req_param始终为空字符串
-身份验证信息在请求正文中的payload字段中发送。
-代码示例
-
-import hmac
-import hashlib
-import json
-import time
-import websocket
-import ssl
-
-def get_api_signature(secret, channel, request_param, ts):
-    key = f"api\n{channel}\n{request_param}\n{ts}"
-    hash_object = hmac.new(secret.encode(), key.encode(), hashlib.sha512)
-    return hash_object.hexdigest()
-
-class ApiPayload:
-    def __init__(self, api_key, signature, timestamp, req_id, request_param):
-        self.api_key = api_key
-        self.signature = signature
-        self.timestamp = timestamp
-        self.req_id = req_id
-        self.request_param = request_param
-
-class ApiRequest:
-    def __init__(self, ts, channel, event, payload):
-        self.time = ts
-        self.channel = channel
-        self.event = event
-        self.payload = payload
-
-def main():
-    api_key = "YOUR_API_KEY"
-    secret = "YOUR_API_SECRET"
-    request_param = ""
-    channel = "futures.login"
-    ts = int(time.time())
-    request_id = f"{int(time.time() * 1000)}-1"
-
-    payload = ApiPayload(
-        api_key=api_key,
-        signature=get_api_signature(secret, channel, request_param, ts),
-        timestamp=str(ts),
-        req_id=request_id,
-        request_param=request_param
-    )
-
-    req = ApiRequest(ts=ts, channel=channel, event="api", payload=payload)
-
-    print(get_api_signature(secret, channel, request_param, ts))
-
-    req_json = json.dumps(req, default=lambda o: o.__dict__)
-    print(req_json)
-
-    # Connect to WebSocket
-    ws_url = "wss://fx-ws.gateio.ws/v4/ws/usdt"  # Replace with your WebSocket URL
-    websocket.enableTrace(False)
-    ws = websocket.create_connection(ws_url, sslopt={"cert_reqs": ssl.CERT_NONE})
-
-    # Function to receive messages
-    def recv_messages():
-        while True:
-            try:
-                message = ws.recv()
-                print(f"recv: {message}")
-            except Exception as e:
-                print(f"Error receiving message: {e}")
-                ws.close()
-                break
-
-    # Start receiving messages in a separate thread
-    import threading
-    receive_thread = threading.Thread(target=recv_messages)
-    receive_thread.start()
-
-    # Send the request
-    ws.send(req_json)
-
-    # Keep the main thread running
-    receive_thread.join()
-
-if __name__ == "__main__":
-    main()
-Copy
-请求示例
-
-{
-  "time": 1681984544,
-  "channel": "futures.login",
-  "event": "api",
-  "payload": {
-    "api_key": "ea83fad2604399da16bf97e6eea772a6",
-    "signature": "6fa3824c8141f2b2283108558ec50966d7caf749bf04a3b604652325b50b47d2343d569d848373d58e65c49d9622ba2e73dc25797abef11c9f20c07da741591e",
-    "timestamp": "1681984544",
-    "req_id": "request-1"
-  }
-}
-Copy
-#登录响应
-响应参数:
-
-名称	类型	描述
-request_id	String	对应的请求 ID
-header	Map	响应元信息
-»response_time	String	响应发送时间(毫秒)
-»channel	String	请求频道
-»event	String	请求event
-»client_id	String	唯一的客户端 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-data	Object	请求响应的数据
-»result	Object	如果这是 ack 响应,则结果是请求的payload,否则结果是 api 的响应
-»»api_key	String	登录成功的 apikey
-»»uid	String	登录成功的用户 ID
-»errs	Object	仅当请求失败时可用
-»»label	String	错误类型
-»»message	String	详细错误信息
-登录响应示例
-
-{
-  "request_id": "request-1",
-  "header": {
-    "response_time": "1681985856666",
-    "status": "200",
-    "channel": "futures.login",
-    "event": "api",
-    "clientId": "",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d"
-  },
-  "data": {
-    "result": {
-      "api_key": "ea83fad2604399da16bf97e6eea772a6",
-      "uid": "110284739"
-    }
-  }
-}
-Copy
-#下单
-futures.order_place
-
-您可以通过此频道进行下单操作.
-
-本频道和以下的 APIV4 功能相同:
-
-POST /futures/{
-  settle
-}/orders
-#下单请求
-payload参数:
-
-名称	类型	必选	描述
-req_id	string	是	请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param	object	是	使用 api 下单参数; api 下单参数详细信息api(opens new window)
-req_header	object	否	Apiv4 自定义请求头
-req_param API 订单模型的 JSON 字节数据:
-
-字段	类型	必选	描述
-contract	string	是	合约
-size	int64	是	订单大小。指定正数进行出价,指定负数进行询问
-iceberg	string	否	冰山订单的显示尺寸。0 表示非冰山。请注意,您需要支付隐藏尺寸的接受者费用
-price	string	否	订单价格。0 表示市价订单,tif设置为ioc
-close	bool	否	设置为true平仓,size设置为 0
-reduce_only	bool	否	设置为true仅减少订单
-tif	string	否	有效时间
-text	string	否	用户定义的信息。如果不为空,则必须遵循以下规则:
-auto_size	string	否	将侧面设置为关闭双模式位置。close_long闭合长边;而close_short短的。注意size还需要设置为 0
-stp_act	string	否	自我交易预防行动。用户可以通过该字段设置自助交易防范策略
-market_order_slip_ratio	string	否	该笔市价单的预设的最大滑点比率(不代表实际的滑点),0.03代表3%的最大滑点
-req_header 自定义 header 数据:
-
-字段	类型	必选	描述
-x-gate-exptime	string	否	指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-#详细描述
-tif: 有效时间
-
-gtc:取消前有效
-ioc: ImmediateOrCancelled, 仅接受者
-poc:PendingOrCancelled,仅发布订单,始终享受挂单费用
-fok:FillOrKill,完全填充或不填充
-text: 订单自定义信息,用户可以用该字段设置自定义 ID,用户自定义字段必须满足以下条件:
-
-必须以 t- 开头
-不计算 t- ,长度不能超过 28 字节
-输入内容只能包含数字、字母、下划线(_)、中划线(-) 或者点(.)
-不填,默认 apiv4-ws,来自 ws
-web:来自网络
-api:来自 API
-app:来自手机
-auto_deleveraging:来自 ADL
-liquidation:来自清算
-insurance:来自保险
-stp_act:自我交易预防行动。用户可以通过该字段设置自助交易防范策略 用户加入后STP Group,他可以通过stp_act限制用户的自我交易防范策略。如果stp_act不通过则默认为cn策略。 当用户没有加入时STP group,传递参数时会返回错误stp_act。 如果用户下单时没有使用stp_act,stp_act将返回-
-
-cn:取消最新订单,取消新订单并保留旧订单
-co:取消最旧的订单,取消旧订单并保留新订单
-cb:取消两者,新旧订单都会被取消
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-api_order = {
-      "contract": "BTC_USDT",
-      "size": 10,
-      "price": "31503.280000",
-      "tif": "gtc",
-      "text": "t-my-custom-id"
-    }
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send(json.dumps(
-    {"time": int(time.time()),
-    "channel": "futures.order_place",
-    "event": "api",
-    "payload": {
-        "req_id": "1ewq-3123w-5",
-        "req_param": api_order
-    }}
-))
-
-print(ws.recv())
-Copy
-请求示例
-
-{
-  "time": 1681195484,
-  "channel": "futures.order_place",
-  "event": "api",
-  "payload": {
-    "req_id": "request-id-1",
-    "req_param": {
-      "contract": "BTC_USDT",
-      "size": "10",
-      "price": "31503.280000",
-      "tif": "gtc",
-      "text": "t-my-custom-id"
-    }
-  }
-}
-Copy
-#订单请求回声消息
-订单确认回声通知示例
-
-{
-  "request_id": "request-id-1",
-  "ack": true,
-  "header": {
-    "response_time": "1681195484268",
-    "status": "200",
-    "channel": "futures.order_place",
-    "event": "api",
-    "client_id": "::1-0x140001a2600",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_requests_remain": 99,
-    "x_gate_ratelimit_limit": 100,
-    "x_gat_ratelimit_reset_timestamp": 1736408263764
-  },
-  "data": {
-    "result": {
-      "req_id": "request-id-1",
-      "req_header": null,
-      "req_param": {
-        "contract": "BTC_USDT",
-        "size": "10",
-        "price": "31503.280000",
-        "tif": "gtc",
-        "text": "t-my-custom-id"
-      }
-    }
-  }
-}
-Copy
-#下单结果通知
-下单时返回订单信息 响应参数:
-
-名称	类型	描述
-request_id	String	对应的请求 ID
-ack	Bool	"ack"消息的返回表示 WebSocket 的确认消息(目前在下单接口中存在)。
-如果ack为 false(false 该字段不会出现在响应中),则说明该消息是响应消息,可以判断请求是否成功<br / >通过检查data.errs。
-header	Map	响应元信息
-»response_time	String	响应发送时间(毫秒)
-»channel	String	请求频道
-»event	String	请求event
-»client_id	String	唯一的客户端 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain	Integer	当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit	Integer	当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp	Integer	已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-data	Object	请求响应的数据
-»result	Object	如果这是 ack 响应,则结果是请求的payload,否则结果是 api 的响应
-»errs	Object	仅当请求失败时可用
-»»label	String	错误类型
-»»message	String	详细错误信息
-响应返回示例
-
-{
-  "request_id": "request-id-1",
-  "ack": false,
-  "header": {
-    "response_time": "1681195484360",
-    "status": "200",
-    "channel": "futures.order_place",
-    "event": "api",
-    "client_id": "::1-0x140001a2600",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_requests_remain": 99,
-    "x_gate_ratelimit_limit": 100,
-    "x_gat_ratelimit_reset_timestamp": 1736408263764
-  },
-  "data": {
-    "result": {
-      "id": 74046514,
-      "user": 6790020,
-      "create_time": 1681195484.462,
-      "finish_time": 1681195484.462,
-      "finish_as": "filled",
-      "status": "finished",
-      "contract": "BTC_USDT",
-      "size": "10",
-      "price": "31503.3",
-      "tif": "gtc",
-      "fill_price": "31500",
-      "text": "t-my-custom-id",
-      "tkfr": "0.0003",
-      "mkfr": "0",
-      "stp_id": 2,
-      "stp_act": "cn",
-      "amend_text": "-"
-    }
-  }
-}
-Copy
-#批量下单
-futures.order_batch_place
-
-您可以通过该频道批量下单
-
-本频道和以下的 APIV4 功能相同:
-
-POST /futures/{
-  settle
-}/batch_orders
-#批量下单请求
-payload 参数:
-
-名称	类型	必选	描述
-req_id	string	是	请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param	object	是	参考 api 批量下单的请求数组; api 批量下单详情api(opens new window)
-req_header	object	否	Apiv4 自定义 header
-req_param API 订单模型的 JSON 字节数据可以参考单个下单,是多个单个下单数组,详情参考下单
-
-req_header 自定义 header 数据:
-
-字段	类型	必选	描述
-x-gate-exptime	string	否	指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-api_order=[
-      {
-        "contract": "BTC_USDT",
-        "size": 10,
-        "price": "31403.180000",
-        "tif": "gtc",
-        "text": "t-my-custom-id"
-      }
-    ]
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-ws.send(json.dumps({
-    "time": int(time.time()),
-    "channel": "futures.order_batch_place",
-    "event": "api",
-    "payload": {
-        "header":{
-            "x-gate-channel-id":"xxxx",
-        },
-        "req_id": "1ewq-3123w-5",
-        "req_param": api_order
-    }
-}))
-
-print(ws.recv())
-Copy
-请求示例
-
-{
-  "time": 1681196536,
-  "channel": "futures.order_batch_place",
-  "event": "api",
-  "payload": {
-    "req_id": "request-id-6",
-    "req_param": [
-      {
-        "contract": "BTC_USDT",
-        "size": "10",
-        "price": "31403.180000",
-        "tif": "gtc",
-        "text": "t-my-custom-id"
-      }
-    ]
-  }
-}
-Copy
-#批量下单确认通知
-确认通知示例
-
-{
-  "request_id": "request-id-6",
-  "ack": true,
-  "header": {
-    "response_time": "1681196536283",
-    "status": "200",
-    "channel": "futures.order_batch_place",
-    "event": "api",
-    "client_id": "::1-0x14002cfa0c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_requests_remain": 99,
-    "x_gate_ratelimit_limit": 100,
-    "x_gat_ratelimit_reset_timestamp": 1736408263764
-  },
-  "data": {
-    "result": {
-      "req_id": "request-id-6",
-      "req_header": null,
-      "req_param": [
-        {
-          "contract": "BTC_USDT",
-          "size": "10",
-          "price": "31403.180000",
-          "tif": "gtc",
-          "text": "t-my-custom-id"
-        }
-      ]
-    }
-  }
-}
-Copy
-#批量下单结果通知
-批量下单订单信息返回
-
-响应参数:
-
-名称	类型	描述
-request_id	String	对应的请求 ID
-ack	Bool	"ack"消息的返回表示 WebSocket 的确认消息(目前在下单接口中存在)。
-如果ack为 false(false 该字段不会出现在响应中),则说明该消息是响应消息,可以判断请求是否成功<br / >通过检查data.errs。
-header	Map	响应元信息
-»response_time	String	响应发送时间(毫秒)
-»channel	String	请求频道
-»event	String	请求event
-»client_id	String	唯一的客户端 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain	Integer	当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit	Integer	当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp	Integer	已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-data	Object	请求响应的数据
-»result	Object	如果这是 ack 响应,则结果是请求的payload,否则结果是 api 的响应
-»errs	Object	仅当请求失败时可用
-»»label	String	错误类型
-»»message	String	详细错误信息
-响应返回示例
-
-{
-  "request_id": "request-id-6",
-  "ack": false,
-  "header": {
-    "response_time": "1681196536532",
-    "status": "200",
-    "channel": "futures.order_batch_place",
-    "event": "api",
-    "client_id": "::1-0x14002cfa0c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_requests_remain": 99,
-    "x_gate_ratelimit_limit": 100,
-    "x_gat_ratelimit_reset_timestamp": 1736408263764
-  },
-  "data": {
-    "result": [
-      {
-        "succeeded": true,
-        "id": 74046545,
-        "user": 6790020,
-        "create_time": 1681196536.592,
-        "status": "open",
-        "contract": "BTC_USDT",
-        "size": "10",
-        "price": "31403.2",
-        "tif": "gtc",
-        "left": "10",
-        "fill_price": "0",
-        "text": "t-my-custom-id",
-        "tkfr": "0.0003",
-        "mkfr": "0"
-      }
-    ]
-  }
-}
-Copy
-#订单取消
-futures.order_cancel
-
-您可以通过此频道取消订单
-
-本频道和以下的 APIV4 功能相同:
-
-DELETE /futures/{
-  settle
-}/orders/{
-  order_id
-}
-#订单取消请求
-payload 参数:
-
-名称	类型	必选	描述
-req_id	string	是	请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param	object	是	API 取消订单,详情至api(opens new window)
-req_header	object	否	Apiv4 自定义请求头
-req_param API 订单模型的 JSON 字节数据:
-
-字段	类型	必选	描述
-order_id	string	是	成功创建订单时返回的订单 ID 或者用户创建时指定的自定义 ID(即text 字段)。
-req_header 自定义 header 数据:
-
-字段	类型	必选	描述
-x-gate-exptime	string	否	指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-api_cancel_order = {
-      "order_id": "74046514"
-    }
-ws.send(json.dumps({
-    "time": int(time.time()),
-    "channel": "futures.order_cancel",
-    "event": "api",
-    "payload": {
-        "req_id": "1ewq-3123w-5",
-        "req_param": api_cancel_order
-    }
-}))
-
-print(ws.recv())
-Copy
-订单取消请求示例
-
-{
-  "time": 1681195485,
-  "channel": "futures.order_cancel",
-  "event": "api",
-  "payload": {
-    "req_id": "request-id-5",
-    "req_param": {
-      "order_id": "74046514"
-    }
-  }
-}
-Copy
-#订单取消通知
-响应参数:
-
-名称	类型	描述
-request_id	String	对应的请求 ID
-header	Map	响应元信息
-»response_time	String	响应发送时间(毫秒)
-»channel	String	请求频道
-»event	String	请求event
-»client_id	String	唯一的客户端 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain	Integer	当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit	Integer	当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp	Integer	已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-data	Object	请求响应的数据
-»result	Object	订单取消参数,详情至api(opens new window)
-»errs	Object	仅当请求失败时可用
-»»label	String	错误类型
-»»message	String	详细错误信息
-订单取消返回示例
-
-{
-  "request_id": "request-id-5",
-  "header": {
-    "response_time": "1681196536282",
-    "status": "200",
-    "channel": "futures.order_cancel",
-    "event": "api",
-    "client_id": "::1-0x14002cfa0c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_requests_remain": 99,
-    "x_gate_ratelimit_limit": 100,
-    "x_gat_ratelimit_reset_timestamp": 1736408263764
-  },
-  "data": {
-    "result": {
-      "id": 74046543,
-      "user": 6790020,
-      "create_time": 1681196535.01,
-      "finish_time": 1681196536.343,
-      "finish_as": "cancelled",
-      "status": "finished",
-      "contract": "BTC_USDT",
-      "size": "10",
-      "price": "31303.2",
-      "tif": "gtc",
-      "left": "10",
-      "fill_price": "0",
-      "text": "t-my-custom-id",
-      "tkfr": "0.0003",
-      "mkfr": "0",
-      "stp_id": 2,
-      "stp_act": "cn",
-      "amend_text": "-"
-    }
-  }
-}
-Copy
-#取消所有 ID 列表内的订单
-您可以使用此频道futures.order_cancel_ids取消所有 ID 列表内的订单。
-
-可以指定多个不同的订单id。一次请求最多只能撤销 20 条记录
-
-以下是 API 的功能:
-
-POST /futures/{settle}/batch_cancel_orders
-#取消所有 ID 列表内的订单请求
-Payload 格式:
-
-字段	类型	必选	描述
-req_id	string	是	服务器将发送回的请求 ID,用于帮助您识别服务器响应的是哪个请求,它与外部的 id 不同。
-req_param	array	是	订单 ID 列表
-req_header	object	否	apiv4 自定义 header
-req_header 自定义 header 数据:
-
-字段	类型	必选	描述
-x-gate-exptime	string	否	指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-代码示例:请求前要先登录
-
-#!/usr/bin/python
-
-import time
-import json
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-cancelWithIdsParam = ["1694883366","123"]
-ws.send(json.dumps({
-    "time":int(time.time()),
-    "channel":"futures.order_cancel_ids",
-    "event":"api",
-    "payload":{
-        "req_id":"test_1",
-        "req_param": cancelWithIdsParam
-    }
-}))
-
-print(ws.recv())
-Copy
-客户端请求示例
-
-{
-  "time": 1681986208,
-  "channel": "futures.order_cancel_ids",
-  "event": "api",
-  "payload": {
-    "req_id": "request-9",
-    "req_param": [
-      "1700664343",
-      "123"
-    ]
-  }
-}
-Copy
-#取消所有 ID 列表内的订单推送
-推送格式:
-
-字段	类型	描述
-request_id	String	消息的唯一标识符
-header	Map	响应的元信息
-»response_time	String	响应发送时间(以毫秒为单位)
-»channel	String	请求的频道
-»event	String	请求事件
-»client_id	String	唯一客户端标识 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-data	Object	请求响应的数据
-»result	Object	响应详见api(opens new window)
-»errs	Object	只有在请求失败时才可用
-»»label	String	以字符串格式表示错误类型
-»»message	String	错误信息详情
-取消订单推送示例
-
-{
-  "request_id": "request-9",
-  "header": {
-    "response_time": "1681986208564",
-    "status": "200",
-    "channel": "futures.order_cancel_ids",
-    "event": "api",
-    "client_id": "::1-0x140001623c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d"
-  },
-  "data": {
-    "result": [
-      {
-        "id": "1694883366",
-        "user_id": 111,
-        "succeeded": true
-      },
-      {
-        "id": "123",
-        "user_id": 111,
-        "message": "ORDER_NOT_FOUND"
-      }
-    ]
-  }
-}
-Copy
-#取消匹配的未结束订单
-futures.order_cancel_cp
-
-您可以通过此渠道取消所有匹配的未结束的订单
-
-本频道和以下的 APIV4 功能相同:
-
-DELETE /futures/{
-  settle
-}/orders
-#请求
-payload 参数:
-
-名称	类型	必选	描述
-req_id	string	是	请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param	object	是	详情至api(opens new window)
-req_header	object	否	Apiv4 自定义请求头
-req_param API 订单模型的 JSON 字节数据:
-
-字段	类型	必选	描述
-contract	string	是	合约
-side	string	否	所有出价或要价。如果没有特别说明,两者都包括在内。
-req_header 自定义 header 数据:
-
-字段	类型	必选	描述
-x-gate-exptime	string	否	指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-api_cancel_all_order = {
-      "contract": "BTC_USDT",
-      "side": "bid"
-    }
-ws.send(json.dumps({
-    "time": int(time.time()),
-    "channel": "futures.order_cancel_cp",
-    "event": "api",
-    "payload": {
-        "req_id": "1ewq-3123w-5",
-        "req_param": api_cancel_all_order
-    }
-}))
-
-print(ws.recv())
-Copy
-客户请求示例
-
-{
-  "time": 1681196537,
-  "channel": "futures.order_cancel_cp",
-  "event": "api",
-  "payload": {
-    "req_id": "request-id-7",
-    "req_param": {
-      "contract": "BTC_USDT",
-      "side": "bid"
-    }
-  }
-}
-Copy
-#响应结果
-响应参数:
-
-名称	类型	描述
-request_id	String	对应的请求 ID
-header	Map	响应元信息
-»response_time	String	响应发送时间(毫秒)
-»channel	String	请求频道
-»event	String	请求event
-»client_id	String	唯一的客户端 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain	Integer	当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit	Integer	当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp	Integer	已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-data	Object	请求响应的数据
-»result	Object	详情至api(opens new window)
-»errs	Object	仅当请求失败时可用
-»»label	String	错误类型
-»»message	String	详细错误信息
-订单取消返回示例
-
-{
-  "request_id": "request-id-7",
-  "header": {
-    "response_time": "1681196537567",
-    "status": "200",
-    "channel": "futures.order_cancel_cp",
-    "event": "api",
-    "client_id": "::1-0x14002cfa0c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_requests_remain": 99,
-    "x_gate_ratelimit_limit": 100,
-    "x_gat_ratelimit_reset_timestamp": 1736408263764
-  },
-  "data": {
-    "result": [
-      {
-        "id": 74046545,
-        "user": 6790020,
-        "create_time": 1681196536.592,
-        "finish_time": 1681196537.626,
-        "finish_as": "cancelled",
-        "status": "finished",
-        "contract": "BTC_USDT",
-        "size": "10",
-        "price": "31403.2",
-        "tif": "gtc",
-        "left": "10",
-        "fill_price": "0",
-        "text": "t-my-custom-id",
-        "tkfr": "0.0003",
-        "mkfr": "0",
-        "stp_id": 2,
-        "stp_act": "cn",
-        "amend_text": "-"
-      }
-    ]
-  }
-}
-Copy
-#修改订单
-futures.order_amend
-
-您可以通过此频道修改未结束的订单
-
-本频道和以下的 APIV4 功能相同:
-
-PUT /futures/{settle}/orders/{order_id}
-#请求
-payload 参数:
-
-名称	类型	必选	描述
-req_id	string	是	请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param	object	是	API 修改订单参数,详情至api(opens new window)
-req_header	object	否	Apiv4 自定义请求头
-req_param API 订单模型的 JSON 字节数据:
-
-字段	类型	必选	描述
-order_id	string	是	成功创建订单时返回的订单 ID 或者用户创建时指定的自定义 ID(即text 字段)。
-size	int64	否	必选。交易数量,正数为买入,负数为卖出。平仓委托则设置为 0。
-price	string	否	价格
-amend_text	int64	否	修改订单时的自定义信息
-req_header 自定义 header 数据:
-
-字段	类型	必选	描述
-x-gate-exptime	string	否	指定过期的时间戳(毫秒)。如果 ws 收到请求的时间大于过期时间,请求将被拒绝
-#详细描述
-=> size: 新订单尺寸,包括已填充部分。
-
-如果新尺寸小于或等于已填充尺寸,订单将被取消。
-订单面必须与原始面相同。
-平仓订单大小无法更改。
-对于仅减少订单,增加尺寸可能会导致其他仅减少订单被取消。
-如果价格不变,减少数量不会改变其在订单簿中的优先级,而增加数量则会以当前价格将其移至最后。
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-api_amend_order = {
-      "order_id": "74046543",
-      "price": "31303.180000"
-    }
-ws.send(json.dumps({
-    "time": int(time.time()),
-    "channel": "futures.order_amend",
-    "event": "api",
-    "payload": {
-        "req_id": "1ewq-3123w-5",
-        "req_param": api_amend_order
-    }
-}))
-
-print(ws.recv())
-Copy
-客户请求示例
-
-{
-  "time": 1681196536,
-  "channel": "futures.order_amend",
-  "event": "api",
-  "payload": {
-    "req_id": "request-id-4",
-    "req_param": {
-      "order_id": "74046543",
-      "price": "31303.180000"
-    }
-  }
-}
-Copy
-#响应结果
-响应参数:
-
-名称	类型	描述
-request_id	String	对应的请求 ID
-header	Map	响应元信息
-»response_time	String	响应发送时间(毫秒)
-»channel	String	请求频道
-»event	String	请求event
-»client_id	String	唯一的客户端 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-»x_gate_ratelimit_requests_remain	Integer	当前时间窗口剩余可用请求数(为0不展示)
-»x_gate_ratelimit_limit	Integer	当前频率限制上限(为0不展示)
-»x_gat_ratelimit_reset_timestamp	Integer	已超过当前窗口频率限制,表示下个可用时间窗口的时间戳(毫秒),即什么时候可以恢复访问;未超过当前窗口频率限制,表示返回的是当前服务器时间(毫秒)
-data	Object	请求响应的数据
-»result	Object	详情至api(opens new window)
-»errs	Object	仅当请求失败时可用
-»»label	String	错误类型
-»»message	String	详细错误信息
-订单修改返回示例
-
-{
-  "request_id": "request-id-4",
-  "header": {
-    "response_time": "1681196536251",
-    "status": "200",
-    "channel": "futures.order_amend",
-    "event": "api",
-    "client_id": "::1-0x14002cfa0c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d",
-    "x_gate_ratelimit_requests_remain": 99,
-    "x_gate_ratelimit_limit": 100,
-    "x_gat_ratelimit_reset_timestamp": 1736408263764
-  },
-  "data": {
-    "result": {
-      "id": 74046543,
-      "user": 6790020,
-      "create_time": 1681196535.01,
-      "status": "open",
-      "contract": "BTC_USDT",
-      "size": "10",
-      "price": "31303.2",
-      "tif": "gtc",
-      "left": "10",
-      "fill_price": "0",
-      "text": "t-my-custom-id",
-      "tkfr": "0.0003",
-      "mkfr": "0",
-      "stp_id": 2,
-      "stp_act": "cn",
-      "amend_text": "-"
-    }
-  }
-}
-Copy
-#获取订单列表
-futures.order_list
-
-您可以通过此频道获取订单列表
-
-本频道和以下的 APIV4 功能相同:
-
-GET /futures/{settle}/orders
-#订单列表请求
-payload 参数:
-
-名称	类型	必选	描述
-req_id	string	是	请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param	object	是	API 请求订单列表参数,详情至api(opens new window)
-req_param API 订单模型的 JSON 字节数据:
-
-字段	类型	必选	描述
-contract	string	否	合约标识,如果指定则只返回该合约相关数据
-status	string	是	只列出具有此状态的订单
-limit	int	否	单个列表中返回的最大记录数
-offset	int	否	列表偏移量,从 0 开始
-last_id	string	否	使用先前列表查询结果中最后一条记录的id 指定列表起始点
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-api_list_order = {
-      "contract": "BTC_USDT",
-      "status": "open"
-    }
-ws.send(json.dumps({
-    "time": int(time.time()),
-    "channel": "futures.order_list",
-    "event": "api",
-    "payload": {
-        "req_id": "1ewq-3123w-5",
-        "req_param": api_list_order
-    }
-}
-))
-
-print(ws.recv())
-Copy
-客户请求示例
-
-{
-  "time": 1681196535,
-  "channel": "futures.order_list",
-  "event": "api",
-  "payload": {
-    "req_id": "request-id-3",
-    "req_param": {
-      "contract": "BTC_USDT",
-      "status": "open"
-    }
-  }
-}
-Copy
-#订单列表响应
-响应参数:
-
-名称	类型	描述
-request_id	String	对应的请求 ID
-header	Map	响应元信息
-»response_time	String	响应发送时间(毫秒)
-»channel	String	请求频道
-»event	String	请求event
-»client_id	String	唯一的客户端 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-data	Object	请求响应的数据
-»result	Object	详情至api(opens new window)
-»errs	Object	仅当请求失败时可用
-»»label	String	错误类型
-»»message	String	详细错误信息
-订单列表返回示例
-
-{
-  "request_id": "request-id-3",
-  "header": {
-    "response_time": "1681196536017",
-    "status": "200",
-    "channel": "futures.order_list",
-    "event": "api",
-    "client_id": "::1-0x14002cfa0c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d"
-  },
-  "data": {
-    "result": [
-      {
-        "id": 74046543,
-        "user": 6790020,
-        "create_time": 1681196535.01,
-        "finish_time": 1681196535.01,
-        "update_time": 1681196535.01,
-        "finish_as": "filled",
-        "status": "open",
-        "contract": "BTC_USDT",
-        "size": "10",
-        "price": "31403.2",
-        "tif": "gtc",
-        "left": "10",
-        "fill_price": "0",
-        "text": "t-my-custom-id",
-        "tkfr": "0.0003",
-        "mkfr": "0",
-        "stp_id": 2,
-        "stp_act": "cn",
-        "amend_text": "-"
-      }
-    ]
-  }
-}
-Copy
-#查询订单详情
-futures.order_status
-
-您可以通过该频道查询订单详情
-
-本频道和以下的 APIV4 功能相同:
-
-GET /futures/{settle}/orders/{order_id}
-#订单详情请求
-payload 参数:
-
-名称	类型	必选	描述
-req_id	string	是	请求 id,服务器会发回,帮助你识别服务器响应的是哪个请求,
-它与外部的id不同
-req_param	object	是	详情至api(opens new window)
-req_param` API 订单模型的 JSON 字节数据:
-
-字段	类型	必选	描述
-order_id	string	是	成功创建订单时返回的订单 ID 或者用户创建时指定的自定义 ID(即text 字段)。
-代码示例:请求前要先登录
-
-import time
-import json
-
-# pip install websocket_client
-from websocket import create_connection
-
-ws = create_connection("wss://fx-ws.gateio.ws/v4/ws/usdt")
-
-api_status_order = {
-      "order_id": "74046543"
-    }
-
-ws.send(json.dumps({
-    "time": int(time.time()),
-    "channel": "futures.order_status",
-    "event": "api",
-    "payload": {
-        "req_id": "1ewq-3123w-5",
-        "req_param": api_status_order
-    }
-}))
-
-print(ws.recv())
-Copy
-客户请求示例
-
-{
-  "time": 1681196535,
-  "channel": "futures.order_status",
-  "event": "api",
-  "payload": {
-    "req_id": "request-id-2",
-    "req_param": {
-      "order_id": "74046543"
-    }
-  }
-}
-Copy
-#订单详情响应
-响应参数:
-
-名称	类型	描述
-request_id	String	对应的请求 ID
-header	Map	响应元信息
-»response_time	String	响应发送时间(毫秒)
-»channel	String	请求频道
-»event	String	请求event
-»client_id	String	唯一的客户端 ID
-»x_in_time	Integer	ws 接收请求的时间(以微秒为单位)
-»x_out_time	Integer	ws 返回响应的时间(以微秒为单位)
-»conn_id	String	与客户端建立连接的链接Id(同一个连接的链接Id保持一致)
-»conn_trace_id	String	与客户端建立连接的TraceId
-»trace_id	String	执行下单操作的TraceId
-data	Object	请求响应的数据
-»result	Object	详情至api(opens new window)
-»errs	Object	仅当请求失败时可用
-»»label	String	错误类型
-»»message	String	详细错误信息
-订单详情返回示例
-
-{
-  "request_id": "request-id-2",
-  "header": {
-    "response_time": "1681196535985",
-    "status": "200",
-    "channel": "futures.order_status",
-    "event": "api",
-    "client_id": "::1-0x14002cfa0c0",
-    "x_in_time": 1681985856667508,
-    "x_out_time": 1681985856667598,
-    "conn_id": "5e74253e9c793974",
-    "conn_trace_id": "1bde5aaa0acf2f5f48edfd4392e1fa68",
-    "trace_id": "e410abb5f74b4afc519e67920548838d"
-  },
-  "data": {
-    "result": {
-      "id": 74046543,
-      "user": 6790020,
-      "create_time": 1681196535.01,
-      "status": "open",
-      "contract": "BTC_USDT",
-      "size": "10",
-      "price": "31403.2",
-      "tif": "gtc",
-      "left": "10",
-      "fill_price": "0",
-      "text": "t-my-custom-id",
-      "tkfr": "0.0003",
-      "mkfr": "0",
-      "stp_id": 2,
-      "stp_act": "cn",
-      "amend_text": "-"
-    }
-  }
-}
\ No newline at end of file
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
deleted file mode 100644
index 744c890..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
+++ /dev/null
@@ -1,519 +0,0 @@
-# Gate Api 模块 — 网格交易系统
-
-## 文件列表
-
-| 文件 | 类型 | 说明 |
-|------|------|------|
-| [GateWebSocketClientManager](#gatewebsocketclientmanager) | `@Component` | Spring 启动入口,组装组件 + 生命周期 |
-| [GateConfig](#gateconfig) | 配置 | Builder 模式:API 密钥、合约、策略参数、环境切换 |
-| [GateKlineWebSocketClient](#gateklinewebsocketclient) | WS 连接管理 | 连接/心跳/重连/消息路由 |
-| [GateGridTradeService](#gategridtradeservice) | 交易服务 | 网格队列策略 + 保证金安全阀 + 盈亏管理 + 额外反向开仓 |
-| [GateTradeExecutor](#gatetradeexecutor) | 异步执行器 | 独立线程池执行 REST 下单,成功/失败双回调 |
-| [GateWebSocketClientMain](#gatewebsocketclientmain) | main 入口 | 独立测试启动 |
-| [Example.java](#examplejava) | 示例 | Gate SDK 用法参考 |
-
-### wsHandler 子包
-
-| 文件 | 类型 | 说明 |
-|------|------|------|
-| `wsHandler/GateChannelHandler.java` | **接口** | subscribe / unsubscribe / handleMessage / getChannelName |
-| `wsHandler/AbstractPrivateChannelHandler.java` | **抽象类** | 私有频道基类:HMAC-SHA512 签名 + 认证请求 |
-| `wsHandler/handler/CandlestickChannelHandler.java` | 公开频道 | K 线解析 → `onKline()` |
-| `wsHandler/handler/PositionsChannelHandler.java` | 私有频道 | 仓位推送 → `onPositionUpdate()`(传 `Position.ModeEnum`),日志输出全部20个推送字段 |
-| `wsHandler/handler/PositionClosesChannelHandler.java` | 私有频道 | 平仓推送 → `onPositionClose()` |
-
----
-
-## 架构总览
-
-```
-┌──────────────────────────────────────────────────────────────────┐
-│                    GateWebSocketClientManager                    │
-│                      (Spring @Component)                         │
-│                                                                  │
-│  GateConfig.builder()  →  GateGridTradeService  +  WS Client     │
-│     │                         │                      │           │
-│     │ REST BasePath           │ GateTradeExecutor    │ WS URL    │
-│     ▼                         ▼                      ▼           │
-│  Gate API (REST)        独立线程池 (async)     Gate WebSocket     │
-│                      onSuccess/onFailure双回调  ┌──────────────┐  │
-│                                               │Candlestick H  │  │
-│                                               │Positions H    │  │
-│                                               │PosCloses H    │  │
-│                                               └──────────────┘  │
-└──────────────────────────────────────────────────────────────────┘
-```
-
----
-
-## 数据流
-
-```
-WebSocket → GateKlineWebSocketClient.handleMessage → 路由 dispatch
-│
-├─ futures.pong → cancelPongTimeout
-├─ subscribe / unsubscribe / error → log
-│
-├─ futures.candlesticks (公开)
-│   └─ CandlestickChannelHandler
-│       └─ gridTradeService.onKline(closePx)
-│           ├─ 更新 unrealizedPnl(浮动盈亏)
-│           ├─ state=WAITING_KLINE → 异步双开基底仓位
-│           └─ state=ACTIVE → processShortGrid/processLongGrid 网格触发
-│
-├─ futures.positions (私有, HMAC-SHA512)
-│   └─ PositionsChannelHandler
-│       ├─ 解析 mode → Position.ModeEnum(DUAL_LONG / DUAL_SHORT)
-│       ├─ 日志输出全部 20 个推送字段(contract/mode/size/entry_price/.../update_id)
-│       └─ gridTradeService.onPositionUpdate(contract, mode, size, entryPrice)
-│           ├─ 有仓位: 标记活跃,首次成交记录入场价并设止盈
-│           │   ├─ 基底开仓 → 首次成交 → 记录基底入场价 → 双基底都成交后生成网格队列
-│           │   └─ 网格开仓 → 成交后立即设止盈单(plan-close-*-position)
-│           └─ 无仓位(size=0): 标记不活跃
-│
-├─ futures.position_closes (私有, HMAC-SHA512)
-│   └─ PositionClosesChannelHandler
-│       └─ gridTradeService.onPositionClose(contract, side, pnl)
-│           └─ cumulativePnl += pnl → checkStopConditions()
-│
-└─ 所有下单操作
-    └─ GateTradeExecutor (单线程 + 64队列 + CallerRunsPolicy)
-        ├─ openLong/Short(qty, onSuccess, onFailure)
-        └─ placeTakeProfit → 条件单(plan-close-*-position, REST)
-```
-
-### PositionsChannelHandler 完整推送字段(20个)
-
-| 字段 | 类型 | 描述 |
-|------|------|------|
-| contract | String | 合约名称 |
-| mode | String | 持仓模式:dual_long / dual_short |
-| size | String/Integer | 合约张数(正=多头,负=空头) |
-| entry_price | Float | 开仓均价 |
-| cross_leverage_limit | Float | 全仓模式下的杠杆倍数上限 |
-| history_pnl | Float | 已平仓的仓位总盈亏 |
-| history_point | Float | 已平仓的点卡总盈亏 |
-| last_close_pnl | Float | 最近一次平仓的盈亏 |
-| leverage | Integer | 杠杆倍数(0=全仓,正数=逐仓) |
-| leverage_max | Integer | 当前风险限额下允许的最大杠杆倍数 |
-| liq_price | Float | 爆仓价格 |
-| maintenance_rate | Float | 当前风险限额下维持保证金比例 |
-| margin | Float | 保证金 |
-| realised_pnl | Float | 已实现盈亏 |
-| realised_point | Float | 点卡已实现盈亏 |
-| risk_limit | Integer | 风险限额 |
-| time | Integer | 更新 unix 时间戳(秒) |
-| time_ms | Integer | 更新 unix 时间戳(毫秒) |
-| user | String | 用户 ID |
-| update_id | Integer | 消息序列号,每次推送 order 后自增1 |
-
-> 以上 20 个字段在 PositionsChannelHandler.handleMessage() 中通过 SLF4J 日志全部输出。
-> 回调给 GateGridTradeService.onPositionUpdate() 的仅有 mode、size、entryPrice 三个核心字段。
-
----
-
-## GateChannelHandler 接口体系
-
-```
-GateChannelHandler (接口)
-  ├── CandlestickChannelHandler          (公开频道)
-  └── AbstractPrivateChannelHandler      (私有频道基类: HMAC-SHA512)
-        ├── PositionsChannelHandler       (解析 mode → Position.ModeEnum,日志输出20个字段)
-        └── PositionClosesChannelHandler
-```
-
-- **subscribe**: 发送订阅请求。私有Handler自动附加 auth 字段
-- **unsubscribe**: 发送取消订阅请求(私有频道也带签名认证)
-- **handleMessage**: 解析推送数据并回调GateGridTradeService,返回true表示已处理
-- 消息路由: update/all事件 → 遍历channelHandlers → handler内部二次匹配channel名 → 匹配成功回调并停止遍历
-- **PositionsChannelHandler 特殊处理**: 推送的 mode 字符串("dual_long")通过 `Position.ModeEnum.fromValue()` 转为枚举
-
----
-
-## 策略状态机
-
-```
-WAITING_KLINE ──onKline──→ OPENING ──双基底都成交──→ ACTIVE
-     │                        │                         │
-     │                    下单异常               ├─ 每根K线: 更新 unrealizedPnl
-     │                        │                 ├─ cumPnl ≥ overallTp → STOPPED
-     │                        │                 ├─ cumPnl ≤ -maxLoss → STOPPED
-     │                        │                 ├─ 保证金超限 → 跳过开仓,队列照常更新
-     │                        │                 ├─ 网格触发 → 开仓+设止盈+队列转移(以对方队列首元素为种子)
-     │                        │                 ├─ 多>空且价格夹在中间 → 额外反向开仓
-     │                        │                 └─ 转移元素贴近持仓均价 → 跳过(过滤)
-     ▼                        ▼
-   STOPPED  ←──────────────────┘
-```
-
-| 状态 | 含义 |
-|------|------|
-| `WAITING_KLINE` | 等待首次K线价格 |
-| `OPENING` | 正在异步开基底多空仓位(已提交到GateTradeExecutor) |
-| `ACTIVE` | 网格队列激活,K线触发网格元素 → 开仓+止盈 |
-| `STOPPED` | 停止(盈利达标 / 亏损超限) |
-
----
-
-## 策略核心:网格队列机制
-
-### 概述
-
-策略采用"基底 + 价格网格队列"模式:先开一对基底多空仓位,然后以基底入场价为基准生成价格队列。每当K线穿破队列元素,就开新仓位并设止盈条件单,同时以对方队列首元素为种子生成新元素加入对方队列。
-
-### 基底开仓
-
-```
-K线到达 → 双开基底(市价开多 + 市价开空)
-  → 成交回调: baseLongOpened=true, longActive=true
-  → 成交回调: baseShortOpened=true, shortActive=true
-  → 两者都成交 → generateShortQueue() + generateLongQueue() → state=ACTIVE
-```
-
-### 网格队列生成
-
-以基底入场价为基准,按 `gridRate`(百分比步长)生成 N 个价格(N = gridQueueSize,默认50):
-
-| 队列 | 计算方式 | 排序 |
-|------|---------|------|
-| 空仓队列 shortPriceQueue | 基底空入场价 × (1 − gridRate × i) (i=1..N) | 降序(大→小) |
-| 多仓队列 longPriceQueue | 基底多入场价 × (1 + gridRate × i) (i=1..N) | 升序(小→大) |
-
-### K线触发网格
-
-```
-K线到达(ACTIVE状态):
-│
-├─ processShortGrid: 当前价 < 空仓队列元素(价格跌破了队列中的高价)
-│   ├─ 匹配: 收集所有 > 当前价的空仓队列元素(降序,一旦遇≤即停止)
-│   ├─ 空仓队列: 移除 matched,尾部补充新元素(尾价 × (1−gridRate) 循环递减)
-│   ├─ 多仓队列转移:
-│   │   ├─ 以多仓队列首元素(最小价)为种子
-│   │   ├─ 生成 matched.size() 个递减元素: seed × (1 − gridRate × i)
-│   │   ├─ 贴近过滤: |currentPrice − longEntryPrice| < longEntryPrice × gridRate → 跳过
-│   │   └─ 升序排列,截断到 gridQueueSize
-│   └─ 下单(队列已更新,避免竞态):
-│       ├─ 保证金检查: positionInitialMargin / initialPrincipal < marginRatioLimit(20%)
-│       │   ├─ 安全 → openShort 开空单
-│       │   │   └─ 额外条件: 多>空 且 空仓均价 < 当前价 < 多仓均价×(1−gridRate) → openLong 额外开多一次
-│       │   └─ 超限 → 跳过开仓
-│
-└─ processLongGrid: 当前价 > 多仓队列元素(价格涨超了队列中的低价)
-    ├─ 匹配: 收集所有 < 当前价的多仓队列元素(升序,一旦遇≥即停止)
-    ├─ 多仓队列: 移除 matched,尾部补充新元素(尾价 × (1+gridRate) 循环递增)
-    ├─ 空仓队列转移:
-    │   ├─ 以空仓队列首元素(最高价)为种子
-    │   ├─ 生成 matched.size() 个递增元素: seed × (1 + gridRate × i)
-    │   ├─ 贴近过滤: |currentPrice − shortEntryPrice| < shortEntryPrice × gridRate → 跳过
-    │   └─ 降序排列,截断到 gridQueueSize
-    └─ 下单(队列已更新,避免竞态):
-        ├─ 保证金检查: 同上
-        │   ├─ 安全 → openLong 开多单
-        │   │   └─ 额外条件: 多>空 且 空仓均价×(1+gridRate) < 当前价 < 多仓均价 → openShort 额外开空一次
-        │   └─ 超限 → 跳过开仓
-```
-
-### 队列转移规则(新)
-
-触发后**不再简单复制** matched 元素到对方队列,而是以对方队列首元素为种子生成新元素:
-
-| 触发方向 | 目标队列 | 种子元素 | 生成公式 | 排序 |
-|---------|---------|---------|---------|------|
-| 空仓触发 → | 多仓队列 | 多仓队列首元素(最小价) | 种子 × (1 − gridRate × i) | 升序 |
-| 多仓触发 → | 空仓队列 | 空仓队列首元素(最高价) | 种子 × (1 + gridRate × i) | 降序 |
-
-### 贴近持仓均价过滤(新)
-
-转移生成新元素时,若元素与对应方向持仓均价的差距小于 gridRate,则跳过:
-
-| 目标队列 | 过滤条件 | 含义 |
-|---------|---------|------|
-| 多仓队列 | \|elem − longEntryPrice\| < longEntryPrice × gridRate | 太贴近多仓成本,跳过 |
-| 空仓队列 | \|elem − shortEntryPrice\| < shortEntryPrice × gridRate | 太贴近空仓成本,跳过 |
-
-> 过滤仅在对应方向有持仓时生效(entryPrice > 0),避免在持仓成本附近生成无效网格线。
-
-### 额外反向开仓条件(新)
-
-当触发价夹在多/空持仓均价之间,且多仓均价大于空仓均价(多>空倒挂)时,额外反向开仓一次:
-
-| 触发方向 | 额外操作 | 条件 |
-|---------|---------|------|
-| 空仓队列触发 | 额外开多 | shortEntryPrice > 0 && longEntryPrice > shortEntryPrice && shortEntryPrice < currentPrice < longEntryPrice × (1 − gridRate) |
-| 多仓队列触发 | 额外开空 | shortEntryPrice > 0 && longEntryPrice > shortEntryPrice && shortEntryPrice × (1 + gridRate) < currentPrice < longEntryPrice |
-
-**条件解释:**
-- `longEntryPrice > shortEntryPrice`:多仓均价高于空仓均价("倒挂"状态)
-- `shortEntryPrice × (1 + gridRate) < currentPrice`:空仓触发时金额够远离空仓均价
-- `currentPrice < longEntryPrice × (1 − gridRate)`:空仓触发时金额够远离多仓均价
-
-> 背后的思路:当"多亏空赚"发生倒挂时,在价格区间中间补一单反方向仓位,利用均值回归获利。
-
-### 队列转移示意
-
-```
-ETH_USDT, gridRate=0.0035, 空仓均价=2270, 多仓均价=2280, gridQueueSize=4:
-
-初始状态:
-  空仓队列: [2567.1, 2570.0, 2572.5, 2575.0]  (降序)
-  多仓队列: [2275.0, 2277.0, 2279.0, 2281.5]  (升序)
-
-价格跌到 2571 → processShortGrid 触发:
-  匹配: [2575.0, 2572.5](都 > 2571)
-  
-  空仓队列: 移除[2575.0,2572.5] → [2570.0,2567.1] → 补充递减 → [2570.0,2567.1,2560.0,2552.0]
-  多仓队列转移:
-    种子=多仓首元素 2275.0
-    生成: 2275.0×(1−0.0035×1)≈2267.0, 2275.0×(1−0.0035×2)≈2259.0
-    贴近过滤: |2267−2280|=13 > 2280×0.0035=7.98 → 通过
-              |2259−2280|=21 > 7.98 → 通过
-    多仓队列: [2259.0, 2267.0, 2275.0, 2277.0] → 截断到4 → [2267.0, 2275.0, 2277.0]
-  
-  当前价 2571 对比: 空仓均价=2270, 多仓均价=2280
-    多>空 成立,但 2270 < 2571 < 2280×(1−0.0035)=2272 ? 否
-    → 不触发额外开多
-```
-
----
-
-## 策略时序
-
-### 阶段 1:启动与初始化
-
-```
-Spring @PostConstruct
-  → GateConfig.builder()...build()
-  → GateGridTradeService(config)
-    → init():
-      1. 查用户ID(用于私有频道订阅)
-      2. 查账户 → 记录初始本金 initialPrincipal → 如需要切持仓模式
-      3. 清除旧止盈止损条件单
-      4. 查当前合约所有仓位 → 逐个市价平仓(reduce_only, IOC)
-         - 单向持仓: size=相反数平仓
-         - 双向持仓: size=0, close=false, autoSize=LONG/SHORT
-      5. 设杠杆
-  → GateKlineWebSocketClient(config.getWsUrl())
-    → addChannelHandler x3 → init() → connect()
-      → onOpen: handlers依次subscribe → sendPing
-  → gridTradeService.startGrid() → state=WAITING_KLINE
-```
-
-### 阶段 2:首次开仓 → 生成网格队列
-
-```
-K线推送 → onKline(closePrice) → state=OPENING
-  → executor.openLong(qty, onSuccess, onFailure)
-    → 成交 → 仓位推送: DUAL_LONG, size>0, entryPrice=X
-      → baseLongOpened=true, longBaseEntryPrice=X
-      → tryGenerateQueues(): 双基底都成交? → 生成队列 → state=ACTIVE
-  → executor.openShort(-qty, onSuccess, onFailure)
-    → 成交 → 仓位推送: DUAL_SHORT, size<0, entryPrice=Y
-      → baseShortOpened=true, shortBaseEntryPrice=Y
-      → tryGenerateQueues(): 双基底都成交? → 生成队列 → state=ACTIVE
-```
-
-### 阶段 3:ACTIVE 状态 — K线驱动网格
-
-```
-每根K线 → onKline → updateUnrealizedPnl → processShortGrid + processLongGrid
-
-仓位推送(每次开仓成交后自动触发):
-  → DUAL_LONG, size>0, 非基底 → 设多头止盈单:止盈价=longPriceQueue[0](多仓队列首元素),
-      使用 plan-close-long-position,平仓张数=-quantity(负=平多),rule=NUMBER_1(≥)
-  → DUAL_SHORT, size<0, 非基底 → 设空头止盈单:止盈价=shortPriceQueue[0](空仓队列首元素),
-      使用 plan-close-short-position,平仓张数=+quantity(正=平空),rule=NUMBER_2(≤)
-
-额外反向开仓(多>空倒挂时):
-  → 空仓队列触发 + 条件满足 → 额外开多一次
-  → 多仓队列触发 + 条件满足 → 额外开空一次
-```
-
-> 止盈由 Gate 服务端条件单自动执行。服务端监控价格,达到触发价后自动平仓。
-> 每次网格触发开仓 quantity 张,只在该批张数上设止盈,与之前已设的止盈单互不影响。
-> 平仓后仓位减少 quantity 张,盈亏通过 position_closes 频道推送到 cumulativePnl。
-
-### 阶段 4:停止
-
-```
-平仓推送: pnl=+0.6 → cumulativePnl=0.6 ≥ overallTp(0.5) → state=STOPPED
-平仓推送: pnl=-8.0 → cumulativePnl=-8.0 ≤ -maxLoss(7.5) → state=STOPPED
-```
-
----
-
-## GateConfig
-
-**角色**: 统一配置中心。Builder模式管理所有参数,提供 REST/WS URL 环境自动切换。
-
-**核心方法**:
-- `getRestBasePath()`: isProduction ? 生产网 : 测试网
-- `getWsUrl()`: 同上
-
-**配置项**(含默认值):
-
-| 参数 | 默认值 | 说明 |
-|------|--------|------|
-| contract | BTC_USDT | 合约 |
-| leverage | 10 | 倍数 |
-| marginMode | cross | 全仓 |
-| positionMode | dual | 双向持仓 |
-| gridRate | 0.0035 | 网格间距 0.35% |
-| overallTp | 0.5 USDT | 整体止盈 |
-| maxLoss | 7.5 USDT | 最大亏损 |
-| quantity | 1 | 下单张数 |
-| reopenMaxRetries | 3 | 补仓最大重试次数(当前版本未使用) |
-| gridQueueSize | 50 | 网格价格队列容量 |
-| marginRatioLimit | 0.2 | 保证金占初始本金比例上限(20%),超限跳过开仓 |
-| contractMultiplier | 0.001 | 合约乘数(单张合约代表的基础资产数量) |
-| unrealizedPnlPriceMode | LAST_PRICE | 未实现盈亏计价模式:LAST_PRICE / MARK_PRICE |
-
----
-
-## GateTradeExecutor
-
-**角色**: 独立线程池执行 REST API 下单。采用成功/失败双回调模式。
-
-**线程模型**:
-- `ThreadPoolExecutor(1, 1, 60s, LinkedBlockingQueue(64), CallerRunsPolicy)`
-- 单线程保序 + 有界队列防堆积 + CallerRuns背压
-- allowCoreThreadTimeOut: 60s 空闲后线程回收
-
-**回调设计**:
-- 每个下单方法接受 `onSuccess` 和 `onFailure` 两个 `Runnable`
-- REST 调用成功 → 执行 `onSuccess`(标记基底已开等)
-- REST 调用失败 → 执行 `onFailure`(当前版本多为 null,依赖 position 推送修正)
-
-| 方法 | 说明 |
-|------|------|
-| `openLong(qty, onSuccess, onFailure)` | 异步 IOC 市价开多,双回调 |
-| `openShort(qty, onSuccess, onFailure)` | 异步 IOC 市价开空,双回调 |
-| `placeTakeProfit(trigger, rule, type, size)` | 异步止盈条件单(plan-close-*-position)。size 为显式平仓张数(正=平空,负=平多),多次调用互不影响 |
-| `cancelAllPriceTriggeredOrders()` | 清除所有条件单 |
-| `shutdown()` | 等待10秒,超时强制关闭 |
-
-### 止盈条件单 order_type 说明
-
-| order_type | 用途 | size 语义 |
-|-----------|------|----------|
-| `plan-close-long-position` | 部分/全部平多仓 | size<0 表示平多仓张数 |
-| `plan-close-short-position` | 部分/全部平空仓 | size>0 表示平空仓张数 |
-
-> **为何不用 close-*-position**:`close-long-position` 和 `close-short-position` 仅支持全部平仓(size=0),且双仓模式还需设置 `auto_size`。网格策略需要指定张数部分平仓,因此必须使用 `plan-close-*-position`。
-
----
-
-## GateGridTradeService
-
-**角色**: 策略核心,管理网格队列状态和执行下单。
-
-**状态**: `StrategyState` enum: `WAITING_KLINE` / `OPENING` / `ACTIVE` / `STOPPED`
-
-**关键常量**:
-```java
-// 止盈条件单 order_type:仓位计划止盈止损,支持指定张数部分平仓
-private static final String ORDER_TYPE_CLOSE_LONG = "plan-close-long-position";
-private static final String ORDER_TYPE_CLOSE_SHORT = "plan-close-short-position";
-```
-
-**核心数据结构**:
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| shortPriceQueue | List\<BigDecimal\> | 空仓价格队列,降序(大→小),容量 gridQueueSize |
-| longPriceQueue | List\<BigDecimal\> | 多仓价格队列,升序(小→大),容量 gridQueueSize |
-| shortBaseEntryPrice | BigDecimal | 基底空头入场价(仅首次记录,用于生成队列) |
-| longBaseEntryPrice | BigDecimal | 基底多头入场价(仅首次记录,用于生成队列) |
-| shortEntryPrice | BigDecimal | 当前空仓入场价(推送实时更新,加权均价) |
-| longEntryPrice | BigDecimal | 当前多仓入场价(推送实时更新,加权均价) |
-| shortPositionSize | BigDecimal | 当前空仓持仓量(绝对值) |
-| longPositionSize | BigDecimal | 当前多仓持仓量 |
-| baseLongOpened | boolean | 基底多头是否已开 |
-| baseShortOpened | boolean | 基底空头是否已开 |
-| longActive / shortActive | boolean | 多/空方向是否持有仓位 |
-| cumulativePnl | BigDecimal | 累计已实现盈亏(平仓推送驱动) |
-| unrealizedPnl | BigDecimal | 未实现盈亏(每根K线更新,浮动盈亏) |
-| markPrice | BigDecimal | 标记价格(外部注入,MARK_PRICE 模式使用) |
-| initialPrincipal | BigDecimal | 初始本金(启动时账户总资产) |
-
-**回调方法**:
-- `onKline(closePrice)`: 更新 lastKlinePrice → 计算 unrealizedPnl → WAITING_KLINE 时触发基底双开,ACTIVE 时驱动 processShortGrid+processLongGrid
-- `onPositionUpdate(contract, mode, size, entryPrice)`: 记录当前入场价和持仓量 → 基底:首次成交记录入场价、生成队列;非基底:按 quantity 张数创建独立止盈条件单(plan-close-*-position)。无仓位时清空持仓量并标记不活跃
-- `onPositionClose(contract, side, pnl)`: 累加已实现盈亏,检查停止条件
-
-**processShortGrid / processLongGrid 核心逻辑**:
-
-| 步骤 | processShortGrid | processLongGrid |
-|------|-----------------|-----------------|
-| 匹配 | 收集 shortPriceQueue 中 > currentPrice 的元素 | 收集 longPriceQueue 中 < currentPrice 的元素 |
-| 主开仓 | 保证金安全 → openShort | 保证金安全 → openLong |
-| 额外反向 | 条件满足 → openLong | 条件满足 → openShort |
-| 本队补充 | 尾价 × (1−gridRate) 循环递减 | 尾价 × (1+gridRate) 循环递增 |
-| 对方转移 | 以多仓首元素为种子,递减生成 | 以空仓首元素为种子,递增生成 |
-| 贴近过滤 | 新增与 longEntryPrice 太近 → 跳过 | 新增与 shortEntryPrice 太近 → 跳过 |
-
-**未实现盈亏计算** (`updateUnrealizedPnl()`):
-
-正向合约公式(含合约乘数):
-
-| 方向 | 公式 |
-|------|------|
-| 多仓 | 持仓量 × contractMultiplier × (计价价格 − 开仓均价) |
-| 空仓 | 持仓量(绝对值)× contractMultiplier × (开仓均价 − 计价价格) |
-
-计价价格由 `unrealizedPnlPriceMode` 决定:
-- `LAST_PRICE`:使用最新成交价(`lastKlinePrice`,每根 K 线更新)
-- `MARK_PRICE`:使用标记价格(通过 `setMarkPrice()` 外部注入,如未注入则回退到最新成交价)
-
-入场价和持仓量由 `onPositionUpdate` 实时推送更新。
-
-**保证金安全阀** (`isMarginSafe()`):
-- 实时查询 `positionInitialMargin / initialPrincipal`
-- 比例 ≥ marginRatioLimit(默认20%)→ 跳过开仓,队列照常更新
-- REST 查询失败 → 默认放行(避免因查询异常阻塞策略)
-
-**止盈计算**:
-
-| 方向 | 公式 | order_type | size(平仓张数) | rule |
-|------|------|------------|-----------|------|
-| 多头 TP | longPriceQueue[0](多仓队列首元素) | `plan-close-long-position` | `-quantity`(负=平多) | NUMBER_1(≥触发价) |
-| 空头 TP | shortPriceQueue[0](空仓队列首元素) | `plan-close-short-position` | `+quantity`(正=平空) | NUMBER_2(≤触发价) |
-
-> 止盈价取自对应方向队列的首元素(多仓队列升序首=最小价,空仓队列降序首=最高价)。止盈单使用显式张数而非 autoSize。每次网格触发开仓 quantity 张,只为该批张数创建独立的条件单,多个止盈单之间互不覆盖。
-
-**REST API 调用**:
-
-| 操作 | API | 方法 | 说明 |
-|------|-----|------|------|
-| 获取用户ID | `GET /account/detail` | `AccountApi.getAccountDetail()` | |
-| 切持仓模式 | `POST /futures/usdt/set_position_mode` | `FuturesApi.setPositionMode()` | |
-| 查仓位 | `GET /futures/usdt/positions` | `FuturesApi.listPositions()` | 遍历所有仓位,按合约过滤 |
-| 市价平仓 | `POST /futures/usdt/orders` | `FuturesApi.createFuturesOrder()` | reduce_only, IOC。双向: size=0+close=false+autoSize |
-| 设杠杆 | `POST /futures/usdt/dual_comp/positions/{contract}/leverage` | `FuturesApi.updateDualModePositionLeverageCall()` | 双向模式专用 |
-| 查账户 | `GET /futures/usdt/accounts` | `FuturesApi.listFuturesAccounts()` | 获取初始本金和保证金 |
-| 清除条件单 | `DELETE /futures/usdt/price_orders` | `FuturesApi.cancelPriceTriggeredOrderList()` | |
-| 市价单 | `POST /futures/usdt/orders` | `FuturesApi.createFuturesOrder()` | price=0, tif=IOC |
-| 条件单 | `POST /futures/usdt/price_orders` | `FuturesApi.createPriceTriggeredOrder()` | strategy=0, price_type=0, expiration=0, order_type=plan-close-*-position, size=显式张数,多次调用互不冲突 |
-
-**初始化顺序** (`init()`):
-```
-1. 获取用户 ID
-2. 查账户 → 记录初始本金 → 如需要切持仓模式
-3. 清除旧的止盈止损条件单
-4. 查当前合约所有仓位 → 逐个市价平仓
-   - 单向持仓(single): size=相反数, reduce_only=true
-   - 双向持仓(dual): size=0, close=false, autoSize=LONG/SHORT, reduce_only=true
-5. 设杠杆
-6. 打印账户余额
-```
-
----
-
-## GateWebSocketClientMain
-
-独立 `main()` 方法入口,通过 Spring XML 上下文启动,运行后手动关闭。
-
----
-
-## Example.java
-
-Gate SDK 使用示例,展示 `FuturesApi` 的基本用法。仅作参考。
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
deleted file mode 100644
index 8fb1d08..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java
+++ /dev/null
@@ -1,183 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import java.nio.charset.StandardCharsets;
-
-/**
- * 私有频道处理器的抽象基类。
- *
- * <h3>封装内容</h3>
- * <ul>
- *   <li>HMAC-SHA512 签名计算(UTF-8 编码)</li>
- *   <li>认证请求 JSON 构建(id/time/channel/payload/auth)</li>
- *   <li>subscribe / unsubscribe 的默认实现(含签名)</li>
- *   <li>用户 ID 获取(从 {@link GateGridTradeService#getUserId()})</li>
- * </ul>
- *
- * <h3>签名算法</h3>
- * {@code SIGN = Hex(HmacSHA512(secret_utf8, "channel={channel}&event={event}&time={timeSec}"_utf8))}
- *
- * <h3>子类</h3>
- * {@link com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionsChannelHandler}、
- * {@link com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionClosesChannelHandler}
- *
- * @author Administrator
- */
-@Slf4j
-public abstract class AbstractPrivateChannelHandler implements GateChannelHandler {
-
-    private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
-
-    private final String channelName;
-    private final String apiKey;
-    private final String apiSecret;
-    private final String contract;
-    private final GateGridTradeService gridTradeService;
-
-    public AbstractPrivateChannelHandler(String channelName,
-                                          String apiKey, String apiSecret,
-                                          String contract,
-                                          GateGridTradeService gridTradeService) {
-        this.channelName = channelName;
-        this.apiKey = apiKey;
-        this.apiSecret = apiSecret;
-        this.contract = contract;
-        this.gridTradeService = gridTradeService;
-    }
-
-    /** @return 频道名称(如 "futures.positions") */
-    @Override
-    public String getChannelName() { return channelName; }
-
-    /**
-     * 发送带签名的订阅请求。
-     *
-     * <h3>请求格式</h3>
-     * <pre>
-     * {
-     *   "id":     &lt;唯一请求ID&gt;,
-     *   "time":   &lt;unix时间戳(秒)&gt;,
-     *   "channel":"futures.positions",
-     *   "event":  "subscribe",
-     *   "payload":[userId, contract],
-     *   "auth":   {"method":"api_key", "KEY":&lt;APIKEY&gt;, "SIGN":&lt;HMAC-SHA512签名&gt;}
-     * }
-     * </pre>
-     */
-    @Override
-    public void subscribe(WebSocketClient ws) {
-        long timeSec = System.currentTimeMillis() / 1000;
-        JSONObject msg = buildAuthRequest("subscribe", buildUid(), timeSec);
-        ws.send(msg.toJSONString());
-        log.info("[{}] 订阅成功, 合约:{}", channelName, contract);
-    }
-
-    /**
-     * 发送带签名的取消订阅请求,与 subscribe 结构一致。
-     * payload: [contract],无 userId(取消订阅不需要用户ID)。
-     */
-    @Override
-    public void unsubscribe(WebSocketClient ws) {
-        long timeSec = System.currentTimeMillis() / 1000;
-        JSONObject msg = new JSONObject();
-        msg.put("id", timeSec * 1000000 + (System.currentTimeMillis() % 1000));
-        msg.put("time", timeSec);
-        msg.put("channel", channelName);
-        msg.put("event", "unsubscribe");
-        JSONArray payload = new JSONArray();
-        payload.add(contract);
-        msg.put("payload", payload);
-        JSONObject auth = new JSONObject();
-        auth.put("method", "api_key");
-        auth.put("KEY", apiKey);
-        auth.put("SIGN", hs512Sign("unsubscribe", timeSec));
-        msg.put("auth", auth);
-        ws.send(msg.toJSONString());
-        log.info("[{}] 取消订阅成功, 合约:{}", channelName, contract);
-    }
-
-    /** @return 网格交易服务实例 */
-    protected GateGridTradeService getGridTradeService() { return gridTradeService; }
-    /** @return 当前订阅的合约名称 */
-    protected String getContract() { return contract; }
-
-    /**
-     * 从策略服务获取用户 ID,用于私有频道订阅的 payload[0]。
-     *
-     * @return 用户 ID 字符串,获取失败返回空字符串
-     */
-    private String buildUid() {
-        return gridTradeService != null && gridTradeService.getUserId() != null
-                ? String.valueOf(gridTradeService.getUserId()) : "";
-    }
-
-    /**
-     * 构建认证请求 JSON。
-     * 包含 id、time、channel、event、payload[userId, contract]、auth 字段。
-     *
-     * @param event   事件类型("subscribe" / "unsubscribe")
-     * @param uid     认证用户 ID
-     * @param timeSec unix 时间戳(秒)
-     * @return 完整的认证请求 JSONObject
-     */
-    private JSONObject buildAuthRequest(String event, String uid, long timeSec) {
-        JSONObject msg = new JSONObject();
-        msg.put("id", timeSec * 1000000 + (System.currentTimeMillis() % 1000));
-        msg.put("time", timeSec);
-        msg.put("channel", channelName);
-        msg.put("event", event);
-        JSONArray payload = new JSONArray();
-        payload.add(uid);
-        payload.add(contract);
-        msg.put("payload", payload);
-        JSONObject auth = new JSONObject();
-        auth.put("method", "api_key");
-        auth.put("KEY", apiKey);
-        auth.put("SIGN", hs512Sign(event, timeSec));
-        msg.put("auth", auth);
-        return msg;
-    }
-
-    /**
-     * HMAC-SHA512 签名计算。
-     *
-     * <h3>签名算法</h3>
-     * <pre>
-     *   message = "channel={channelName}&event={event}&time={timeSec}"
-     *   SIGN = Hex(HmacSHA512(apiSecret(UTF-8), message(UTF-8)))
-     * </pre>
-     *
-     * <h3>错误处理</h3>
-     * 签名计算失败时返回空字符串(日志记录错误),不抛异常,
-     * 避免阻塞 WebSocket 回调线程。
-     *
-     * @param event   事件类型
-     * @param timeSec unix 时间戳(秒)
-     * @return 十六进制签名字符串,失败返回 ""
-     */
-    private String hs512Sign(String event, long timeSec) {
-        try {
-            String message = "channel=" + channelName + "&event=" + event + "&time=" + timeSec;
-            Mac mac = Mac.getInstance("HmacSHA512");
-            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
-            mac.init(spec);
-            byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
-            StringBuilder hex = new StringBuilder(hash.length * 2);
-            for (byte b : hash) {
-                hex.append(HEX_ARRAY[(b >> 4) & 0xF]);
-                hex.append(HEX_ARRAY[b & 0xF]);
-            }
-            return hex.toString();
-        } catch (Exception e) {
-            log.error("[{}] 签名计算失败", channelName, e);
-            return "";
-        }
-    }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/GateChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/GateChannelHandler.java
deleted file mode 100644
index e24baff..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/GateChannelHandler.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler;
-
-import com.alibaba.fastjson.JSONObject;
-import org.java_websocket.client.WebSocketClient;
-
-/**
- * WebSocket 频道处理器接口。
- *
- * <p>每个 Gate 频道对应一个实现类。新增频道只需实现此接口,
- * 然后通过 {@code GateKlineWebSocketClient.addChannelHandler()} 注册即可。
- *
- * <h3>实现类</h3>
- * <ul>
- *   <li>{@code CandlestickChannelHandler} — 公开频道,K 线数据</li>
- *   <li>{@code AbstractPrivateChannelHandler} — 私有频道抽象基类(签名+认证)</li>
- *   <li>{@code PositionsChannelHandler} — 私有频道,仓位更新</li>
- *   <li>{@code PositionClosesChannelHandler} — 私有频道,平仓推送</li>
- * </ul>
- *
- * <h3>路由机制</h3>
- * {@code handleMessage()} 返回 {@code true} 表示消息已被该 handler 处理,
- * 路由循环会停止遍历。返回 {@code false} 表示不匹配(channel 名不相等)。
- *
- * @author Administrator
- */
-public interface GateChannelHandler {
-
-    /** 频道名称,如 {@code "futures.candlesticks"} */
-    String getChannelName();
-
-    /** 发送订阅请求 */
-    void subscribe(WebSocketClient ws);
-
-    /** 发送取消订阅请求 */
-    void unsubscribe(WebSocketClient ws);
-
-    /**
-     * 处理频道推送消息。
-     *
-     * @param response WebSocket 推送的完整 JSON
-     * @return true 表示已处理(循环停止),false 表示频道不匹配(继续遍历下一个 handler)
-     */
-    boolean handleMessage(JSONObject response);
-}
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
deleted file mode 100644
index bac9ef9..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler.handler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.blackchain.service.DateUtil;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import com.xcong.excoin.modules.gateApi.wsHandler.GateChannelHandler;
-import lombok.extern.slf4j.Slf4j;
-import org.java_websocket.client.WebSocketClient;
-
-import java.math.BigDecimal;
-
-/**
- * K 线(Candlestick)频道处理器。
- *
- * <h3>特点</h3>
- * 公开频道,无需 HMAC-SHA512 认证签名。订阅 1m 周期的 K 线数据。
- *
- * <h3>数据流</h3>
- * <pre>
- *   WebSocket 推送 update event
- *     → handleMessage() → 解析 OHLCV → log 打印 → gridTradeService.onKline(closePx)
- *       → WAITING_KLINE: 首次 K 线触发基底双开
- *       → ACTIVE: 驱动 processShortGrid + processLongGrid 网格触发
- * </pre>
- *
- * <h3>订阅格式</h3>
- * payload: {@code ["1m", contract]}
- *
- * @author Administrator
- */
-@Slf4j
-public class CandlestickChannelHandler implements GateChannelHandler {
-
-    private static final String CHANNEL_NAME = "futures.candlesticks";
-    private static final String INTERVAL = "1m";
-
-    private final String contract;
-    private final GateGridTradeService gridTradeService;
-
-    public CandlestickChannelHandler(String contract, GateGridTradeService gridTradeService) {
-        this.contract = contract;
-        this.gridTradeService = gridTradeService;
-    }
-
-    /** @return 频道名称 "futures.candlesticks" */
-    @Override
-    public String getChannelName() { return CHANNEL_NAME; }
-
-    /**
-     * 发送 K 线频道订阅请求(公开频道,无需签名)。
-     *
-     * <h3>订阅格式</h3>
-     * <pre>
-     * {
-     *   "time":    &lt;unix时间戳(秒)&gt;,
-     *   "channel": "futures.candlesticks",
-     *   "event":   "subscribe",
-     *   "payload": ["1m", "{contract}"]
-     * }
-     * </pre>
-     */
-    @Override
-    public void subscribe(WebSocketClient ws) {
-        JSONObject msg = new JSONObject();
-        msg.put("time", System.currentTimeMillis() / 1000);
-        msg.put("channel", CHANNEL_NAME);
-        msg.put("event", "subscribe");
-        JSONArray payload = new JSONArray();
-        payload.add(INTERVAL);
-        payload.add(contract);
-        msg.put("payload", payload);
-        ws.send(msg.toJSONString());
-        log.info("[{}] 订阅成功, 合约:{}, 周期:{}", CHANNEL_NAME, contract, INTERVAL);
-    }
-
-    /**
-     * 发送 K 线频道取消订阅请求。
-     */
-    @Override
-    public void unsubscribe(WebSocketClient ws) {
-        JSONObject msg = new JSONObject();
-        msg.put("time", System.currentTimeMillis() / 1000);
-        msg.put("channel", CHANNEL_NAME);
-        msg.put("event", "unsubscribe");
-        JSONArray payload = new JSONArray();
-        payload.add(INTERVAL);
-        payload.add(contract);
-        msg.put("payload", payload);
-        ws.send(msg.toJSONString());
-        log.info("[{}] 取消订阅成功", CHANNEL_NAME);
-    }
-
-    /**
-     * 处理 K 线推送消息。
-     *
-     * <h3>数据提取</h3>
-     * result[0] 中提取:
-     * <ul>
-     *   <li>c(close):收盘价 → 传给 gridTradeService.onKline()</li>
-     *   <li>n(name):烛线名称(如 "1m_ETH_USDT")</li>
-     *   <li>t(time):烛线起始时间戳</li>
-     *   <li>w(window_close):烛线是否完结(仅日志输出,不做门控)</li>
-     * </ul>
-     *
-     * <h3>注意</h3>
-     * 不判断 w(已完结)——策略需要 tick 级实时响应价格变动,
-     * 而非等 1 分钟烛线完结后才行动。
-     *
-     * @param response WebSocket 推送的完整 JSON
-     * @return true 表示已处理(匹配成功)
-     */
-    @Override
-    public boolean handleMessage(JSONObject response) {
-        if (!CHANNEL_NAME.equals(response.getString("channel"))) {
-            return false;
-        }
-        try {
-            JSONArray resultArray = response.getJSONArray("result");
-            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("名称: {} 时间: {}", data.getString("n"), DateUtil.TimeStampToDateTime(data.getLong("t")));
-            log.info("收盘: {} 已完结: {}",data.getString("c"),data.getBooleanValue("w"));
-            log.info("==================================");
-
-            if (gridTradeService != null) {
-                gridTradeService.onKline(closePx);
-            }
-        } 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
deleted file mode 100644
index 3ca98ff..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler.handler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import com.xcong.excoin.modules.gateApi.wsHandler.AbstractPrivateChannelHandler;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-
-/**
- * 平仓频道处理器。
- *
- * <h3>数据用途</h3>
- * 每笔平仓发生时推送 pnl(盈亏金额),累加到 {@code cumulativePnl} 用于判断策略停止条件:
- * cumulativePnl ≥ overallTp(达到止盈目标)或 ≤ -maxLoss(超过亏损上限)。
- * 止盈由 Gate 服务端条件单自动触发,平仓后仓位变为 0,盈亏通过本频道推送。
- *
- * <h3>推送字段</h3>
- * contract, side(long / short), pnl(该次平仓的盈亏,如 "+0.2" 或 "-0.1")
- *
- * <h3>注意</h3>
- * 平仓盈亏来自服务器端,不受本地计算误差影响。这是策略停止的唯一盈亏判断来源。
- *
- * @author Administrator
- */
-@Slf4j
-public class PositionClosesChannelHandler extends AbstractPrivateChannelHandler {
-
-    private static final String CHANNEL_NAME = "futures.position_closes";
-
-    public PositionClosesChannelHandler(String apiKey, String apiSecret,
-                                         String contract,
-                                         GateGridTradeService gridTradeService) {
-        super(CHANNEL_NAME, apiKey, apiSecret, contract, gridTradeService);
-    }
-
-    /**
-     * 处理平仓推送消息。
-     *
-     * <h3>数据提取</h3>
-     * result 数组中每个元素包含:
-     * <ul>
-     *   <li>contract:合约名称</li>
-     *   <li>side:平仓方向("long" / "short")</li>
-     *   <li>pnl:本次平仓的盈亏金额(字符串格式,如 "+0.2" / "-0.1")</li>
-     * </ul>
-     *
-     * <h3>数据处理</h3>
-     * 按合约名称过滤 → 提取 pnl 和 side → 调用 gridTradeService.onPositionClose() 累加盈亏。
-     * pnl 来自服务端,不受本地计算误差影响。
-     *
-     * @param response WebSocket 推送的完整 JSON
-     * @return true 表示已处理(匹配成功)
-     */
-    @Override
-    public boolean handleMessage(JSONObject response) {
-        if (!CHANNEL_NAME.equals(response.getString("channel"))) {
-            return false;
-        }
-        try {
-            JSONArray resultArray = response.getJSONArray("result");
-            if (resultArray == null || resultArray.isEmpty()) {
-                return true;
-            }
-            for (int i = 0; i < resultArray.size(); i++) {
-                JSONObject item = resultArray.getJSONObject(i);
-                if (!getContract().equals(item.getString("contract"))) {
-                    continue;
-                }
-                BigDecimal pnl = new BigDecimal(item.getString("pnl"));
-                String side = item.getString("side");
-                log.info("[{}] 平仓更新, 方向:{}, 盈亏:{}", CHANNEL_NAME, side, pnl);
-                if (getGridTradeService() != null) {
-                    getGridTradeService().onPositionClose(getContract(), side, pnl);
-                }
-            }
-        } 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
deleted file mode 100644
index 4b6bf50..0000000
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package com.xcong.excoin.modules.gateApi.wsHandler.handler;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.xcong.excoin.modules.gateApi.GateGridTradeService;
-import com.xcong.excoin.modules.gateApi.wsHandler.AbstractPrivateChannelHandler;
-import io.gate.gateapi.models.Position;
-import lombok.extern.slf4j.Slf4j;
-
-import java.math.BigDecimal;
-
-/**
- * 仓位频道处理器(futures.positions)。
- *
- * <h3>数据用途</h3>
- * 监控仓位数量(size)和入场价(entry_price)。
- * 有仓位时(size.abs > 0):标记方向活跃,记录入场价 → 基底首次成交记录基底入场价并等待生成网格队列,
- * 非基底成交立即设止盈条件单。无仓位时(size=0):标记方向不活跃。
- *
- * <h3>完整推送字段(共20个,日志全部输出)</h3>
- * <table>
- *   <tr><th>字段</th><th>类型</th><th>描述</th></tr>
- *   <tr><td>contract</td><td>String</td><td>合约名称</td></tr>
- *   <tr><td>mode</td><td>String</td><td>持仓模式:dual_long / dual_short</td></tr>
- *   <tr><td>size</td><td>String/Integer</td><td>合约张数(正=多头,负=空头)</td></tr>
- *   <tr><td>entry_price</td><td>Float</td><td>开仓均价</td></tr>
- *   <tr><td>cross_leverage_limit</td><td>Float</td><td>全仓模式下的杠杆倍数上限</td></tr>
- *   <tr><td>history_pnl</td><td>Float</td><td>已平仓的仓位总盈亏</td></tr>
- *   <tr><td>history_point</td><td>Float</td><td>已平仓的点卡总盈亏</td></tr>
- *   <tr><td>last_close_pnl</td><td>Float</td><td>最近一次平仓的盈亏</td></tr>
- *   <tr><td>leverage</td><td>Integer</td><td>杠杆倍数(0=全仓,正数=逐仓)</td></tr>
- *   <tr><td>leverage_max</td><td>Integer</td><td>当前风险限额下允许的最大杠杆倍数</td></tr>
- *   <tr><td>liq_price</td><td>Float</td><td>爆仓价格</td></tr>
- *   <tr><td>maintenance_rate</td><td>Float</td><td>当前风险限额下维持保证金比例</td></tr>
- *   <tr><td>margin</td><td>Float</td><td>保证金</td></tr>
- *   <tr><td>realised_pnl</td><td>Float</td><td>已实现盈亏</td></tr>
- *   <tr><td>realised_point</td><td>Float</td><td>点卡已实现盈亏</td></tr>
- *   <tr><td>risk_limit</td><td>Integer</td><td>风险限额</td></tr>
- *   <tr><td>time</td><td>Integer</td><td>更新 unix 时间戳(秒)</td></tr>
- *   <tr><td>time_ms</td><td>Integer</td><td>更新 unix 时间戳(毫秒)</td></tr>
- *   <tr><td>user</td><td>String</td><td>用户 ID</td></tr>
- *   <tr><td>update_id</td><td>Integer</td><td>消息序列号,每次推送 order 后自增1</td></tr>
- * </table>
- *
- * <h3>回调数据(传给 GateGridTradeService)</h3>
- * mode (Position.ModeEnum), size (BigDecimal), entry_price (BigDecimal)
- *
- * <h3>注意</h3>
- * 双向持仓模式下空头 size 为负数,使用 {@code size.abs()} 判断是否有仓位。
- * 累计盈亏不由本频道计算,而是由 {@link PositionClosesChannelHandler} 独立处理。
- * 止盈条件单由服务端自动触发平仓,本频道不负责开仓操作。
- *
- * @author Administrator
- */
-@Slf4j
-public class PositionsChannelHandler extends AbstractPrivateChannelHandler {
-
-    private static final String CHANNEL_NAME = "futures.positions";
-
-    public PositionsChannelHandler(String apiKey, String apiSecret,
-                                    String contract,
-                                    GateGridTradeService gridTradeService) {
-        super(CHANNEL_NAME, apiKey, apiSecret, contract, gridTradeService);
-    }
-
-    @Override
-    public boolean handleMessage(JSONObject response) {
-        if (!CHANNEL_NAME.equals(response.getString("channel"))) {
-            return false;
-        }
-        try {
-            JSONArray resultArray = response.getJSONArray("result");
-            if (resultArray == null || resultArray.isEmpty()) {
-                return true;
-            }
-            for (int i = 0; i < resultArray.size(); i++) {
-                JSONObject pos = resultArray.getJSONObject(i);
-                if (!getContract().equals(pos.getString("contract"))) {
-                    continue;
-                }
-                String modeStr = pos.getString("mode");
-                Position.ModeEnum mode = Position.ModeEnum.fromValue(modeStr);
-                BigDecimal size = new BigDecimal(pos.getString("size"));
-                BigDecimal entryPrice = new BigDecimal(pos.getString("entry_price"));
-                log.info("[{}] 持仓更新, 合约:{}, 模式:{}, 数量:{}, 入场价:{}, 全仓杠杆上限:{}, 历史盈亏:{}, 历史点卡:{}, 最近平仓盈亏:{}, 杠杆:{}, 最大杠杆:{}, 爆仓价:{}, 维持保证金率:{}, 保证金:{}, 已实现盈亏:{}, 点卡已实现盈亏:{}, 风险限额:{}, 时间:{}, 时间ms:{}, 用户:{}, 更新ID:{}",
-                        CHANNEL_NAME, pos.getString("contract"), modeStr, size, entryPrice,
-                        pos.get("cross_leverage_limit"), pos.get("history_pnl"), pos.get("history_point"),
-                        pos.get("last_close_pnl"), pos.get("leverage"), pos.get("leverage_max"),
-                        pos.get("liq_price"), pos.get("maintenance_rate"), pos.get("margin"),
-                        pos.get("realised_pnl"), pos.get("realised_point"), pos.get("risk_limit"),
-                        pos.get("time"), pos.get("time_ms"), pos.get("user"), pos.get("update_id"));
-                if (getGridTradeService() != null) {
-                    getGridTradeService().onPositionUpdate(getContract(), mode, size, entryPrice);
-                }
-            }
-        } catch (Exception e) { log.error("[{}] 处理数据失败", CHANNEL_NAME, e); }
-        return true;
-    }
-}
diff --git a/src/main/java/com/xcong/excoin/modules/okxApi/OkxGridTradeService.java b/src/main/java/com/xcong/excoin/modules/okxApi/OkxGridTradeService.java
index 7e285ae..75b1296 100644
--- a/src/main/java/com/xcong/excoin/modules/okxApi/OkxGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/okxApi/OkxGridTradeService.java
@@ -17,9 +17,11 @@
         WAITING_KLINE, OPENING, ACTIVE, STOPPED
     }
 
+    private static final String ORDER_TYPE_CLOSE_LONG = "plan-close-long-position";
+    private static final String ORDER_TYPE_CLOSE_SHORT = "plan-close-short-position";
+
     private final OkxConfig config;
     private final OkxTradeExecutor executor;
-    private final String accountName;
 
     private volatile StrategyState state = StrategyState.WAITING_KLINE;
 
@@ -41,21 +43,18 @@
     private volatile BigDecimal longPositionSize = BigDecimal.ZERO;
     private volatile BigDecimal shortPositionSize = BigDecimal.ZERO;
 
-    private volatile WebSocketClient wsClient;
-
     public OkxGridTradeService(OkxConfig config, String accountName) {
         this.config = config;
-        this.accountName = accountName;
-        this.executor = new OkxTradeExecutor(config, accountName);
+        this.executor = new OkxTradeExecutor(config.getContract(), config.getMarginMode(), accountName);
     }
 
     public void setWebSocketClient(WebSocketClient wsClient) {
-        this.wsClient = wsClient;
+        this.executor.setWebSocketClient(wsClient);
     }
 
     public void startGrid() {
         if (state != StrategyState.WAITING_KLINE && state != StrategyState.STOPPED) {
-            log.warn("[{}] 策略已在运行中, state:{}", accountName, state);
+            log.warn("[{}] 策略已在运行中, state:{}", config.getContract(), state);
             return;
         }
         state = StrategyState.WAITING_KLINE;
@@ -71,19 +70,17 @@
         shortActive = false;
         shortPriceQueue.clear();
         longPriceQueue.clear();
-        log.info("[{}] 网格策略已启动", accountName);
+        log.info("[{}] 网格策略已启动", config.getContract());
     }
 
     public void stopGrid() {
         state = StrategyState.STOPPED;
+        executor.cancelAllPriceTriggeredOrders();
         executor.shutdown();
-        log.info("[{}] 策略已停止, 累计盈亏: {}", accountName, cumulativePnl);
+        log.info("[{}] 策略已停止, 累计盈亏: {}", config.getContract(), cumulativePnl);
     }
 
     public void onKline(BigDecimal closePrice) {
-        if (wsClient == null || !wsClient.isOpen()) {
-            return;
-        }
         lastKlinePrice = closePrice;
         updateUnrealizedPnl();
         if (state == StrategyState.STOPPED) {
@@ -92,9 +89,13 @@
 
         if (state == StrategyState.WAITING_KLINE) {
             state = StrategyState.OPENING;
-            log.info("[{}] 首根K线到达,开基底仓位...", accountName);
-            executor.openLong(wsClient, () -> log.info("[{}] 基底多单已发送", accountName));
-            executor.openShort(wsClient, () -> log.info("[{}] 基底空单已发送", accountName));
+            log.info("[{}] 首根K线到达,开基底仓位...", config.getContract());
+            executor.openLong(config.getQuantity(), () -> {
+                log.info("[{}] 基底多单已提交", config.getContract());
+            }, null);
+            executor.openShort(config.getQuantity(), () -> {
+                log.info("[{}] 基底空单已提交", config.getContract());
+            }, null);
             return;
         }
 
@@ -120,13 +121,17 @@
                     longPositionSize = size;
                     longBaseEntryPrice = entryPrice;
                     baseLongOpened = true;
-                    log.info("[{}] 基底多成交价: {}", accountName, longBaseEntryPrice);
+                    log.info("[{}] 基底多成交价: {}", config.getContract(), longBaseEntryPrice);
                     tryGenerateQueues();
                 } else if (size.compareTo(longPositionSize) > 0) {
                     longPositionSize = size;
-                    BigDecimal tpPrice = entryPrice.multiply(BigDecimal.ONE.add(config.getGridRate())).setScale(1, RoundingMode.HALF_UP);
-                    executor.placeTakeProfit(wsClient, OkxEnums.POSSIDE_LONG, tpPrice, config.getQuantity());
-                    log.info("[{}] 多单止盈已设, entry:{}, tp:{}", accountName, entryPrice, tpPrice);
+                    if (longPriceQueue.isEmpty()) {
+                        log.warn("[{}] 多仓队列为空,无法设止盈", config.getContract());
+                    } else {
+                        BigDecimal tpPrice = longPriceQueue.get(0);
+                        executor.placeTakeProfit(tpPrice, ORDER_TYPE_CLOSE_LONG, config.getQuantity());
+                        log.info("[{}] 多单止盈已设, entry:{}, tp:{}, size:{}", config.getContract(), entryPrice, tpPrice, config.getQuantity());
+                    }
                 } else {
                     longPositionSize = size;
                 }
@@ -142,13 +147,17 @@
                     shortPositionSize = size;
                     shortBaseEntryPrice = entryPrice;
                     baseShortOpened = true;
-                    log.info("[{}] 基底空成交价: {}", accountName, shortBaseEntryPrice);
+                    log.info("[{}] 基底空成交价: {}", config.getContract(), shortBaseEntryPrice);
                     tryGenerateQueues();
                 } else if (size.compareTo(shortPositionSize) > 0) {
                     shortPositionSize = size;
-                    BigDecimal tpPrice = entryPrice.multiply(BigDecimal.ONE.subtract(config.getGridRate())).setScale(1, RoundingMode.HALF_UP);
-                    executor.placeTakeProfit(wsClient, OkxEnums.POSSIDE_SHORT, tpPrice, config.getQuantity());
-                    log.info("[{}] 空单止盈已设, entry:{}, tp:{}", accountName, entryPrice, tpPrice);
+                    if (shortPriceQueue.isEmpty()) {
+                        log.warn("[{}] 空仓队列为空,无法设止盈", config.getContract());
+                    } else {
+                        BigDecimal tpPrice = shortPriceQueue.get(0);
+                        executor.placeTakeProfit(tpPrice, ORDER_TYPE_CLOSE_SHORT, config.getQuantity());
+                        log.info("[{}] 空单止盈已设, entry:{}, tp:{}, size:{}", config.getContract(), entryPrice, tpPrice, config.getQuantity());
+                    }
                 } else {
                     shortPositionSize = size;
                 }
@@ -164,13 +173,13 @@
             return;
         }
         cumulativePnl = cumulativePnl.add(pnl);
-        log.info("[{}] 订单成交盈亏: {}, 方向:{}, 累计:{}", accountName, pnl, posSide, cumulativePnl);
+        log.info("[{}] 订单成交盈亏: {}, 方向:{}, 累计:{}", config.getContract(), pnl, posSide, cumulativePnl);
 
         if (cumulativePnl.compareTo(config.getOverallTp()) >= 0) {
-            log.info("[{}] 已达止盈目标 {}→已停止", accountName, cumulativePnl);
+            log.info("[{}] 已达止盈目标 {}→已停止", config.getContract(), cumulativePnl);
             state = StrategyState.STOPPED;
         } else if (cumulativePnl.compareTo(config.getMaxLoss().negate()) <= 0) {
-            log.info("[{}] 已达亏损上限 {}→已停止", accountName, cumulativePnl);
+            log.info("[{}] 已达亏损上限 {}→已停止", config.getContract(), cumulativePnl);
             state = StrategyState.STOPPED;
         }
     }
@@ -181,7 +190,7 @@
             generateLongQueue();
             state = StrategyState.ACTIVE;
             log.info("[{}] 网格队列已生成, 空队首:{} → 尾:{}, 多队首:{} → 尾:{}, 已激活",
-                    accountName,
+                    config.getContract(),
                     shortPriceQueue.isEmpty() ? "N/A" : shortPriceQueue.get(0),
                     shortPriceQueue.isEmpty() ? "N/A" : shortPriceQueue.get(shortPriceQueue.size() - 1),
                     longPriceQueue.isEmpty() ? "N/A" : longPriceQueue.get(0),
@@ -196,7 +205,7 @@
             shortPriceQueue.add(shortBaseEntryPrice.multiply(BigDecimal.ONE.subtract(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP));
         }
         shortPriceQueue.sort((a, b) -> b.compareTo(a));
-        log.info("[{}] 空队列:{}", accountName, shortPriceQueue);
+        log.info("[{}] 空队列:{}", config.getContract(), shortPriceQueue);
     }
 
     private void generateLongQueue() {
@@ -206,7 +215,7 @@
             longPriceQueue.add(longBaseEntryPrice.multiply(BigDecimal.ONE.add(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP));
         }
         longPriceQueue.sort(BigDecimal::compareTo);
-        log.info("[{}] 多队列:{}", accountName, longPriceQueue);
+        log.info("[{}] 多队列:{}", config.getContract(), longPriceQueue);
     }
 
     /**
@@ -219,10 +228,10 @@
      * <h3>执行流程</h3>
      * <ol>
      *   <li>匹配队列元素 → 为空则直接返回</li>
-     *   <li>保证金检查 → 安全则开空一次</li>
-     *   <li>额外反向开多:若多仓均价 > 空仓均价 且 当前价夹在中间且远离多仓均价</li>
      *   <li>空仓队列:移除 matched 元素,尾部补充新元素(尾价 × (1 − gridRate) 循环递减)</li>
      *   <li>多仓队列:以多仓队列首元素(最小价)为种子,生成 matched.size() 个递减元素加入</li>
+     *   <li>保证金检查 → 安全则开空一次</li>
+     *   <li>额外反向开多:若多仓均价 > 空仓均价 且 当前价夹在中间且远离多仓均价</li>
      * </ol>
      *
      * <h3>多仓队列转移过滤</h3>
@@ -239,23 +248,12 @@
                 }
             }
         }
+        log.info("[{}] 原空队列:{}", config.getContract(), shortPriceQueue);
         if (matched.isEmpty()) {
+            log.info("[{}] 空仓队列未触发, 当前价:{}", config.getContract(), currentPrice);
             return;
         }
-        log.info("[{}] 空仓队列触发, 匹配{}个元素, 当前价:{}", accountName, matched.size(), currentPrice);
-        if (!isMarginSafe()) {
-            log.warn("[{}] 保证金超限,跳过空单开仓", accountName);
-        } else {
-            executor.openShort(wsClient, null);
-            if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                    && longEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                    && longEntryPrice.compareTo(shortEntryPrice) > 0
-                    && currentPrice.compareTo(shortEntryPrice) > 0
-                    && currentPrice.compareTo(longEntryPrice.multiply(BigDecimal.ONE.subtract(config.getGridRate()))) < 0) {
-                executor.openLong(wsClient, null);
-                log.info("[{}] 触发价在多/空持仓价之间且多>空且远离多仓均价, 额外开多一次, 当前价:{}", accountName, currentPrice);
-            }
-        }
+        log.info("[{}] 空仓队列触发, 匹配{}个元素, 当前价:{}", config.getContract(), matched.size(), currentPrice);
 
         synchronized (shortPriceQueue) {
             shortPriceQueue.removeAll(matched);
@@ -264,8 +262,10 @@
             for (int i = 0; i < matched.size(); i++) {
                 min = min.multiply(BigDecimal.ONE.subtract(step)).setScale(1, RoundingMode.HALF_UP);
                 shortPriceQueue.add(min);
+                log.info("[{}] 空队列增加:{}", config.getContract(), min);
             }
             shortPriceQueue.sort((a, b) -> b.compareTo(a));
+            log.info("[{}] 现空队列:{}", config.getContract(), shortPriceQueue);
         }
 
         synchronized (longPriceQueue) {
@@ -275,13 +275,30 @@
                 BigDecimal elem = first.multiply(BigDecimal.ONE.subtract(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP);
                 if (longEntryPrice.compareTo(BigDecimal.ZERO) > 0
                         && currentPrice.subtract(longEntryPrice).abs().compareTo(longEntryPrice.multiply(step)) < 0) {
+                    log.info("[{}] 多队列跳过(price≈longEntry):{}", config.getContract(), elem);
                     continue;
                 }
                 longPriceQueue.add(elem);
+                log.info("[{}] 多队列增加:{}", config.getContract(), elem);
             }
             longPriceQueue.sort(BigDecimal::compareTo);
             while (longPriceQueue.size() > config.getGridQueueSize()) {
                 longPriceQueue.remove(longPriceQueue.size() - 1);
+            }
+            log.info("[{}] 现多队列:{}", config.getContract(), longPriceQueue);
+        }
+
+        if (!isMarginSafe()) {
+            log.warn("[{}] 保证金超限,跳过空单开仓", config.getContract());
+        } else {
+            executor.openShort(config.getQuantity(), null, null);
+            if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
+                    && longEntryPrice.compareTo(BigDecimal.ZERO) > 0
+                    && longEntryPrice.compareTo(shortEntryPrice) > 0
+                    && currentPrice.compareTo(shortEntryPrice) > 0
+                    && currentPrice.compareTo(longEntryPrice.multiply(BigDecimal.ONE.subtract(config.getGridRate()))) < 0) {
+                executor.openLong(config.getQuantity(), null, null);
+                log.info("[{}] 触发价在多/空持仓价之间且多>空且远离多仓均价, 额外开多一次, 当前价:{}", config.getContract(), currentPrice);
             }
         }
     }
@@ -296,10 +313,10 @@
      * <h3>执行流程</h3>
      * <ol>
      *   <li>匹配队列元素 → 为空则直接返回</li>
-     *   <li>保证金检查 → 安全则开多一次</li>
-     *   <li>额外反向开空:若多仓均价 > 空仓均价 且 当前价夹在中间且远离空仓均价</li>
      *   <li>多仓队列:移除 matched 元素,尾部补充新元素(尾价 × (1 + gridRate) 循环递增)</li>
      *   <li>空仓队列:以空仓队列首元素(最高价)为种子,生成 matched.size() 个递增元素加入</li>
+     *   <li>保证金检查 → 安全则开多一次</li>
+     *   <li>额外反向开空:若多仓均价 > 空仓均价 且 当前价夹在中间且远离空仓均价</li>
      * </ol>
      *
      * <h3>空仓队列转移过滤</h3>
@@ -316,23 +333,12 @@
                 }
             }
         }
+        log.info("[{}] 原多队列:{}", config.getContract(), longPriceQueue);
         if (matched.isEmpty()) {
+            log.info("[{}] 多仓队列未触发, 当前价:{}", config.getContract(), currentPrice);
             return;
         }
-        log.info("[{}] 多仓队列触发, 匹配{}个元素, 当前价:{}", accountName, matched.size(), currentPrice);
-        if (!isMarginSafe()) {
-            log.warn("[{}] 保证金超限,跳过多单开仓", accountName);
-        } else {
-            executor.openLong(wsClient, null);
-            if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                    && longEntryPrice.compareTo(BigDecimal.ZERO) > 0
-                    && longEntryPrice.compareTo(shortEntryPrice) > 0
-                    && currentPrice.compareTo(shortEntryPrice.multiply(BigDecimal.ONE.add(config.getGridRate()))) > 0
-                    && currentPrice.compareTo(longEntryPrice) < 0) {
-                executor.openShort(wsClient, null);
-                log.info("[{}] 触发价在多/空持仓价之间且多>空且远离空仓均价, 额外开空一次, 当前价:{}", accountName, currentPrice);
-            }
-        }
+        log.info("[{}] 多仓队列触发, 匹配{}个元素, 当前价:{}", config.getContract(), matched.size(), currentPrice);
 
         synchronized (longPriceQueue) {
             longPriceQueue.removeAll(matched);
@@ -341,8 +347,10 @@
             for (int i = 0; i < matched.size(); i++) {
                 max = max.multiply(BigDecimal.ONE.add(step)).setScale(1, RoundingMode.HALF_UP);
                 longPriceQueue.add(max);
+                log.info("[{}] 多队列增加:{}", config.getContract(), max);
             }
             longPriceQueue.sort(BigDecimal::compareTo);
+            log.info("[{}] 现多队列:{}", config.getContract(), longPriceQueue);
         }
 
         synchronized (shortPriceQueue) {
@@ -352,13 +360,30 @@
                 BigDecimal elem = first.multiply(BigDecimal.ONE.add(step.multiply(BigDecimal.valueOf(i)))).setScale(1, RoundingMode.HALF_UP);
                 if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
                         && currentPrice.subtract(shortEntryPrice).abs().compareTo(shortEntryPrice.multiply(step)) < 0) {
+                    log.info("[{}] 空队列跳过(price≈shortEntry):{}", config.getContract(), elem);
                     continue;
                 }
                 shortPriceQueue.add(elem);
+                log.info("[{}] 空队列增加:{}", config.getContract(), elem);
             }
             shortPriceQueue.sort((a, b) -> b.compareTo(a));
             while (shortPriceQueue.size() > config.getGridQueueSize()) {
                 shortPriceQueue.remove(shortPriceQueue.size() - 1);
+            }
+            log.info("[{}] 现空队列:{}", config.getContract(), shortPriceQueue);
+        }
+
+        if (!isMarginSafe()) {
+            log.warn("[{}] 保证金超限,跳过多单开仓", config.getContract());
+        } else {
+            executor.openLong(config.getQuantity(), null, null);
+            if (shortEntryPrice.compareTo(BigDecimal.ZERO) > 0
+                    && longEntryPrice.compareTo(BigDecimal.ZERO) > 0
+                    && longEntryPrice.compareTo(shortEntryPrice) > 0
+                    && currentPrice.compareTo(shortEntryPrice.multiply(BigDecimal.ONE.add(config.getGridRate()))) > 0
+                    && currentPrice.compareTo(longEntryPrice) < 0) {
+                executor.openShort(config.getQuantity(), null, null);
+                log.info("[{}] 触发价在多/空持仓价之间且多>空且远离空仓均价, 额外开空一次, 当前价:{}", config.getContract(), currentPrice);
             }
         }
     }
@@ -390,6 +415,7 @@
             shortPnl = shortPositionSize.multiply(multiplier).multiply(shortEntryPrice.subtract(price));
         }
         unrealizedPnl = longPnl.add(shortPnl);
+        log.info("[{}] 未实现盈亏: {}", config.getContract(), unrealizedPnl);
     }
 
     public BigDecimal getLastKlinePrice() { return lastKlinePrice; }
@@ -397,5 +423,5 @@
     public BigDecimal getCumulativePnl() { return cumulativePnl; }
     public BigDecimal getUnrealizedPnl() { return unrealizedPnl; }
     public StrategyState getState() { return state; }
-    public String getAccountName() { return accountName; }
+    public String getAccountName() { return config.getContract(); }
 }
diff --git a/src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java b/src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java
index a5a15ea..94c162e 100644
--- a/src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java
+++ b/src/main/java/com/xcong/excoin/modules/okxApi/OkxTradeExecutor.java
@@ -22,26 +22,44 @@
  * WebSocket 消息在回调线程中处理。下单操作参数构建等逻辑
  * 提交到独立线程池异步执行,避免阻塞 WS 回调线程。
  *
+ * <h3>回调设计</h3>
+ * 每个下单方法接受 onSuccess/onFailure 两个 Runnable。
+ * 基底开仓时 onSuccess 用于标记基底已开,网格触发时通常为 null(成交状态由仓位推送驱动)。
+ *
  * <h3>线程模型</h3>
  * <ul>
  *   <li><b>单线程</b>:保证下单顺序(开多→开空→止盈单),避免并发竞争</li>
- *   <li><b>有界队列 64</b>:防止堆积</li>
+ *   <li><b>有界队列 64</b>:防止堆积。极端行情下最多累积 64 个任务</li>
  *   <li><b>CallerRunsPolicy</b>:队列满时由提交线程直接同步执行,形成自然背压</li>
- *   <li><b>allowCoreThreadTimeOut</b>:60s 空闲后线程回收</li>
+ *   <li><b>allowCoreThreadTimeOut</b>:60s 空闲后线程回收,不浪费资源</li>
  * </ul>
+ *
+ * <h3>调用链</h3>
+ * <pre>
+ *   OkxGridTradeService.onKline → executor.openLong/openShort (基底双开 + 网格触发)
+ *   OkxGridTradeService.onPositionUpdate → executor.placeTakeProfit (开仓成交后设止盈)
+ *   OkxGridTradeService.stopGrid → executor.cancelAllPriceTriggeredOrders
+ * </pre>
  *
  * @author Administrator
  */
 @Slf4j
 public class OkxTradeExecutor {
 
-    private final OkxConfig config;
+    private static final String ORDER_TYPE_CLOSE_LONG = "plan-close-long-position";
+    private static final String ORDER_TYPE_CLOSE_SHORT = "plan-close-short-position";
+
+    private final String contract;
+    private final String marginMode;
     private final String accountName;
+
+    private volatile WebSocketClient wsClient;
 
     private final ExecutorService executor;
 
-    public OkxTradeExecutor(OkxConfig config, String accountName) {
-        this.config = config;
+    public OkxTradeExecutor(String contract, String marginMode, String accountName) {
+        this.contract = contract;
+        this.marginMode = marginMode;
         this.accountName = accountName;
         this.executor = new ThreadPoolExecutor(
                 1, 1,
@@ -57,6 +75,10 @@
         ((ThreadPoolExecutor) executor).allowCoreThreadTimeOut(true);
     }
 
+    public void setWebSocketClient(WebSocketClient wsClient) {
+        this.wsClient = wsClient;
+    }
+
     public void shutdown() {
         executor.shutdown();
         try {
@@ -67,19 +89,33 @@
         }
     }
 
-    public void openLong(WebSocketClient wsClient, Runnable onSuccess) {
-        openPosition(wsClient, config.getQuantity(), OkxEnums.POSSIDE_LONG, OkxEnums.SIDE_BUY, "开多", onSuccess);
+    /**
+     * 异步市价开多。quantity 为正数(如 "1")。
+     *
+     * @param quantity  开仓张数(正数)
+     * @param onSuccess 成交成功回调(可为 null)
+     * @param onFailure 成交失败回调(可为 null)
+     */
+    public void openLong(String quantity, Runnable onSuccess, Runnable onFailure) {
+        openPosition(quantity, OkxEnums.POSSIDE_LONG, OkxEnums.SIDE_BUY, "开多", onSuccess, onFailure);
     }
 
-    public void openShort(WebSocketClient wsClient, Runnable onSuccess) {
-        openPosition(wsClient, config.getQuantity(), OkxEnums.POSSIDE_SHORT, OkxEnums.SIDE_SELL, "开空", onSuccess);
+    /**
+     * 异步市价开空。quantity 为正数(如 "1")。
+     *
+     * @param quantity  开仓张数(正数)
+     * @param onSuccess 成交成功回调(可为 null)
+     * @param onFailure 成交失败回调(可为 null)
+     */
+    public void openShort(String quantity, Runnable onSuccess, Runnable onFailure) {
+        openPosition(quantity, OkxEnums.POSSIDE_SHORT, OkxEnums.SIDE_SELL, "开空", onSuccess, onFailure);
     }
 
-    private void openPosition(WebSocketClient wsClient, String sz, String posSide, String side, String label, Runnable onSuccess) {
+    private void openPosition(String sz, String posSide, String side, String label, Runnable onSuccess, Runnable onFailure) {
         executor.execute(() -> {
             try {
                 TradeRequestParam param = buildParam(side, posSide, sz, OkxEnums.ORDTYPE_MARKET);
-                sendOrder(wsClient, param);
+                sendOrder(param);
 
                 log.info("[TradeExec] {}已发送, 方向:{}, 数量:{}", label, posSide, sz);
                 if (onSuccess != null) {
@@ -87,24 +123,94 @@
                 }
             } catch (Exception e) {
                 log.error("[TradeExec] {}发送失败", label, e);
+                if (onFailure != null) {
+                    onFailure.run();
+                }
             }
         });
     }
 
-    public void placeTakeProfit(WebSocketClient wsClient, String posSide, BigDecimal triggerPrice, String size) {
+    /**
+     * 异步创建止盈条件单(仓位计划止盈止损)。
+     *
+     * <p>通过 OKX WebSocket 发送 algo order(conditional order),服务器监控价格,
+     * 达到触发价后自动平指定张数。
+     *
+     * <h3>orderType 说明</h3>
+     * <ul>
+     *   <li>plan-close-long-position:平多仓,posSide=long, side=sell</li>
+     *   <li>plan-close-short-position:平空仓,posSide=short, side=buy</li>
+     * </ul>
+     *
+     * <p>止盈单创建失败时,立即市价平仓兜底(marketClose)。
+     *
+     * @param triggerPrice 触发价格
+     * @param orderType    stop 类型(plan-close-long-position / plan-close-short-position)
+     * @param size         平仓张数(正数)
+     */
+    public void placeTakeProfit(BigDecimal triggerPrice, String orderType, String size) {
         executor.execute(() -> {
-            try {
-                String side = OkxEnums.POSSIDE_LONG.equals(posSide) ? OkxEnums.SIDE_SELL : OkxEnums.SIDE_BUY;
+            String posSide;
+            String side;
+            if (ORDER_TYPE_CLOSE_LONG.equals(orderType)) {
+                posSide = OkxEnums.POSSIDE_LONG;
+                side = OkxEnums.SIDE_SELL;
+            } else {
+                posSide = OkxEnums.POSSIDE_SHORT;
+                side = OkxEnums.SIDE_BUY;
+            }
 
+            try {
                 TradeRequestParam param = buildParam(side, posSide, size, OkxEnums.ORDTYPE_LIMIT);
                 param.setMarkPx(triggerPrice.toString());
 
                 List<TradeRequestParam> params = new ArrayList<>();
                 params.add(param);
-                sendBatchOrders(wsClient, params);
-                log.info("[TradeExec] 止盈单已发送, 方向:{}, 触发价:{}, 数量:{}", posSide, triggerPrice, size);
+                sendBatchOrders(params);
+                log.info("[TradeExec] 止盈单已发送, 触发价:{}, 类型:{}, size:{}", triggerPrice, orderType, size);
             } catch (Exception e) {
-                log.error("[TradeExec] 止盈单发送失败", e);
+                log.error("[TradeExec] 止盈单发送失败, 触发价:{}, size:{}, 立即市价止盈", triggerPrice, size, e);
+                marketClose(side, posSide, size);
+            }
+        });
+    }
+
+    /**
+     * 市价止盈:在止盈条件单创建失败时立即市价平仓。
+     */
+    private void marketClose(String side, String posSide, String size) {
+        try {
+            TradeRequestParam param = buildParam(side, posSide, size, OkxEnums.ORDTYPE_MARKET);
+            param.setTradeType("3");
+            sendOrder(param);
+            log.info("[TradeExec] 市价止盈已发送, posSide:{}, size:{}", posSide, size);
+        } catch (Exception e) {
+            log.error("[TradeExec] 市价止盈也失败, posSide:{}, size:{}", posSide, size, e);
+        }
+    }
+
+    /**
+     * 异步清除指定合约的所有止盈止损条件单。
+     */
+    public void cancelAllPriceTriggeredOrders() {
+        executor.execute(() -> {
+            try {
+                if (wsClient == null || !wsClient.isOpen()) {
+                    log.warn("[TradeExec] WS未连接,跳过撤销条件单");
+                    return;
+                }
+                JSONArray argsArray = new JSONArray();
+                JSONObject args = new JSONObject();
+                args.put("instId", contract);
+                args.put("algoOrdType", "conditional");
+                argsArray.add(args);
+
+                String connId = OkxWsUtil.getOrderNum("cancel");
+                JSONObject msg = OkxWsUtil.buildJsonObject(connId, "cancel-algos", argsArray);
+                wsClient.send(msg.toJSONString());
+                log.info("[TradeExec] 已发送撤销所有条件单请求");
+            } catch (Exception e) {
+                log.error("[TradeExec] 撤销条件单失败", e);
             }
         });
     }
@@ -112,8 +218,8 @@
     private TradeRequestParam buildParam(String side, String posSide, String sz, String ordType) {
         TradeRequestParam param = new TradeRequestParam();
         param.setAccountName(accountName);
-        param.setInstId(config.getContract());
-        param.setTdMode(config.getMarginMode());
+        param.setInstId(contract);
+        param.setTdMode(marginMode);
         param.setPosSide(posSide);
         param.setOrdType(ordType);
         param.setSide(side);
@@ -123,7 +229,7 @@
         return param;
     }
 
-    private void sendOrder(WebSocketClient wsClient, TradeRequestParam param) {
+    private void sendOrder(TradeRequestParam param) {
         if (wsClient == null || !wsClient.isOpen()) {
             log.warn("[TradeExec] WS未连接,跳过下单");
             return;
@@ -150,7 +256,7 @@
         log.info("[TradeExec] 发送下单: side={}, sz={}", param.getSide(), param.getSz());
     }
 
-    private void sendBatchOrders(WebSocketClient wsClient, List<TradeRequestParam> params) {
+    private void sendBatchOrders(List<TradeRequestParam> params) {
         if (wsClient == null || !wsClient.isOpen() || params == null || params.isEmpty()) {
             log.warn("[TradeExec] WS未连接或参数为空,跳过批量下单");
             return;
diff --git a/src/main/java/com/xcong/excoin/modules/okxApi/okxApi-logic.md b/src/main/java/com/xcong/excoin/modules/okxApi/okxApi-logic.md
new file mode 100644
index 0000000..9e67176
--- /dev/null
+++ b/src/main/java/com/xcong/excoin/modules/okxApi/okxApi-logic.md
@@ -0,0 +1,724 @@
+# OKX API 网格交易策略 — 逻辑文档
+
+---
+
+## 目录
+
+1. [整体架构](#1-整体架构)
+2. [配置层:OkxConfig](#2-配置层okxconfig)
+3. [基础设施层](#3-基础设施层)
+   - [3.1 OkxEnums — 常量定义](#31-okxenums--常量定义)
+   - [3.2 OkxWsUtil — WebSocket 工具类](#32-okxwsutil--websocket-工具类)
+   - [3.3 TradeRequestParam — 下单参数](#33-traderequestparam--下单参数)
+4. [WebSocket 通信层](#4-websocket-通信层)
+   - [4.1 OkxWebSocketClientManager — 入口管理器](#41-okxwebsocketclientmanager--入口管理器)
+   - [4.2 OkxKlineWebSocketClient — WS 连接客户端](#42-okxklinewebsocketclient--ws-连接客户端)
+5. [频道处理器层](#5-频道处理器层)
+   - [5.1 OkxChannelHandler — 处理器接口](#51-okxchannelhandler--处理器接口)
+   - [5.2 OkxCandlestickChannelHandler — K线频道](#52-okxcandlestickchannelhandler--k线频道)
+   - [5.3 OkxPositionsChannelHandler — 持仓频道](#53-okxpositionschannelhandler--持仓频道)
+   - [5.4 OkxAccountChannelHandler — 账户频道](#54-okxaccountchannelhandler--账户频道)
+   - [5.5 OkxOrderInfoChannelHandler — 订单成交频道](#55-okxorderinfochannelhandler--订单成交频道)
+6. [策略执行层](#6-策略执行层)
+   - [6.1 OkxTradeExecutor — 异步下单执行器](#61-okxtradeexecutor--异步下单执行器)
+   - [6.2 OkxGridTradeService — 网格策略核心](#62-okxgridtradeservice--网格策略核心)
+7. [独立启动类:OkxWebSocketClientMain](#7-独立启动类okxwebsocketclientmain)
+8. [完整调用链](#8-完整调用链)
+9. [与 Gate API 的差异对比](#9-与-gate-api-的差异对比)
+
+---
+
+## 1. 整体架构
+
+```
+┌──────────────────────────────────────────────────────────────┐
+│  OkxWebSocketClientManager (Spring @Component)               │
+│    · 读取配置 · 组装所有组件 · 启动 WS 连接 · 生命周期管理    │
+└──────────────────────┬───────────────────────────────────────┘
+                       │
+         ┌─────────────┼─────────────┐
+         ▼             ▼             ▼
+   OkxConfig      OkxGridTradeService   OkxKlineWebSocketClient
+   (Builder配置)    (策略核心)            (WS连接客户端)
+                       │                      │
+                       │              ┌────────┴────────┐
+                       │              │  4 个频道处理器   │
+                       │              ├─────────────────┤
+                       │              │ K线 | 持仓       │
+                       │              │ 账户 | 订单成交   │
+                       │              └────────┬────────┘
+                       │                       │
+                       ▼                       │
+              OkxTradeExecutor                 │
+              (异步下单线程池) ◄────────────────┘
+                       │
+                       ▼
+              通过 WS 发送下单 JSON
+```
+
+**核心数据流**:
+
+```
+K线推送 → OkxGridTradeService.onKline() → 匹配网格队列 → OkxTradeExecutor 异步下单
+持仓推送 → OkxGridTradeService.onPositionUpdate() → 识别基底成交 → 设置止盈单 → 队列就绪 → 激活策略
+订单推送 → OkxGridTradeService.onOrderFilled() → 累计盈亏跟踪 → 达标/超限自动停止
+```
+
+**设计原则**:
+- **包自包含**:`okxApi` 包不依赖任何其他业务包(`okxNewPrice`、`gateApi`、`newPrice`、`blackchain` 等)
+- **WS 回调不阻塞**:所有下单操作通过 `OkxTradeExecutor` 单线程池异步执行
+- **状态机驱动**:策略状态(`WAITING_KLINE → OPENING → ACTIVE → STOPPED`)严格控制执行流程
+
+---
+
+## 2. 配置层:OkxConfig
+
+```
+文件:OkxConfig.java
+```
+
+使用 **Builder 模式**构造配置对象,不可变设计,所有字段 `private final`。
+
+### 配置字段
+
+| 分组 | 字段 | 说明 |
+|------|------|------|
+| **API 密钥** | `apiKey` | OKX API Key |
+| | `secretKey` | OKX Secret Key |
+| | `passphrase` | OKX Passphrase |
+| **合约参数** | `contract` | 合约品种(如 `BTC-USDT-SWAP`) |
+| | `marginMode` | 保证金模式(`cross` 全仓 / `isolated` 逐仓) |
+| | `tickSz` | 价格精度 |
+| | `contractMultiplier` | 合约乘数(用于盈亏计算) |
+| | `leverage` | 杠杆倍数 |
+| **策略参数** | `quantity` | 每次开仓张数 |
+| | `gridRate` | 网格间距比例(如 0.01 = 1%) |
+| | `gridQueueSize` | 网格队列长度 |
+| | `marginRatioLimit` | 保证金占用比例上限 |
+| | `overallTp` | 全局止盈目标(累计盈亏 ≥ 此值停止) |
+| | `maxLoss` | 最大亏损限制(累计盈亏 ≤ 此值停止) |
+| **环境** | `isProduction` | 是否生产环境(决定 WS URL 域名) |
+
+### Builder 方法链
+
+```java
+OkxConfig config = OkxConfig.builder()
+    .apiKey("xxx")
+    .secretKey("xxx")
+    .passphrase("xxx")
+    .contract("BTC-USDT-SWAP")
+    .marginMode("cross")
+    .leverage(1)
+    .quantity("1")
+    .gridRate(new BigDecimal("0.01"))
+    .gridQueueSize(10)
+    .overallTp(new BigDecimal("100"))
+    .isProduction(false)
+    .build();
+```
+
+---
+
+## 3. 基础设施层
+
+### 3.1 OkxEnums — 常量定义
+
+```
+文件:enums/OkxEnums.java
+```
+
+集中管理所有 OKX API 相关字符串常量,替代外部 `CoinEnums` 依赖。
+
+| 常量 | 值 | 用途 |
+|------|-----|------|
+| `INSTTYPE_SPOT` | `SPOT` | 现货 |
+| `INSTTYPE_SWAP` | `SWAP` | 永续合约 |
+| `POSSIDE_LONG` | `long` | 多仓方向 |
+| `POSSIDE_SHORT` | `short` | 空仓方向 |
+| `SIDE_BUY` | `buy` | 买入 |
+| `SIDE_SELL` | `sell` | 卖出 |
+| `ORDTYPE_MARKET` | `market` | 市价单 |
+| `ORDTYPE_LIMIT` | `limit` | 限价单 |
+| `CHANNEL_POSITIONS` | `positions` | 持仓频道 |
+| `CHANNEL_CANDLE` | `candle` + 周期 | K线频道 |
+| `CHANNEL_ACCOUNT` | `account` | 账户频道 |
+| `CHANNEL_ORDERS` | `orders` | 订单频道 |
+| `CHANNEL_ORDERS_ALGO` | `orders-algo` | 策略委托频道 |
+
+---
+
+### 3.2 OkxWsUtil — WebSocket 工具类
+
+```
+文件:OkxWsUtil.java
+```
+
+替代外部 `SSLConfig`、`SignUtils`、`WsParamBuild`、`DateUtil` 等依赖,提供以下静态方法:
+
+| 方法 | 用途 |
+|------|------|
+| `configureSSL(wsClient)` | 为 `WebSocketClient` 配置 SSL(跳过证书验证,仅测试环境) |
+| `generateSignature(timestamp, method, requestPath, body, secretKey)` | OKX 签名算法:HMAC-SHA256 + Base64 |
+| `getOrderNum(side)` | 生成唯一订单 ID(时间戳 + 随机数 + side) |
+| `timestampToDateTime(timestamp)` | 毫秒时间戳 → `yyyy/MM/dd HH:mm:ss` 格式 |
+| `timestampToDateToString(timestamp)` | 毫秒时间戳 → `yyyy/MM/dd` 格式 |
+| `buildJsonObject(connId, channel, args)` | 构建 WS 请求 JSON 对象 |
+| `buildLoginParam(okxConfig)` | 构建登录认证参数(sign + timestamp) |
+
+**签名算法**:
+```
+sign = Base64(HMAC-SHA256(timestamp + "GET" + requestPath + body, secretKey))
+```
+
+---
+
+### 3.3 TradeRequestParam — 下单参数
+
+```
+文件:param/TradeRequestParam.java
+```
+
+纯 POJO,替代外部 `TradeRequestParam` 依赖。
+
+| 字段 | 说明 |
+|------|------|
+| `accountName` | 账户标识 |
+| `instId` | 合约 ID |
+| `tdMode` | 保证金模式(cross/isolated) |
+| `posSide` | 持仓方向(long/short) |
+| `ordType` | 订单类型(market/limit) |
+| `side` | 买卖方向(buy/sell) |
+| `clOrdId` | 客户端订单 ID(唯一) |
+| `sz` | 下单数量 |
+| `markPx` | 标记价格(限价单用) |
+| `tradeType` | 交易类型(1=开仓,3=平仓) |
+
+---
+
+## 4. WebSocket 通信层
+
+### 4.1 OkxWebSocketClientManager — 入口管理器
+
+```
+文件:OkxWebSocketClientManager.java
+```
+
+**Spring `@Component`**,管理完整的 WS 生命周期。
+
+#### 职责
+
+1. **组件组装**:创建 `OkxConfig` → `OkxGridTradeService` → `OkxTradeExecutor`(注入 WS Client)→ 4 个频道处理器 → `OkxKlineWebSocketClient`
+2. **生命周期管理**:
+   - `@PostConstruct init()`:初始化和连接(生产环境)或注册 MBean(测试环境)
+   - `@PreDestroy close()`:优雅关闭(停止策略 → 取消条件单 → 关闭 WS)
+
+#### 初始化流程
+
+```
+init()
+  ├── configMap — 从本地缓存读取账户配置
+  ├── OkxGridTradeService.startGrid()
+  ├── OkxTradeExecutor.setWebSocketClient(wsClient)
+  ├── 创建 4 个频道处理器
+  ├── OkxKlineWebSocketClient.connect()
+  │     ├── 连接 OSKL 公开 WS(K线频道不需要登录)
+  │     ├── 登录私有 WS → 订阅 持仓/账户/订单/策略委托频道
+  │     └── 启动心跳定时器(30s ping/pong)
+  └── isProduction ? 直接启动 : MBean 注册(JMX 手动控制)
+```
+
+---
+
+### 4.2 OkxKlineWebSocketClient — WS 连接客户端
+
+```
+文件:OkxKlineWebSocketClient.java
+```
+
+封装 `java-websocket` 客户端,管理物理连接。
+
+#### 连接架构
+
+- **公开频道 WS**(`wss://ws.okx.com:8443/ws/v5/public` 或模拟盘域名):K线推送不需要登录
+- **私有频道 WS**(`wss://ws.okx.com:8443/ws/v5/private` 或模拟盘域名):需要登录认证,订阅持仓/账户/订单/策略委托频道
+
+#### 连接流程
+
+```
+connect()
+  ├── 1. 创建公开 WS Client → connect()
+  │      └── onOpen → subscribePublicChannels() → 订阅 K线频道
+  ├── 2. 创建私有 WS Client → connect()
+  │      └── onOpen → login() → onLoginSuccess → subscribePrivateChannels()
+  │             ├── 订阅 positions 频道
+  │             ├── 订阅 account 频道
+  │             ├── 订阅 orders 频道
+  │             └── 订阅 orders-algo 频道
+  └── 3. 启动心跳定时器(30s 间隔 ping/pong,60s 超时检测)
+```
+
+#### 断线重连机制
+
+- 最多重连 `MAX_RECONNECT_ATTEMPTS` 次(默认 30)
+- 重连延迟 `RECONNECT_DELAY_MS`(默认 5000ms)
+- 重连成功后重新执行登录 + 订阅流程
+- 兜底机制:重连失败后尝试通过 MBean 重启整个 WS 客户端
+
+#### 消息路由
+
+`onMessage` → 遍历所有 `OkxChannelHandler` → 调用 `handleMessage(response)` 分发到具体处理器
+
+---
+
+## 5. 频道处理器层
+
+### 5.1 OkxChannelHandler — 处理器接口
+
+```
+文件:wsHandler/OkxChannelHandler.java
+```
+
+统一接口,所有频道处理器实现此接口:
+
+```java
+public interface OkxChannelHandler {
+    String getChannelName();                      // 频道名称
+    void subscribe(WebSocketClient ws);           // 订阅
+    void unsubscribe(WebSocketClient ws);         // 取消订阅
+    boolean handleMessage(JSONObject response);   // 处理推送消息
+}
+```
+
+### 5.2 OkxCandlestickChannelHandler — K线频道
+
+```
+文件:wsHandler/handler/OkxCandlestickChannelHandler.java
+```
+
+#### 订阅参数
+
+| 参数 | 值 |
+|------|-----|
+| `channel` | `candle{period}`(如 `candle1H`) |
+| `instId` | 合约 ID(如 `BTC-USDT-SWAP`) |
+
+#### 数据处理
+
+- 解析 `data[0]` → `[ts, o, h, l, c, vol, volCcy, ...]`
+- 提取**收盘价** `c` → 调用 `gridTradeService.onKline(closePrice)`
+- K线为 `candle1H` 时打印整点日志
+
+#### 调用链
+
+```
+onKline(closePrice)
+  ├── WAITING_KLINE → 进入 OPENING 状态,开基底多+空
+  ├── ACTIVE → processShortGrid(closePrice) + processLongGrid(closePrice)
+  └── STOPPED → 仅更新未实现盈亏
+```
+
+### 5.3 OkxPositionsChannelHandler — 持仓频道
+
+```
+文件:wsHandler/handler/OkxPositionsChannelHandler.java
+```
+
+#### 订阅参数
+
+| 参数 | 值 |
+|------|-----|
+| `channel` | `positions` |
+| `instType` | `SWAP` |
+| `instId` | 合约 ID |
+
+#### 数据处理
+
+解析 `data[]` 数组 → 提取 `posSide`、`pos`(数量)、`avgPx`(均价)→ 调用 `gridTradeService.onPositionUpdate(posSide, size, avgPx)`
+
+#### 在策略中的作用
+
+```
+onPositionUpdate() → 区分 3 种场景:
+  1. 仓位从无到有(基底开仓成交)→ 标记 baseOpened → 双基底都成后生成网格队列
+  2. 仓位量增加(网格触发开仓成交)→ 取队列首元素做止盈价 → 设止盈条件单
+  3. 仓位归零(止盈平仓完成)→ 标记 active=false
+```
+
+### 5.4 OkxAccountChannelHandler — 账户频道
+
+```
+文件:wsHandler/handler/OkxAccountChannelHandler.java
+```
+
+#### 订阅参数
+
+| 参数 | 值 |
+|------|-----|
+| `channel` | `account` |
+
+#### 数据处理
+
+解析 `data[]` → 提取 `availBal`(可用余额)、`cashBal`(现金余额)、`eq`(权益)、`upl`(未实现盈亏)、`imr`(保证金占用)
+
+**当前版本**:仅做日志输出,不做业务判断。后续可扩展保证金安全阀功能。
+
+### 5.5 OkxOrderInfoChannelHandler — 订单成交频道
+
+```
+文件:wsHandler/handler/OkxOrderInfoChannelHandler.java
+```
+
+#### 订阅参数
+
+| 参数 | 值 |
+|------|-----|
+| `channel` | `orders` |
+| `instType` | `SWAP` |
+| `instId` | 合约 ID |
+
+#### 数据处理
+
+- 过滤 `state=filled` 且 `accFillSz>0` 的订单
+- 提取 `posSide`、`accFillSz`(成交数量)、`fillPnl`(已实现盈亏)
+- 调用 `gridTradeService.onOrderFilled(posSide, accFillSz, fillPnl)`
+
+#### 在策略中的作用
+
+```
+onOrderFilled()
+  ├── 累计盈亏 += fillPnl
+  ├── 累计盈亏 ≥ overallTp → 策略停止(止盈达标)
+  └── 累计盈亏 ≤ -maxLoss → 策略停止(亏损超限)
+```
+
+---
+
+## 6. 策略执行层
+
+### 6.1 OkxTradeExecutor — 异步下单执行器
+
+```
+文件:OkxTradeExecutor.java
+```
+
+#### 设计目的
+
+WS 消息在回调线程处理,下单操作提交到**独立线程池异步执行**,避免阻塞 WS 回调线程。
+
+#### 线程模型
+
+| 参数 | 值 |
+|------|-----|
+| 核心线程 | 1 |
+| 最大线程 | 1 |
+| 空闲超时 | 60s(`allowCoreThreadTimeOut`) |
+| 队列类型 | `LinkedBlockingQueue` |
+| 队列容量 | 64 |
+| 拒绝策略 | `CallerRunsPolicy`(队列满时由提交线程直接同步执行,形成自然背压) |
+| 守护线程 | 是 |
+
+**单线程的作用**:保证下单顺序(开多 → 开空 → 止盈单),避免并发竞争。
+
+#### 公开方法
+
+| 方法 | 说明 |
+|------|------|
+| `openLong(quantity, onSuccess, onFailure)` | 异步市价开多 |
+| `openShort(quantity, onSuccess, onFailure)` | 异步市价开空 |
+| `placeTakeProfit(triggerPrice, orderType, size)` | 异步创建止盈条件单(通过 `batch-orders` 发送 algo 委托) |
+| `cancelAllPriceTriggeredOrders()` | 撤销所有条件单(`cancel-algos`) |
+| `setWebSocketClient(wsClient)` | 注入 WS 客户端引用 |
+| `shutdown()` | 优雅关闭(等待 10s,超时强制中断) |
+
+#### 止盈兜底机制
+
+```
+placeTakeProfit()
+  ├── 成功 → 发送 batch-orders(algo 条件单)
+  └── 失败 → marketClose() 立即市价平仓兜底
+```
+
+#### 下单方式
+
+所有下单通过 **WebSocket** 发送 JSON(非 REST API),`sendOrder` 构建如下消息:
+
+```json
+{
+  "id": "order_1712345678901_a1b2c3",
+  "op": "order",
+  "args": [{
+    "instId": "BTC-USDT-SWAP",
+    "tdMode": "cross",
+    "clOrdId": "buy_1712345678901_d4e5f6",
+    "side": "buy",
+    "posSide": "long",
+    "ordType": "market",
+    "sz": "1"
+  }]
+}
+```
+
+#### 调用链
+
+```
+OkxGridTradeService.onKline
+  └── executor.openLong() / openShort()     ← 基底双开 + 网格触发
+
+OkxGridTradeService.onPositionUpdate
+  └── executor.placeTakeProfit()             ← 仓位成交后设止盈
+
+OkxGridTradeService.stopGrid
+  └── executor.cancelAllPriceTriggeredOrders()  + shutdown()
+```
+
+---
+
+### 6.2 OkxGridTradeService — 网格策略核心
+
+```
+文件:OkxGridTradeService.java
+```
+
+这是整个包的核心,实现了**多空双开网格交易策略**的所有状态机和网格队列逻辑。
+
+#### 策略状态机
+
+```
+WAITING_KLINE ──(首根K线到达)──▶ OPENING ──(双基底成交)──▶ ACTIVE ──(止盈/止损达标)──▶ STOPPED
+                        ▲                                                         │
+                        └──────────────────(startGrid() 重新启动)──────────────────┘
+```
+
+| 状态 | 含义 |
+|------|------|
+| `WAITING_KLINE` | 等待首根 K 线到达 |
+| `OPENING` | 已收到 K 线,正在开基底仓位(多+空各一单) |
+| `ACTIVE` | 双基底已成交,网格队列已生成,正常交易中 |
+| `STOPPED` | 已停止(止盈达标 / 亏损超限 / 手动停止) |
+
+#### 数据结构
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `shortPriceQueue` | `List<BigDecimal>` | 空仓价格队列(**降序**) |
+| `longPriceQueue` | `List<BigDecimal>` | 多仓价格队列(**升序**) |
+| `shortBaseEntryPrice` | `BigDecimal` | 空仓基底成交价 |
+| `longBaseEntryPrice` | `BigDecimal` | 多仓基底成交价 |
+| `baseLongOpened` | `boolean` | 多仓基底是否已开 |
+| `baseShortOpened` | `boolean` | 空仓基底是否已开 |
+| `cumulativePnl` | `BigDecimal` | 累计已实现盈亏 |
+
+#### 策略完整生命周期
+
+```
+1. startGrid()
+   └── 重置所有状态 → WAITING_KLINE
+
+2. onKline(closePrice) → WAITING_KLINE
+   └── 转为 OPENING → 发送基底多单 + 基底空单
+
+3. onPositionUpdate(posSide, size, entryPrice)
+   ├── 仓位从无到有
+   │   ├── 标记 baseLongOpened / baseShortOpened
+   │   ├── 记录 entryPrice
+   │   ├── 双基底都成交 → tryGenerateQueues() → ACTIVE
+   │   └── 生成网格队列:
+   │       · 空仓队列:entryPrice × (1 - gridRate×1), (1 - gridRate×2), ... 降序排列
+   │       · 多仓队列:entryPrice × (1 + gridRate×1), (1 + gridRate×2), ... 升序排列
+   ├── 仓位量增加(网格触发开仓成交)
+   │   └── 检查队列非空 → 取队列首元素做止盈价 → executor.placeTakeProfit()
+   └── 仓位归零
+       └── 标记 active=false
+
+4. onKline(closePrice) → ACTIVE
+   ├── processShortGrid(closePrice)  ← 空仓网格处理
+   │   ├── 匹配队列中 > closePrice 的元素
+   │   ├── 移除已匹配 → 尾部补充新元素(递减)
+   │   ├── 多仓队列转移(以对方队列首元素为种子生成递减元素)
+   │   ├── 贴近持仓均价过滤(skip)
+   │   ├── 保证金安全检查
+   │   ├── 开空一次
+   │   └── 额外反向开多(价格夹在多/空均价之间且多>空倒挂时)
+   └── processLongGrid(closePrice)   ← 多仓网格处理
+       └── (对称逻辑,方向反转)
+
+5. onOrderFilled(posSide, fillSz, pnl)
+   ├── cumulativePnl += pnl
+   ├── cumulativePnl ≥ overallTp → STOPPED
+   └── cumulativePnl ≤ -maxLoss → STOPPED
+
+6. stopGrid()
+   ├── 状态 → STOPPED
+   ├── cancelAllPriceTriggeredOrders()
+   └── executor.shutdown()
+```
+
+#### 空仓网格处理 `processShortGrid(currentPrice)` 详解
+
+```
+1. 匹配队列元素(空仓队列降序遍历,收集 > currentPrice 的元素)
+   └── 为空 → 直接返回
+
+2. 空仓队列更新
+   ├── 移除 matched 元素
+   └── 尾部补充新元素(尾价 × (1 - gridRate) 循环递减)→ 降序排序
+
+3. 多仓队列转移
+   ├── 以多仓队列首元素(最小价)为种子
+   ├── 生成 matched.size() 个递减元素加入多仓队列
+   ├── 贴近持仓均价过滤:元素与多仓均价差距 < gridRate → skip
+   └── 升序排序,超长截断
+
+4. 保证金安全检查
+   └── 超限 → warn 跳过开仓
+
+5. 开空一次 → executor.openShort()
+
+6. 额外反向开多条件(同时满足):
+   ├── longEntryPrice > shortEntryPrice(多>空倒挂)
+   ├── currentPrice > shortEntryPrice(当前价在空仓均价上方)
+   └── currentPrice < longEntryPrice × (1 - gridRate)(远离多仓均价)
+   └── 满足 → executor.openLong() 额外开多一次
+```
+
+#### 多仓网格处理 `processLongGrid(currentPrice)` 详解
+
+对称逻辑,方向反转。
+
+---
+
+## 7. 独立启动类:OkxWebSocketClientMain
+
+```
+文件:OkxWebSocketClientMain.java
+```
+
+**纯 main 方法启动**,不依赖 Spring 容器。
+
+### 用途
+
+用于**本地测试和调试**,无需启动整个 Spring 应用。
+
+### 启动流程
+
+```java
+public static void main(String[] args) {
+    OkxConfig config = OkxConfig.builder()
+        .apiKey("xxx")
+        .secretKey("xxx")
+        .passphrase("xxx")
+        .contract("BTC-USDT-SWAP")
+        .marginMode("cross")
+        .leverage(1)
+        .quantity("1")
+        .gridRate(new BigDecimal("0.01"))
+        .gridQueueSize(10)
+        .overallTp(new BigDecimal("100"))
+        .isProduction(false)
+        .build();
+
+    OkxGridTradeService service = new OkxGridTradeService(config, "test-account");
+    service.startGrid();
+
+    OkxKlineWebSocketClient wsClient = new OkxKlineWebSocketClient(config, service, ...);
+    wsClient.connect();
+
+    // 注册 JVM 关闭钩子
+    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+        service.stopGrid();
+        wsClient.close();
+    }));
+}
+```
+
+---
+
+## 8. 完整调用链
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│ 1. 启动阶段                                                   │
+├─────────────────────────────────────────────────────────────┤
+│ OkxWebSocketClientManager.init()                             │
+│   ├── new OkxConfig.Builder()...build()                      │
+│   ├── new OkxGridTradeService(config, accountName)           │
+│   │     └── new OkxTradeExecutor(contract, marginMode, name) │
+│   ├── gridTradeService.startGrid() → WAITING_KLINE           │
+│   ├── new OkxCandlestickChannelHandler(instId, candlePeriod, │
+│   │        gridTradeService, config)                          │
+│   ├── new OkxPositionsChannelHandler(instId, gridTradeService)│
+│   ├── new OkxAccountChannelHandler()                         │
+│   ├── new OkxOrderInfoChannelHandler(instId, gridTradeService,│
+│   │        config)                                            │
+│   ├── new OkxKlineWebSocketClient(config, handlers, ...)     │
+│   ├── wsClient.connect()                                     │
+│   │     ├── 连接公开 WS → 订阅 K线频道                        │
+│   │     ├── 连接私有 WS → 登录 → 订阅 持仓/账户/订单/策略委托  │
+│   │     └── 启动心跳定时器                                    │
+│   └── executor.setWebSocketClient(privateWsClient)           │
+└─────────────────────────────────────────────────────────────┘
+
+┌─────────────────────────────────────────────────────────────┐
+│ 2. 运行时数据流                                               │
+├─────────────────────────────────────────────────────────────┤
+│ [K线推送]                                                    │
+│ OkxCandlestickChannelHandler.handleMessage()                 │
+│   └── gridTradeService.onKline(closePrice)                   │
+│         ├── WAITING_KLINE → OPENING                          │
+│         │     ├── executor.openLong(quantity, onSuccess,     │
+│         │     │        onFailure)                             │
+│         │     └── executor.openShort(quantity, onSuccess,    │
+│         │              onFailure)                             │
+│         └── ACTIVE                                           │
+│               ├── processShortGrid(closePrice)               │
+│               │     ├── 匹配队列 → 更新队列 → 转移对方队列    │
+│               │     └── executor.openShort()                  │
+│               └── processLongGrid(closePrice)                │
+│                     └──(对称逻辑)                            │
+│                                                              │
+│ [持仓推送]                                                    │
+│ OkxPositionsChannelHandler.handleMessage()                   │
+│   └── gridTradeService.onPositionUpdate(posSide, size, avgPx)│
+│         ├── 基底成交 → 标记 baseOpened → tryGenerateQueues() │
+│         └── 增量成交 → executor.placeTakeProfit(tp, type, sz)│
+│                                                              │
+│ [订单成交推送]                                                │
+│ OkxOrderInfoChannelHandler.handleMessage()                   │
+│   └── gridTradeService.onOrderFilled(posSide, fillSz, pnl)   │
+│         └── cumulativePnl 累加 → 达标则停止                   │
+└─────────────────────────────────────────────────────────────┘
+
+┌─────────────────────────────────────────────────────────────┐
+│ 3. 停止阶段                                                   │
+├─────────────────────────────────────────────────────────────┤
+│ OkxWebSocketClientManager.close()                            │
+│   ├── gridTradeService.stopGrid()                            │
+│   │     ├── state = STOPPED                                  │
+│   │     ├── executor.cancelAllPriceTriggeredOrders()         │
+│   │     │     └── wsClient.send(cancel-algos)               │
+│   │     └── executor.shutdown()                              │
+│   └── wsClient.close()                                       │
+│         └── 关闭公开WS + 私有WS                               │
+└─────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## 9. 与 Gate API 的差异对比
+
+| 方面 | Gate API (gateApi) | OKX API (okxApi) |
+|------|-------------------|-----------------|
+| **下单方式** | REST API (`FuturesApi.createFuturesOrder`) | WebSocket JSON 消息 (`op: "order"`) |
+| **止盈单** | REST API (`createPriceTriggeredOrder`),`plan-close-*-position` | WS 消息 (`op: "batch-orders"`),`ordType: limit` + `px` 触发价 |
+| **仓位方向** | 正数=开多、负数=开空(size 带符号) | `posSide: long/short` 显式区分,`sz` 始终正数 |
+| **保证金模式** | 无(Gate API 隐含) | `tdMode: cross/isolated` 显式指定 |
+| **客户端订单 ID** | 自动生成(Gate API 隐式处理) | `clOrdId` 显式生成和传入 |
+| **取消条件单** | REST API (`cancelPriceTriggeredOrderList`) | WS 消息 (`op: "cancel-algos"`) |
+| **止损失败兜底** | REST `createFuturesOrder` IOC 市价平仓 | WS 消息 `marketClose()`(`tradeType: "3"`) |
+| **成交识别** | 通过 WS `FuturesOrderBookTicker` 或 REST 查询 | WS `orders` 频道推送 `state=filled` |
+| **API 认证** | HMAC-SHA256 请求头签名(Gate SDK 封装) | HMAC-SHA256 + Base64 WS 登录消息 |
+| **WS 连接** | 单一连接,频道订阅混合 | 双连接:公开 WS(K线)+ 私有 WS(持仓/账户/订单) |
+| **`placeTakeProfit` 签名** | `(triggerPrice, rule, orderType, size)` 多一个 `rule` 参数 | `(triggerPrice, orderType, size)` (OKX 无 rule 概念) |
+| **止盈单下单** | 单条 `FuturesPriceTriggeredOrder` | `batch-orders` 包装(List 格式,但实际传 1 条) |
+| **心跳机制** | 应用层 ping/pong JSON 消息 | `java-websocket` 自带 ping/pong + 60s 超时重连 |
+| **包依赖** | 依赖 Gate SDK (`io.gate.gateapi`) | **完全自包含**,仅依赖 `java-websocket` + `fastjson` + `lombok` |

--
Gitblit v1.9.1