Administrator
4 days ago c7cb31dcafe3046f925f17e3d05604b35938199e
src/main/java/com/xcong/excoin/modules/gateApi/gateApi-logic.md
@@ -4,32 +4,47 @@
| 文件 | 类型 | 说明 |
|------|------|------|
| [GateWebSocketClientManager](#gatewebsocketclientmanager) | `@Component` | 启动入口,生命周期管理 |
| [GateKlineWebSocketClient](#gateklinewebsocketclient) | WebSocket 客户端 | K 线 + 仓位数据监听 |
| [GateWebSocketClientManager](#gatewebsocketclientmanager) | `@Component` | Spring 启动入口,生命周期管理 |
| [GateKlineWebSocketClient](#gateklinewebsocketclient) | WebSocket 连接管理 | 连接/心跳/重连/消息路由 |
| [GateGridTradeService](#gategridtradeservice) | 交易服务 | 网格策略 + 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()` |
| `wsHandler/handler/PositionClosesChannelHandler.java` | 私有频道处理器 | 平仓推送解析 → `onPositionClose()` |
---
## 架构总览
```
┌────────────────────────────────────────────────────────────┐
│                  GateWebSocketClientManager                │
│                    (Spring @Component)                     │
│                                                            │
│  @PostConstruct init():                                    │
│    ┌──────────────────────┐   ┌─────────────────────────┐  │
│    │ GateGridTradeService │   │ GateKlineWebSocketClient │  │
│    │  ▶ init()            │   │  ▶ init()                │  │
│    │  ▶ startGrid()       │←──│  ▶ connect()             │  │
│    └──────┬───────────────┘   └───────────┬─────────────┘  │
│           │ REST API                      │ WebSocket       │
│           ▼                               ▼                │
│     Gate Testnet API           Gate Testnet WS             │
│  (https://api-testnet...)   (wss://ws-testnet.gate.com)   │
└────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│                    GateWebSocketClientManager                    │
│                      (Spring @Component)                         │
│                                                                  │
│  @PostConstruct init():                                          │
│    ┌──────────────────────┐   ┌───────────────────────────────┐  │
│    │ GateGridTradeService │   │ GateKlineWebSocketClient       │  │
│    │  ▶ init()            │   │  ▶ addChannelHandler(x3)       │  │
│    │  ▶ startGrid()       │   │  ▶ init()                      │  │
│    └──────┬───────────────┘   └──────────┬────────────────────┘  │
│           │ REST API                     │ WebSocket (委托路由)   │
│           ▼                              ▼                        │
│     Gate Testnet API          Gate Testnet WS                     │
│  (https://api-testnet...)    (wss://ws-testnet.gate.com)         │
│                              ┌──────────────────────┐            │
│                              │ CandlestickHandler    │  → onKline │
│                              │ PositionsHandler      │  → onPos   │
│                              │ PositionClosesHandler │  → onClose │
│                              └──────────────────────┘            │
└──────────────────────────────────────────────────────────────────┘
```
---
@@ -39,22 +54,27 @@
```
WebSocket 推送
├─ futures.candlesticks (update)
│   └─ GateKlineWebSocketClient.processPushDataV2()
├─ futures.candlesticks (update) [公开]
│   └─ CandlestickChannelHandler.handleMessage()
│       ├─ 解析: o/h/l/c/v/a/t/w
│       ├─ 打印 K 线日志
│       └─ GateGridTradeService.onKline(closePx)
│           ├─ 首次 → dualOpenPositions() → 开多 + 开空 + TP 单
│           └─ 后续 → 仅缓存 lastKlinePrice
├─ futures.positions (update) [需 HMAC-SHA512 签名]
│   └─ GateKlineWebSocketClient.processPositionData()
│       ├─ 解析: contract/mode/size/entry_price/history_pnl/realised_pnl
├─ futures.positions (update) [私有,HMAC-SHA512]
│   └─ PositionsChannelHandler.handleMessage()
│       ├─ 解析: contract/mode/size/entry_price
│       └─ GateGridTradeService.onPositionUpdate(...)
│           ├─ size=0 && longActive → reopenLongPosition()
│           ├─ size=0 && shortActive → reopenShortPosition()
│           ├─ size>0 → 确认仓位活跃
│           └─ checkStopConditions(history_pnl)
│           └─ size>0 → 确认仓位活跃
├─ futures.position_closes (update) [私有,HMAC-SHA512]
│   └─ PositionClosesChannelHandler.handleMessage()
│       ├─ 解析: contract/side/pnl
│       └─ GateGridTradeService.onPositionClose(pnl)
│           └─ cumulativePnl += pnl → checkStopConditions()
├─ futures.pong
│   └─ cancelPongTimeout()
@@ -73,12 +93,15 @@
Spring 启动
  → GateWebSocketClientManager.init()
    → GateGridTradeService.init()
      → REST: 查用户ID
      → REST: 查账户 → 如需要切换持仓模式 (dual)
      → REST: 清除旧止盈止损条件单
      → REST: 设杠杆 30x cross
      → REST: 查账户余额
      → REST: 切双向持仓 dual
    → GateKlineWebSocketClient.init()
      → WebSocket: connect()
        → onOpen: subscribe candlesticks + positions + ping
      → REST: 打印账户余额
    → GateKlineWebSocketClient
      → addChannelHandler: Candlestick + Positions + PositionCloses
      → init() → connect()
        → onOpen: 遍历 handlers.subscribe() + sendPing()
    → GateGridTradeService.startGrid()
      → strategyActive = true
```
@@ -86,37 +109,46 @@
### 阶段 2:首次开仓
```
K 线推送 closePrice=80000
  → onKline(80000)
K 线推送 closePrice=4711
  → onKline(4711)
    → dualOpened = true
    → dualOpenPositions()
      → REST: 市价开多 10 张 → longEntryPrice=80000
      → REST: 创建多头止盈单 TP=80000×1.0035=80280
      → REST: 市价开空 10 张 → shortEntryPrice=80000
      → REST: 创建空头止盈单 TP=80000×0.9965=79720
      → REST: 市价开多 10 张 → longEntryPrice=4711
      → REST: 创建多头止盈单 TP=4711×1.0035=4727 (close-long-position)
      → REST: 市价开空 10 张 → shortEntryPrice=4711
      → REST: 创建空头止盈单 TP=4711×0.9965=4694 (close-short-position)
      → longActive=true, shortActive=true
```
### 阶段 3:止盈触发 → 补仓
```
仓位推送: mode=dual_long, size=0  (多头被止盈平掉了)
仓位推送: mode=dual_long, size=0  (多头被服务器止盈平掉了)
  → longActive=true && size=0
    → longActive=false
    → reopenLongPosition()
      → REST: 市价开多 10 张 (用最新 K 线价)
      → REST: 市价补开多 10 张
      → REST: 创建新的多头止盈单
仓位推送: history_pnl=0.12  (未达阈值,继续)
仓位推送: mode=dual_short, size=0  (空头被服务器止盈平掉了)
  → shortActive=true && size=0
    → reopenShortPosition()
      → REST: 市价补开空 10 张
      → REST: 创建新的空头止盈单
```
### 阶段 4:停止
> 注意:只补被平掉的方向(另一方向不受影响),不双方向重新开。补仓时检查 `longActive` / `shortActive` 防重复开仓。
### 阶段 4:停止条件
```
仓位推送: history_pnl ≥ 0.5 (累计盈利达标)
  → strategyActive = false  → 不再补仓
平仓推送: pnl=+0.2
  → cumulativePnl = 0.2, 未达阈值,继续
仓位推送: history_pnl ≤ -7.5 (亏损超限)
  → strategyActive = false  → 不再补仓
平仓推送: pnl=+0.4
  → cumulativePnl = 0.6 ≥ 0.5 → strategyActive=false
平仓推送: pnl=-8
  → cumulativePnl = -8 ≤ -7.5 → strategyActive=false
```
---
@@ -126,14 +158,14 @@
**角色**: Spring Bean 入口,组装并管理所有 Gate 模块组件。
**关键方法**:
- `init()`: 创建 `GateGridTradeService` → 初始化 → 创建 `GateKlineWebSocketClient` → 启动策略
- `init()`: 创建 `GateGridTradeService` → 初始化 → 创建 `GateKlineWebSocketClient` + 注册 3 个 Handler → 启动策略
- `destroy()`: 停止策略 → 关闭 WebSocket
**当前参数**(硬编码在 `init()` 中):
| 参数 | 值 | 说明 |
|------|-----|------|
| 合约 | XAU_USDT | 黄金 |
| 合约 | XAUT_USDT | 黄金(测试网) |
| 杠杆 | 30x | 全仓模式 |
| 持仓模式 | dual | 双向持仓 |
| 网格间距 | 0.0035 | 0.35% |
@@ -145,29 +177,17 @@
## GateKlineWebSocketClient
**角色**: WebSocket 客户端,订阅 Gate 的行情和仓位频道。
**角色**: WebSocket 连接管理器。负责建立连接、心跳检测、指数退避重连。频道逻辑委托给 `GateChannelHandler` 实现类。
**订阅频道**:
**Handler 路由**:
| 频道 | 类型 | 认证 | 用途 |
|------|------|------|------|
| `futures.candlesticks` | 公开 | 否 | 1m K 线数据 |
| `futures.positions` | 私有 | HMAC-SHA512 | 用户仓位更新 |
| `futures.ping` | 公开 | 否 | 应用层心跳 |
| 频道 | Handler | 认证 | 回调 |
|------|---------|------|------|
| `futures.candlesticks` | `CandlestickChannelHandler` | 否 | `onKline(closePx)` |
| `futures.positions` | `PositionsChannelHandler` | HMAC-SHA512 | `onPositionUpdate(mode, size, entryPrice)` |
| `futures.position_closes` | `PositionClosesChannelHandler` | HMAC-SHA512 | `onPositionClose(side, pnl)` |
**签名算法**(`futures.positions` 订阅时使用):
```
message = "channel=futures.positions&event=subscribe&time={秒级时间戳}"
SIGN = Hex(HmacSHA512(apiSecret, message))
```
**连接管理**:
- 心跳: 10 秒超时,每 25 秒检查,超时发 ping
- 重连: 指数退避,最多 3 次,初始 5 秒
- 关闭: 先取消订阅 → 等 500ms → 关闭连接 → 关闭线程池
**消息路由** (`handleWebSocketMessage`):
**消息路由** (`handleMessage`):
| channel | event | 处理 |
|---------|-------|------|
@@ -175,8 +195,38 @@
| — | `subscribe` | 打日志 |
| — | `unsubscribe` | 打日志 |
| — | `error` | 打错误日志 |
| `futures.candlesticks` | `update`/`all` | `processPushDataV2()` |
| `futures.positions` | `update`/`all` | `processPositionData()` |
| 任意 | `update`/`all` | 遍历 channelHandlers → `handler.handleMessage()` |
**签名算法**:
```
message = "channel={channel}&event=subscribe&time={秒级时间戳}"
SIGN = Hex(HmacSHA512(apiSecret.getBytes(UTF-8), message.getBytes(UTF-8)))
```
**连接管理**:
- 心跳: 10 秒超时,每 25 秒检查,超时发 ping
- 重连: 指数退避,最多 3 次,初始 5 秒
- 关闭: 遍历 `handler.unsubscribe()` → 等 500ms → `closeBlocking()` → `sharedExecutor.shutdown()`
---
## GateChannelHandler 接口体系
```
GateChannelHandler (接口)
  ├── CandlestickChannelHandler                (公开频道)
  └── AbstractPrivateChannelHandler (抽象类)   (私有频道基类)
        ├── PositionsChannelHandler
        └── PositionClosesChannelHandler
```
| 方法 | 说明 |
|------|------|
| `getChannelName()` | 返回频道名(如 `"futures.candlesticks"`) |
| `subscribe(ws)` | 发送订阅请求。私有频道自动附加 HMAC-SHA512 签名 |
| `unsubscribe(ws)` | 发送取消订阅请求 |
| `handleMessage(response)` | 解析推送数据并回调 `GateGridTradeService`,返回 `true` 表示已处理 |
---
@@ -199,17 +249,20 @@
                         longActive=true         shortActive=true
                              │                       │
                    仓位推送 size=0             仓位推送 size=0
                   (止盈触发平仓)             (止盈触发平仓)
                              │                       │
                              ▼                       ▼
                       reopenLong()             reopenShort()
                              │                       │
                              └───────────┬───────────┘
                                          │
                              平仓推送 pnl (futures.position_closes)
                                          │
                                    checkStopConditions()
                                          │
                              ┌───────────┴───────────┐
                              ▼                       ▼
                         history_pnl≥0.5       history_pnl≤-7.5
                         cumulativePnl≥0.5   cumulativePnl≤-7.5
                         strategyActive=false  strategyActive=false
```
@@ -217,18 +270,29 @@
| 方向 | 公式 | 触发条件 | order_type | auto_size |
|------|------|----------|------------|-----------|
| 多头 TP | entryPrice × 1.0035 | 最新价 ≥ 触发价 | `close-long-position` | `close_long` |
| 空头 TP | entryPrice × 0.9965 | 最新价 ≤ 触发价 | `close-short-position` | `close_short` |
| 多头 TP | entryPrice × (1 + gridRate) | 最新价 ≥ 触发价 | `close-long-position` | `close_long` |
| 空头 TP | entryPrice × (1 - gridRate) | 最新价 ≤ 触发价 | `close-short-position` | `close_short` |
**REST API 调用**:
| 操作 | API |
|------|-----|
| 设杠杆 | `POST /futures/usdt/positions/{contract}/leverage` |
| 查账户 | `GET /futures/usdt/accounts` |
| 设持仓模式 | `POST /futures/usdt/set_position_mode` |
| 市价下单 | `POST /futures/usdt/orders` (price=0, tif=IOC) |
| 止盈条件单 | `POST /futures/usdt/price_orders` |
| 操作 | API | 方法 |
|------|-----|------|
| 获取用户 ID | `GET /account/detail` | `AccountApi.getAccountDetail()` |
| 切持仓模式 | `POST /futures/{settle}/set_position_mode` | `FuturesApi.setPositionMode()` |
| 设杠杆 | `POST /futures/{settle}/positions/{contract}/leverage` | `FuturesApi.updateContractPositionLeverageCall()` |
| 查账户 | `GET /futures/{settle}/accounts` | `FuturesApi.listFuturesAccounts()` |
| 清除条件单 | `DELETE /futures/{settle}/price_orders` | `FuturesApi.cancelPriceTriggeredOrderList()` |
| 市价下单 | `POST /futures/{settle}/orders` (price=0, tif=IOC) | `FuturesApi.createFuturesOrder()` |
| 止盈条件单 | `POST /futures/{settle}/price_orders` | `FuturesApi.createPriceTriggeredOrder()` |
**初始化顺序** (`init()`):
```
1. 获取用户 ID
2. 查账户 → 如需要切持仓模式
3. 清除旧的止盈止损条件单
4. 设杠杆
5. 打印账户余额
```
---
@@ -240,4 +304,4 @@
## Example.java
Gate SDK 使用示例,展示 `FuturesApi` 的基本用法:获取账户、设置仓位模式、设置杠杆。仅作参考,不参与实际策略运行。
Gate SDK 使用示例,展示 `FuturesApi` 的基本用法。仅作参考,不参与实际策略运行。