From 7fbfa7a21c9cdf15ae33498669581ed4980819cd Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Tue, 19 May 2026 14:42:44 +0800
Subject: [PATCH] ``` fix(gate): 修复网格交易中订单状态更新处理逻辑

---
 src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java                           |  112 +++++-------
 src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java                                    |   68 +++++--
 src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java                                    |   45 +---
 src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java                     |   29 ++-
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java    |   17 -
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/UserTradesChannelHandler.java     |   28 --
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java        |   17 -
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java |   13 -
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java      |   40 ----
 src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java                                     |   61 +++---
 src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java                              |   52 ++---
 src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/OrdersChannelHandler.java         |   20 --
 12 files changed, 195 insertions(+), 307 deletions(-)

diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
index 3d6edfe..9f8ea9a 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateConfig.java
@@ -5,41 +5,42 @@
 import java.util.List;
 
 /**
- * Gate 模块统一配置。
+ * Gate 交易模块全局配置,策略的唯一参数入口。
  *
- * <p>通过 Builder 模式集中管理所有运行参数,避免参数散落在多个文件中。
- * 提供 REST API 和 WebSocket 地址的自动环境切换(测试网/生产网)。
+ * <h3>定位</h3>
+ * 通过 Builder 模式将所有运行参数集中管理,避免策略参数散落在多个类中。
+ * 运行时动态参数(step、gridElements、baseLongTraderParam、baseShortTraderParam)
+ * 由 {@link GateGridTradeService} 在策略执行过程中写入。
  *
- * <h3>关键参数</h3>
+ * <h3>参数分类</h3>
+ * <table>
+ *   <tr><th>类别</th><th>参数</th><th>用途</th></tr>
+ *   <tr><td>认证</td><td>apiKey, apiSecret</td><td>REST/WS 签名认证</td></tr>
+ *   <tr><td>交易标的</td><td>contract, leverage, quantity, contractMultiplier</td><td>合约、杠杆、张数、乘数</td></tr>
+ *   <tr><td>持仓</td><td>marginMode, positionMode</td><td>全仓/逐仓、单向/双向</td></tr>
+ *   <tr><td>网格策略</td><td>gridRate, gridQueueSize, priceScale</td><td>间距比例、队列容量、价格精度(交易所tick)</td></tr>
+ *   <tr><td>止盈止损</td><td>overallTp, maxLoss</td><td>整体止盈/亏损阈值(USDT),触发后策略停止</td></tr>
+ *   <tr><td>风控</td><td>marginRatioLimit, reopenMaxRetries</td><td>保证金占比上限、补仓重试次数</td></tr>
+ *   <tr><td>盈亏计算</td><td>contractMultiplier, unrealizedPnlPriceMode</td><td>合约乘数、未实现盈亏计价模式</td></tr>
+ *   <tr><td>运行时</td><td>step, gridElements, baseLongTraderParam, baseShortTraderParam</td><td>由策略动态填充</td></tr>
+ * </table>
+ *
+ * <h3>priceScale 说明</h3>
+ * 价格精度表示交易所允许的最小价格单位的小数位数:
  * <ul>
- *   <li><b>网格参数</b>:gridRate(比例间距)、step(绝对步长 = shortBaseEntryPrice × gridRate,运行时计算)、
- *       gridQueueSize(队列容量)</li>
- *   <li><b>止盈止损</b>:overallTp(整体止盈 USDT)、maxLoss(最大亏损 USDT)</li>
- *   <li><b>风险控制</b>:marginRatioLimit(保证金占比上限,超限跳过开仓)、leverage(杠杆)、
- *       marginMode(全仓/逐仓)、positionMode(单向/双向)</li>
- *   <li><b>盈亏计算</b>:contractMultiplier(合约乘数)、unrealizedPnlPriceMode(计价模式:最新价/标记价)</li>
+ *   <li>XAU_USDT: tick=0.1 → priceScale=1</li>
+ *   <li>ETH_USDT: tick=0.01 → priceScale=2</li>
  * </ul>
+ * 所有价格计算必须对齐到 tick 整数倍,否则 Gate API 返回
+ * {@code invalid argument: trigger.price price is not an integer multiple of a price unit}。
  *
- * <h3>使用示例</h3>
- * <pre>
- *   GateConfig config = GateConfig.builder()
- *       .apiKey("...")
- *       .apiSecret("...")
- *       .contract("ETH_USDT")
- *       .leverage("100")
- *       .gridRate(new BigDecimal("0.0035"))
- *       .contractMultiplier("0.01")
- *       .isProduction(false)
- *       .build();
- * </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>
+ * <h3>gridElements 生命周期</h3>
+ * <ol>
+ *   <li>项目启动时初始化为空 ArrayList</li>
+ *   <li>{@code tryGenerateQueues()} 中通过 {@code updateGridElements()} 填充,同时触发
+ *       {@link GridElement#rebuildIndex(List)} 建立全局 O(1) 索引</li>
+ *   <li>每次挂单/止盈操作后通过 {@link GridElement#refreshIndices()} 更新索引</li>
+ * </ol>
  *
  * @author Administrator
  */
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
index b1d7814..2f1487b 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -24,79 +24,63 @@
 import com.xcong.excoin.modules.gateApi.wsHandler.handler.PositionsChannelHandler;
 
 /**
- * Gate 网格交易服务 — 策略核心。
+ * 网格交易策略引擎 — 多空对冲网格。
  *
- * <h3>策略概述</h3>
- * 多空双开基底 → 生成价格网格队列 → 条件单监控 → 触发成交后队列动态转移。
- * 每根 K 线更新未实现盈亏(unrealizedPnl),平仓后累加已实现盈亏(cumulativePnl)。
+ * <h3>策略原理</h3>
+ * 以空仓基底入场价(shortBaseEntryPrice)为价格基准,向上/向下各生成一个价格网格队列。
+ * 价格触发网格层级时挂条件单,成交后自动挂止盈单。每笔止盈盈利 = step - minTick。
  *
- * <h3>核心机制</h3>
- * <ul>
- *   <li><b>条件开仓单</b>:使用 Gate API {@code FuturesPriceTriggeredOrder},服务器监控价格,
- *       达到触发价后以市价 IOC 开仓。相比限价单,条件单仅在触发价到达时才执行,避免提前成交。</li>
- *   <li><b>条件单 ID 映射</b>(currentLongOrderIds / currentShortOrderIds):
- *       用同步 Map 管理所有活跃的条件单(订单ID → 止盈价格)。挂条件单时通过回调存入,
- *       订单成交后通过 {@code futures.orders} 推送匹配止盈价并挂止盈单。</li>
- *   <li><b>订单订阅(futures.orders)</b>:订单成交(status=finished, finish_as=filled)时,
- *       通过 {@link #onOrderUpdate(String, String, String)} 从 Map 中取出止盈价,
- *       调用 {@code executor.placeTakeProfit} 创建止盈条件单。</li>
- *   <li><b>反向条件单</b>:当新网格首元素价格夹在多/空持仓均价之间,
- *       且反向持仓张数不超过 3 张时,额外挂一张反向市价单,通过订单订阅自动挂止盈。</li>
- * </ul>
- *
- * <h3>状态机</h3>
+ * <h3>完整生命周期</h3>
  * <pre>
- *   WAITING_KLINE → (首K线) → 异步双开基底
- *
- *   仓位推送(dual_long/dual_short) → 基底成交 → 记录入场价
- *     → 双基底都成交 → 生成队列 + 初始条件单 + 止盈队列 → ACTIVE
- *
- *   ACTIVE:
- *     ├─ 每根K线 → 更新 unrealizedPnl → 方向判断
- *     │    ├─ closePrice > longPriceQueue[0] → processLongGrid
- *     │    └─ closePrice < shortPriceQueue[0] → processShortGrid
- *     ├─ processShortGrid: 匹配空仓队列 → 本队补充 → 挂空仓+多仓条件单(止盈价存入Map)
- *     ├─ processLongGrid: 匹配多仓队列 → 本队补充 → 挂多仓+空仓条件单(止盈价存入Map)
- *     ├─ 订单推送(futures.orders) → onOrderUpdate → Map 匹配止盈价 → 挂止盈条件单
- *     ├─ 仓位推送 → 更新均价/持仓量、仓位减少时处理反向单
- *     ├─ 平仓推送 → 累加 cumulativePnl
- *     ├─ 保证金安全阀 → 超限跳过挂单,队列照常更新
- *     └─ cumulativePnl ≥ overallTp 或 ≤ -maxLoss → STOPPED
+ *   init() → startGrid() → WAITING_KLINE
+ *     ↓
+ *   onKline(首根K线) → OPENING → 异步市价双开基底(开多+开空)
+ *     ↓
+ *   onPositionUpdate() → 基底成交 → baseLongOpened && baseShortOpened
+ *     ↓
+ *   tryGenerateQueues()
+ *     ├── generateShortQueue()   ← 空仓价格队列(降序,从 shortBaseEntryPrice-step 向下)
+ *     ├── generateLongQueue()    ← 多仓价格队列(升序,从 shortBaseEntryPrice+step 向上)
+ *     ├── updateGridElements()   ← 构建 GridElement 列表 + TraderParam + 全局索引
+ *     ├── 挂基座止盈单(ID=0 的 long/short takeProfit)
+ *     └── 挂初始条件单(up=-1 多单, down=1 空单)
+ *     ↓
+ *   state = ACTIVE(每根K线反复执行以下循环)
+ *     ↓
+ *   onKline() → processLongGrid() + processShortGrid()
+ *     ├── 匹配队列元素 → 队列补偿 → 保证金检查
+ *     ├── 首元素方向:挂条件开仓单 → 订单ID + GridElement状态同步
+ *     └── 反向守卫:在 downGrid 位置挂对向单(价格区间+trigger方向校验)
+ *     ↓
+ *   onOrderUpdate()  ← futures.orders / futures.autoorders 推送
+ *     ├── 匹配止盈单ID → 清空止盈状态(已成交)
+ *     └── 匹配挂单ID → 挂止盈条件单 → 止盈ID + GridElement状态同步
+ *     ↓
+ *   onPositionClose() → cumulativePnl 累加
+ *     ├──  ≥ overallTp → STOPPED
+ *     └──  ≤ -maxLoss → STOPPED
  * </pre>
  *
- * <h3>队列转移规则</h3>
- * <ul>
- *   <li><b>空仓队列触发</b>(processShortGrid):matched 元素从空仓队列移除,
- *       尾部递减 step 补充新元素;多仓队列以首元素(最小价)递减 step 生成新元素加入。</li>
- *   <li><b>多仓队列触发</b>(processLongGrid):matched 元素从多仓队列移除,
- *       尾部递增 step 补充新元素;空仓队列以首元素(最高价)递增 step 生成新元素加入。</li>
- *   <li>队列容量超限时截断尾部,保持固定容量。</li>
- * </ul>
- *
- * <h3>止盈机制</h3>
- * <ul>
- *   <li>网格触发时,挂条件单的回调中将订单 ID 和止盈价存入 currentLongOrderIds / currentShortOrderIds Map。</li>
- *   <li>条件单成交后,{@code futures.orders} 推送触发 {@link #onOrderUpdate},
- *       通过订单 ID 取出止盈价,创建止盈条件单(plan-close-*-position)。</li>
- *   <li>止盈条件单:以触发价监控(price_type=最新价,strategy_type=价格触发),
- *       到达后以市价 IOC 平仓(reduce_only=true,price="0")。</li>
- * </ul>
- *
- * <h3>反向条件单条件</h3>
+ * <h3>仓位线动态调整</h3>
  * <pre>
- *   newFirstPrice > shortEntryPrice AND newFirstPrice < longEntryPrice
- *   AND 反向持仓张数 < 3
+ *   onPositionUpdate() 中仓位均价变化后:
+ *     longEntryPrice ↑ → 取消 高于 longEntryPrice 的空仓挂单(避免逆势空单)
+ *     shortEntryPrice ↓ → 取消 低于 shortEntryPrice 的多仓挂单(避免逆势多单)
  * </pre>
- * 满足条件时以 newFirstPrice ± step 为止盈价直接挂市价单,通过订单订阅自动挂止盈。
  *
- * <h3>未实现盈亏公式(正向合约)</h3>
+ * <h3>关键公式</h3>
  * <pre>
- *   多仓: 持仓量 × 合约乘数 × (计价价格 − 开仓均价)
- *   空仓: 持仓量 × 合约乘数 × (开仓均价 − 计价价格)
+ *   step  = shortBaseEntryPrice × gridRate                      ← 网格绝对步长
+ *   minTick = 10^(-priceScale)                                  ← 交易所最小价格单位
+ *   多止盈 = gridPrice + (step - minTick)                       ← 多仓止盈价
+ *   空止盈 = gridPrice - (step - minTick)                       ← 空仓止盈价
+ *   单笔盈利 = (step - minTick) × contractMultiplier × quantity  ← USDT
  * </pre>
- * 计价价格支持切换:{@link GateConfig.PnLPriceMode#LAST_PRICE 最新成交价} 或
- * {@link GateConfig.PnLPriceMode#MARK_PRICE 标记价格}(通过 {@link #setMarkPrice(BigDecimal)} 注入)。
- * 入场价和持仓量由 {@link #onPositionUpdate(String, Position.ModeEnum, BigDecimal, BigDecimal)} 实时更新。
+ *
+ * <h3>线程模型</h3>
+ * 所有 WS 回调(onKline/onPositionUpdate/onOrderUpdate 等)在 WS 回调线程中串行执行。
+ * 下单/撤单操作提交到 GateTradeExecutor 的单线程池异步执行,避免阻塞 WS 线程。
+ * stopGrid() 会将 state 设为 STOPPED,后续所有 WS 回调直接返回不再处理。
  *
  * @author Administrator
  */
@@ -461,7 +445,7 @@
                     List<GridElement> allLongOrders = GridElement.findAllLongOrders(shortEntryPrice);
                     if (CollUtil.isNotEmpty(allLongOrders)){
                         for (GridElement e : allLongOrders) {
-                            executor.cancelOrder(e.getShortOrderId());
+                            executor.cancelOrder(e.getLongOrderId());
                         }
                     }
                 }
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
index 7730ec5..4235df0 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateTradeExecutor.java
@@ -17,45 +17,37 @@
 import java.util.function.Consumer;
 
 /**
- * Gate REST API 执行器。
+ * Gate REST API 异步执行器,所有下单/撤单操作经此类提交。
  *
  * <h3>设计目的</h3>
- * WebSocket 消息在回调线程中处理(如 {@code WebSocketClient} 的 {@code onMessage} 线程)。
- * 下单 REST API 调用可能耗时数百毫秒,若同步执行会阻塞 WS 回调线程,导致心跳超时误判。
- * 本类将所有 REST 调用提交到独立线程池异步执行。
- *
- * <h3>回调设计</h3>
- * 每个下单方法接受 onSuccess/onFailure 两个 Runnable。
- * 基底开仓时 onSuccess 用于标记基底已开,网格触发时通常为 null(成交状态由仓位推送驱动)。
+ * REST API 调用可能耗时数百毫秒,若在 WebSocket 回调线程中同步执行会阻塞消息处理,
+ * 导致心跳超时误判。本类将所有网络 I/O 提交到独立单线程池异步执行。
  *
  * <h3>线程模型</h3>
  * <ul>
- *   <li><b>单线程</b>:保证下单顺序(开多→开空→止盈单),避免并发竞争</li>
- *   <li><b>有界队列 64</b>:防止堆积。极端行情下最多累积 64 个任务</li>
- *   <li><b>CallerRunsPolicy</b>:队列满时由提交线程直接同步执行,形成自然背压</li>
- *   <li><b>allowCoreThreadTimeOut</b>:60s 空闲后线程回收,不浪费资源</li>
+ *   <li><b>单线程 + 有界队列(64)</b> — 保证下单顺序,避免并发竞争</li>
+ *   <li><b>CallerRunsPolicy</b> — 队列满时由提交线程直接执行,形成自然背压</li>
+ *   <li><b>Daemon 线程</b> — 60s 空闲自动回收</li>
  * </ul>
  *
- * <h3>调用链</h3>
- * <pre>
- *   // 基底双开
- *   GateGridTradeService.init → executor.openLong / executor.openShort
+ * <h3>对外接口</h3>
+ * <table>
+ *   <tr><th>方法</th><th>用途</th><th>调用方</th></tr>
+ *   <tr><td>openLong / openShort</td><td>市价 IOC 基底开仓</td><td>onKline(WAITING_KLINE)</td></tr>
+ *   <tr><td>placeConditionalEntryOrder</td><td>挂条件开仓单(价格触发后市价开仓)</td><td>tryGenerateQueues / processShortGrid / processLongGrid</td></tr>
+ *   <tr><td>placeTakeProfit</td><td>挂止盈条件单(plan-close-*-position)</td><td>tryGenerateQueues / onOrderUpdate / onAutoOrder</td></tr>
+ *   <tr><td>cancelOrder</td><td>取消限价单(仓位线调整用)</td><td>onPositionUpdate</td></tr>
+ *   <tr><td>cancelConditionalOrder</td><td>取消单个条件单</td><td>遗留保留</td></tr>
+ *   <tr><td>cancelAllPriceTriggeredOrders</td><td>取消所有条件单(策略停止时)</td><td>stopGrid</td></tr>
+ * </table>
  *
- *   // 网格条件开仓
- *   GateGridTradeService.tryGenerateQueues / processShortGrid / processLongGrid
- *     → executor.placeConditionalEntryOrder(价格触发后市价 IOC 开仓)
- *     → executor.cancelConditionalOrder(取消对方方向旧条件单)
+ * <h3>容错</h3>
+ * <ul>
+ *   <li>止盈单创建失败 → 立即 marketClose() 市价平仓</li>
+ *   <li>取消订单失败 → 仅 warn 日志(可能已成交/已取消)</li>
+ * </ul>
  *
- *   // 止盈
- *   GateGridTradeService.onPositionUpdate → executor.placeTakeProfit(开仓后设止盈条件单)
- *
- *   // 停止
- *   GateGridTradeService.stopGrid → executor.cancelAllPriceTriggeredOrders
- * </pre>
- *
- * <h3>遗留方法(当前策略未使用)</h3>
- * {@link #placeGridLimitOrder(BigDecimal, String, Consumer, Runnable)} 和
- * {@link #cancelOrder(String)} 为旧版限价单策略的遗留方法,保留以备后续使用。
+ * @author Administrator
  */
 @Slf4j
 public class GateTradeExecutor {
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
index def4b82..80b2e45 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GateWebSocketClientManager.java
@@ -14,24 +14,31 @@
 import java.math.BigDecimal;
 
 /**
- * Gate 模块 Spring 入口,组装所有组件并管理生命周期。
+ * Gate 模块 Spring 容器入口 — 组件组装 + 生命周期管理。
  *
- * <h3>启动流程 ({@code @PostConstruct})</h3>
+ * <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>
+ *   <li>{@link GateConfig} — 构建配置(API 密钥、合约、策略参数)</li>
+ *   <li>{@link GateGridTradeService} — init():获取用户 ID → 切双向持仓 → 清旧条件单 → 平仓 → 设杠杆</li>
+ *   <li>{@link GateKlineWebSocketClient} — 注册 6 个频道处理器 → init():建立 WS 连接并订阅</li>
+ *   <li>{@code gridTradeService.startGrid()} — 状态重置,等待首根 K 线</li>
  * </ol>
  *
- * <h3>销毁流程 ({@code @PreDestroy})</h3>
+ * <h3>6 个频道处理器</h3>
  * <ol>
- *   <li>gridTradeService.stopGrid():取消条件单 → 关闭交易线程池</li>
+ *   <li>CandlestickChannelHandler — 公开频道,K线 → onKline()</li>
+ *   <li>PositionsChannelHandler — 私有频道,仓位 → onPositionUpdate()</li>
+ *   <li>PositionClosesChannelHandler — 私有频道,平仓 → onPositionClose()</li>
+ *   <li>OrdersChannelHandler — 私有频道,订单成交 → onOrderUpdate()</li>
+ *   <li>UserTradesChannelHandler — 私有频道,用户成交 → onUserTrade()</li>
+ *   <li>AutoOrdersChannelHandler — 私有频道,条件单状态 → onAutoOrder()</li>
+ * </ol>
+ *
+ * <h3>销毁顺序({@code @PreDestroy})</h3>
+ * <ol>
+ *   <li>gridTradeService.stopGrid():取消所有条件单 → 关闭交易线程池</li>
  *   <li>wsClient.destroy():取消订阅 → 断开 WS → 关闭线程池</li>
  * </ol>
- *
- * <h3>配置</h3>
- * 当前在代码中硬编码测试网参数。切换到生产网只需改为 {@code .isProduction(true)}。
  *
  * @author Administrator
  */
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java b/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java
index 1b1fb96..8543ed9 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/GridElement.java
@@ -7,34 +7,56 @@
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * 网格元素,表示网格交易策略中的一个价格层级。
+ * 网格价格层级,策略的最小操作单元。
  *
- * <p>每个网格层级包含该价格位置上的多仓和空仓挂单信息,
- * 通过编号和网格价格唯一标识一个网格层级。
+ * <h3>定位</h3>
+ * 每个 GridElement 对应网格中的一个价格点,同时持有该点的多仓和空仓挂单状态。
+ * 与传统的"价格队列+Map"模式不同,GridElement 将价格、方向、状态、订单ID 聚合到一个对象中,
+ * 并维护全局静态 HashMap 索引实现 O(1) 双向查询。
  *
- * <h3>关键字段</h3>
- * <ul>
- *   <li><b>编号</b>:网格层级的唯一标识</li>
- *   <li><b>网格价格</b>:该层级对应的触发价格</li>
- *   <li><b>多仓挂单</b>:是否已有多头挂单、多头挂单参数</li>
- *   <li><b>空仓挂单</b>:是否有空头挂单、空头挂单参数</li>
- * </ul>
+ * <h3>ID 体系与链表</h3>
+ * <pre>
+ *   ID ≦ -1:  空仓队列区域(降序),ID 自减,gridPrice 递减
+ *   ID  =  0:  基座位置,gridPrice = shortBaseEntryPrice
+ *   ID ≧  1:  多仓队列区域(升序),ID 自增,gridPrice 递增
+ *
+ *   链表: ... ← -3 ← -2 ← -1 ← 0 → 1 → 2 → 3 → ...
+ *         (通过 upId/downId + INDEX 实现 O(1) 遍历)
+ * </pre>
+ *
+ * <h3>字段分组</h3>
+ * <table>
+ *   <tr><th>类别</th><th>字段</th><th>说明</th></tr>
+ *   <tr><td>标识</td><td>id, gridPrice, upId, downId</td><td>编号、价格、双向链表指针</td></tr>
+ *   <tr><td>多仓订单</td><td>hasLongOrder, longOrderId, longTraderParam</td><td>是否有挂单、订单ID、完整参数</td></tr>
+ *   <tr><td>空仓订单</td><td>hasShortOrder, shortOrderId, shortTraderParam</td><td>是否有挂单、订单ID、完整参数</td></tr>
+ *   <tr><td>止盈</td><td>longTakeProfitOrderId, shortTakeProfitOrderId</td><td>止盈条件单ID</td></tr>
+ * </table>
+ *
+ * <h3>6 个全局 O(1) 索引</h3>
+ * <pre>
+ *   INDEX                 → findById(int)               ID → 元素
+ *   PRICE_INDEX           → findByPrice(BigDecimal)     价格 → 元素
+ *   LONG_ORDER_ID_INDEX   → findByLongOrderId(String)   多仓挂单ID → 元素
+ *   SHORT_ORDER_ID_INDEX  → findByShortOrderId(String)  空仓挂单ID → 元素
+ *   LONG_TP_ORDER_ID_INDEX→ findByLongTakeProfitOrderId(String)  多止盈ID → 元素
+ *   SHORT_TP_ORDER_ID_INDEX→ findByShortTakeProfitOrderId(String) 空止盈ID → 元素
+ * </pre>
+ * 索引通过 {@link #rebuildIndex(List)}(全量重建)或 {@link #refreshIndices()}(增量刷新)
+ * 维护,每次操作后自动打印全量网格状态到控制台。
+ *
+ * <h3>何时填充 TraderParam</h3>
+ * 初始化时 {@code updateGridElements()} 为每个元素预填充 longTraderParam 和 shortTraderParam
+ * (含 direction/entryPrice/takeProfitPrice/quantity),订单ID字段在挂单成功后由
+ * {@link GateGridTradeService} 的 4 个辅助方法写入。
  *
  * <h3>使用示例</h3>
  * <pre>
- *   GridElement element = GridElement.builder()
- *       .id(1)
- *       .gridPrice(new BigDecimal("2300.0"))
- *       .build();
- *
- *   // 挂多仓单
- *   TraderParam longParam = TraderParam.builder()
- *       .direction(TraderParam.Direction.LONG)
- *       .entryPrice(new BigDecimal("2293.7"))
- *       .takeProfitPrice(new BigDecimal("2301.6"))
- *       .build();
- *   element.setHasLongOrder(true);
- *   element.setLongTraderParam(longParam);
+ *   GridElement elem = GridElement.findById(1);
+ *   boolean hasLong = elem.isHasLongOrder();           // 是否挂了多单
+ *   BigDecimal tpPrice = elem.getLongTraderParam().getTakeProfitPrice();  // 止盈价
+ *   elem.getUp();     // 上一个网格(O(1))
+ *   elem.getDown();   // 下一个网格(O(1))
  * </pre>
  *
  * @author Administrator
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java b/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java
index bce7886..08ba24a 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/TraderParam.java
@@ -3,38 +3,27 @@
 import java.math.BigDecimal;
 
 /**
- * 网格交易单参数,封装单笔条件开仓单及其止盈单的完整状态。
+ * 单笔挂单的完整参数,封装条件开仓单及止盈单的状态。
  *
- * <p>每笔挂单对应的参数独立存储为一个 TraderParam 实例,
- * 用于追踪条件开仓单和止盈条件单的挂单状态、价格位置及订单 ID。
+ * <h3>定位</h3>
+ * 每个 GridElement 内嵌两个 TraderParam(longTraderParam / shortTraderParam),
+ * 分别记录该价格层级上多仓和空仓的挂单参数。所有字段通过 getter/setter
+ * 在挂单/成交/止盈各阶段逐步填充。
  *
- * <h3>关键字段</h3>
- * <ul>
- *   <li><b>方向</b>:多 / 空,决定挂单和止盈的触发方向</li>
- *   <li><b>价格</b>:挂单价(条件开仓触发价)、止盈价(止盈触发价)</li>
- *   <li><b>挂单状态</b>:挂单价是否挂成功、止盈价是否挂成功</li>
- *   <li><b>网格位置</b>:挂单价网格位置、止盈价网格位置(用于定位在价格队列中的索引)</li>
- *   <li><b>订单ID</b>:挂单订单 ID、止盈订单 ID(用于取消和匹配)</li>
- * </ul>
+ * <h3>字段分组</h3>
+ * <table>
+ *   <tr><th>类别</th><th>字段</th><th>生命周期</th></tr>
+ *   <tr><td>开仓准备</td><td>direction, entryPrice, quantity</td><td>updateGridElements() 预填充</td></tr>
+ *   <tr><td>止盈预定</td><td>takeProfitPrice</td><td>updateGridElements() 预填充(entryPrice ± (step - minTick))</td></tr>
+ *   <tr><td>挂单确认</td><td>entryOrderPlaced, entryOrderId</td><td>条件单挂成功后由 longEntryTraderIdParam 等写入</td></tr>
+ *   <tr><td>止盈确认</td><td>takeProfitPlaced, takeProfitOrderId</td><td>止盈单挂成功后由 longTakeProfitTraderIdParam 等写入</td></tr>
+ *   <tr><td>定位</td><td>entryGridPosition, takeProfitGridPosition</td><td>当前策略中由 upId/downId 替代</td></tr>
+ * </table>
  *
- * <h3>使用示例</h3>
+ * <h3>盈利公式(正向合约)</h3>
  * <pre>
- *   TraderParam param = TraderParam.builder()
- *       .direction(Direction.LONG)
- *       .entryPrice(new BigDecimal("2293.7"))
- *       .takeProfitPrice(new BigDecimal("2301.6"))
- *       .quantity("1")
- *       .entryGridPosition(3)
- *       .takeProfitGridPosition(4)
- *       .build();
- *
- *   // 挂单成功后更新
- *   param.setEntryOrderPlaced(true);
- *   param.setEntryOrderId("12345");
- *
- *   // 止盈单挂成功后更新
- *   param.setTakeProfitPlaced(true);
- *   param.setTakeProfitOrderId("12346");
+ *   多仓止盈盈利 = takeProfitPrice - entryPrice = (entryPrice + step - minTick) - entryPrice = step - minTick
+ *   空仓止盈盈利 = entryPrice - takeProfitPrice = entryPrice - (entryPrice - step + minTick) = step - minTick
  * </pre>
  *
  * @author Administrator
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java
index 4e41e0c..1889761 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/AbstractPrivateChannelHandler.java
@@ -11,22 +11,7 @@
 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}
+ * 私有频道 WS 处理器的抽象基类,封装 HMAC-SHA512 签名认证与订阅/取消订阅逻辑。
  *
  * @author Administrator
  */
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java
index e05520a..90000a6 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/CandlestickChannelHandler.java
@@ -11,21 +11,14 @@
 import java.math.BigDecimal;
 
 /**
- * K 线(Candlestick)频道处理器。
+ * K 线频道处理器(futures.candlesticks)— 策略的唯一价格时间驱动源。
  *
- * <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>
+ * 订阅 1 分钟 K 线实时推送,每收到一根 K 线(不等待完结)即触发
+ * {@link GateGridTradeService#onKline(BigDecimal)},由策略引擎决定是否开仓/止盈。
  *
  * <h3>订阅格式</h3>
- * payload: {@code ["1m", contract]}
+ * 公开频道,无需认证签名。payload: {@code ["1m", contract]}。
  *
  * @author Administrator
  */
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/OrdersChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/OrdersChannelHandler.java
index f561a65..3d15c45 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/OrdersChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/OrdersChannelHandler.java
@@ -7,24 +7,8 @@
 import lombok.extern.slf4j.Slf4j;
 
 /**
- * 订单频道处理器(futures.orders)。
- *
- * <h3>数据用途</h3>
- * 订阅订单更新推送。当订单状态变为 finished 且成交方式为 filled 时,
- * 通过订单 ID 匹配 {@code currentShortOrderIds} 中存储的止盈价格,自动挂止盈单。
- *
- * <h3>关键推送字段</h3>
- * <ul>
- *   <li>id:订单 ID</li>
- *   <li>contract:合约名称</li>
- *   <li>status:订单状态(open / finished)</li>
- *   <li>finish_as:订单结束方式(filled / cancelled / ioc 等)</li>
- *   <li>price:订单价格</li>
- *   <li>size:订单大小</li>
- * </ul>
- *
- * <h3>回调数据(传给 GateGridTradeService)</h3>
- * orderId (String), status (String), finishAs (String)
+ * 订单频道处理器(futures.orders),接收订单更新推送并回调 {@link GateGridTradeService#onOrderUpdate}。
+ * 回调内部通过 {@code GridElement.findByLongOrderId / findByShortOrderId} 匹配网格订单。
  *
  * @author Administrator
  */
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java
index ef61db7..c58ea39 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionClosesChannelHandler.java
@@ -9,18 +9,7 @@
 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>
- * 平仓盈亏来自服务器端,不受本地计算误差影响。这是策略停止的唯一盈亏判断来源。
+ * 平仓频道处理器(futures.position_closes),接收平仓盈亏推送并回调 {@link GateGridTradeService#onPositionClose}。
  *
  * @author Administrator
  */
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java
index 8f99d4a..9608782 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/PositionsChannelHandler.java
@@ -10,45 +10,7 @@
 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} 独立处理。
- * 止盈条件单由服务端自动触发平仓,本频道不负责开仓操作。
+ * 仓位频道处理器(futures.positions),接收仓位更新推送并回调 {@link GateGridTradeService#onPositionUpdate}。
  *
  * @author Administrator
  */
diff --git a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/UserTradesChannelHandler.java b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/UserTradesChannelHandler.java
index 282df7a..b3d3cc3 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/UserTradesChannelHandler.java
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/wsHandler/handler/UserTradesChannelHandler.java
@@ -9,27 +9,7 @@
 import java.math.BigDecimal;
 
 /**
- * 用户私有成交频道处理器(futures.usertrades)。
- *
- * <h3>数据用途</h3>
- * 订阅用户私有成交更新推送。当订单成交时,获得真实的成交价格、手续费等信息,
- * 可用于计算实际盈亏。
- *
- * <h3>关键推送字段</h3>
- * <ul>
- *   <li>id:交易 ID</li>
- *   <li>contract:合约名称</li>
- *   <li>order_id:订单 ID</li>
- *   <li>size:成交数量</li>
- *   <li>price:成交价格</li>
- *   <li>role:用户角色(maker/taker)</li>
- *   <li>fee:手续费</li>
- *   <li>point_fee:点卡手续费</li>
- *   <li>text:订单自定义信息</li>
- * </ul>
- *
- * <h3>回调数据(传给 GateGridTradeService)</h3>
- * contract (String), orderId (String), price (BigDecimal), size (String), role (String), fee (BigDecimal)
+ * 用户私有成交频道处理器(futures.usertrades),接收成交推送并回调 {@link GateGridTradeService#onUserTrade}。
  *
  * @author Administrator
  */
@@ -69,9 +49,9 @@
                 String text = trade.getString("text");
                 log.info("[{}] 成交更新, id:{}, order_id:{}, price:{}, size:{}, role:{}, fee:{}, text:{}",
                         CHANNEL_NAME, id, orderId, price, size, role, fee, text);
-                if (getGridTradeService() != null) {
-                    getGridTradeService().onUserTrade(contract, orderId, price, size, role, fee);
-                }
+//                if (getGridTradeService() != null) {
+//                    getGridTradeService().onUserTrade(contract, orderId, price, size, role, fee);
+//                }
             }
         } catch (Exception e) {
             log.error("[{}] 处理数据失败", CHANNEL_NAME, e);

--
Gitblit v1.9.1