From 7ff32aba4d8d763affa76c68260008bd45605f40 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Tue, 12 May 2026 17:39:44 +0800
Subject: [PATCH] fix(trade): 修复网格交易逻辑并更新生产配置
---
src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md | 42 +++++++++++++++++++++++++++---------------
1 files changed, 27 insertions(+), 15 deletions(-)
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
index 5230301..f3b4128 100644
--- a/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
+++ b/src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
@@ -411,14 +411,17 @@
- allowCoreThreadTimeOut: 60s 空闲后线程回收
**回调设计**:
-- 每个下单方法接受 `onSuccess` 和 `onFailure` 两个 `Runnable`
-- REST 调用成功 → 执行 `onSuccess`(标记基底已开等)
+- `openLong`/`openShort`/`placeTakeProfit` 接受 `onSuccess` 和 `onFailure` 两个 `Runnable`
+- `placeGridLimitOrder` 的 `onSuccess` 为 `Consumer<String>`(接收 orderId)
+- REST 调用成功 → 执行 `onSuccess`(标记基底已开、记录 orderId 等)
- REST 调用失败 → 执行 `onFailure`(当前版本多为 null,依赖 position 推送修正)
| 方法 | 说明 |
|------|------|
| `openLong(qty, onSuccess, onFailure)` | 异步 IOC 市价开多,双回调 |
| `openShort(qty, onSuccess, onFailure)` | 异步 IOC 市价开空,双回调 |
+| `placeGridLimitOrder(price, size, onSuccess, onFailure)` | 异步 GTC 限价单(网格开仓用),onSuccess 接收 orderId |
+| `cancelOrder(orderId)` | 异步取消指定挂单(orderId 为 null 时跳过) |
| `placeTakeProfit(trigger, rule, type, size)` | 异步止盈条件单(plan-close-*-position)。size 为显式平仓张数(正=平空,负=平多),多次调用互不影响 |
| `cancelAllPriceTriggeredOrders()` | 清除所有条件单 |
| `shutdown()` | 等待10秒,超时强制关闭 |
@@ -453,6 +456,10 @@
|------|------|------|
| shortPriceQueue | List\<BigDecimal\> | 空仓价格队列,降序(大→小),容量 gridQueueSize |
| longPriceQueue | List\<BigDecimal\> | 多仓价格队列,升序(小→大),容量 gridQueueSize |
+| longTakeProfitQueue | List\<BigDecimal\> | 多仓止盈队列,升序(小→大),仓位推送时消费 |
+| shortTakeProfitQueue | List\<BigDecimal\> | 空仓止盈队列,降序(大→小),仓位推送时消费 |
+| currentLongOrderId | String | 当前多仓限价单 ID(用于取消旧单) |
+| currentShortOrderId | String | 当前空仓限价单 ID(用于取消旧单) |
| shortBaseEntryPrice | BigDecimal | 基底空头入场价(仅首次记录,用于生成队列) |
| longBaseEntryPrice | BigDecimal | 基底多头入场价(仅首次记录,用于生成队列) |
| shortEntryPrice | BigDecimal | 当前空仓入场价(推送实时更新,加权均价) |
@@ -468,8 +475,8 @@
| initialPrincipal | BigDecimal | 初始本金(启动时账户总资产) |
**回调方法**:
-- `onKline(closePrice)`: 更新 lastKlinePrice → 计算 unrealizedPnl → WAITING_KLINE 时触发基底双开,ACTIVE 时驱动 processShortGrid+processLongGrid
-- `onPositionUpdate(contract, mode, size, entryPrice)`: 记录当前入场价和持仓量 → 基底:首次成交记录入场价、生成队列;非基底:按 quantity 张数创建独立止盈条件单(plan-close-*-position)。无仓位时清空持仓量并标记不活跃
+- `onKline(closePrice)`: 更新 lastKlinePrice → 计算 unrealizedPnl → WAITING_KLINE 时触发基底双开,ACTIVE 时方向区分(closePrice>longPriceQueue[0]→processLongGrid,closePrice<shortPriceQueue[0]→processShortGrid,其余跳过)
+- `onPositionUpdate(contract, mode, size, entryPrice)`: 记录当前入场价和持仓量 → 基底:首次成交记录入场价、生成队列+止盈队列+挂限价单;非基底(仓位增加):按 quantity 为单位计算增量,逐个从止盈队列消费止盈价(队列不足时 entryPrice ± step 兜底),每批挂独立止盈条件单。无仓位时清空持仓量并标记不活跃
- `onPositionClose(contract, side, pnl)`: 累加已实现盈亏,检查停止条件
**processShortGrid / processLongGrid 核心逻辑**:
@@ -477,9 +484,11 @@
| 步骤 | processShortGrid | processLongGrid |
|------|-----------------|-----------------|
| 匹配 | 收集 shortPriceQueue 中 > currentPrice 的元素 | 收集 longPriceQueue 中 < currentPrice 的元素 |
-| 本队补充 | 尾价 − step 循环递减 | 尾价 + step 循环递增 |
-| 对方转移 | 以多仓首元素为种子,递减 step | 以空仓首元素为种子,递增 step |
-| 贴近过滤 | 新增与 longEntryPrice 太近 → 跳过 | 新增与 shortEntryPrice 太近 → 跳过 |
+| 本队补充 | 尾价 − step 循环递减 × matched.size() 次 | 尾价 + step 循环递增 × matched.size() 次 |
+| 对方转移 | 以多仓首元素为种子,递减 step × i | 以空仓首元素为种子,递增 step × i |
+| 止盈队列 | shortTakeProfitQueue.add(新 short[0] − step),降序 | longTakeProfitQueue.add(新 long[0] + step),升序 |
+| 下单 | 取消旧多仓限价单 → 挂新空单(新 short[0]) + 新多单(新 long[0]) | 取消旧空仓限价单 → 挂新多单(新 long[0]) + 新空单(新 short[0]) |
+| 额外反向 | closePrice在[空均价,多均价]间 且 多>空 → openLong | closePrice在[空均价,多均价]间 且 多>空 → openShort |
**未实现盈亏计算** (`updateUnrealizedPnl()`):
@@ -505,10 +514,11 @@
| 方向 | 公式 | order_type | size(平仓张数) | rule |
|------|------|------------|-----------|------|
-| 多头 TP | longPriceQueue[0](多仓队列首元素) | `plan-close-long-position` | `-quantity`(负=平多) | NUMBER_1(≥触发价) |
-| 空头 TP | shortPriceQueue[0](空仓队列首元素) | `plan-close-short-position` | `+quantity`(正=平空) | NUMBER_2(≤触发价) |
+| 多头 TP | longTakeProfitQueue.remove(0),空时兜底 longEntryPrice + step | `plan-close-long-position` | `-quantity`(负=平多) | NUMBER_1(≥触发价) |
+| 空头 TP | shortTakeProfitQueue.remove(0),空时兜底 shortEntryPrice − step | `plan-close-short-position` | `+quantity`(正=平空) | NUMBER_2(≤触发价) |
-> 止盈价取自对应方向队列的首元素(多仓队列升序首=最小价,空仓队列降序首=最高价)。止盈单使用显式张数而非 autoSize。每次网格触发开仓 quantity 张,只为该批张数创建独立的条件单,多个止盈单之间互不覆盖。
+> 止盈价从止盈队列消费。止盈队列由 K线触发时新增元素(新 queue[0] ± step),仓位推送时按每批 quantity 张数逐个消费。
+> 止盈队列空时兜底用当前入场价 ± step。每批挂独立止盈条件单,互不覆盖。
**REST API 调用**:
@@ -522,6 +532,8 @@
| 查账户 | `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/orders` | `FuturesApi.createFuturesOrder()` | price=具体价, tif=GTC(网格开仓用) |
+| 取消订单 | `DELETE /futures/usdt/orders/{order_id}` | `FuturesApi.cancelFuturesOrder()` | 取消指定挂单 |
| 条件单 | `POST /futures/usdt/price_orders` | `FuturesApi.createPriceTriggeredOrder()` | strategy=0, price_type=0, expiration=0, order_type=plan-close-*-position, size=显式张数,多次调用互不冲突 |
**初始化顺序** (`init()`):
@@ -529,11 +541,11 @@
1. 获取用户 ID
2. 查账户 → 记录初始本金 → 如需要切持仓模式
3. 清除旧的止盈止损条件单
-4. 查当前合约所有仓位 → 逐个市价平仓
- - 单向持仓(single): size=相反数, reduce_only=true
- - 双向持仓(dual): size=0, close=false, autoSize=LONG/SHORT, reduce_only=true
-5. 设杠杆
-6. 打印账户余额
+4. 设多/空方向杠杆
+5. 重置策略状态 + 清空队列 + 清空止盈队列 + 清除 orderId
+6. 等待 K 线回调 → 双开基底(市价开多+市价开空,IOC)
+7. 双基底成交 → 生成网格队列 + 止盈队列初始化 + 挂限价多单+空单(GTC) → state=ACTIVE
+8. 异常回退: 10s 内任一基底未成交 → state=STOPPED
```
---
--
Gitblit v1.9.1