edit | blame | history | raw

Gate Api 模块 — 网格交易系统

文件列表

文件 类型 说明
GateWebSocketClientManager @Component Spring 启动入口,组装组件 + 生命周期
GateConfig 配置 Builder 模式:API 密钥、合约、策略参数、环境切换
GateKlineWebSocketClient WS 连接管理 连接/心跳/重连/消息路由
GateGridTradeService 交易服务 网格队列策略 + 保证金安全阀 + 盈亏管理 + 额外反向开仓
GateTradeExecutor 异步执行器 独立线程池执行 REST 下单,成功/失败双回调
GateWebSocketClientMain main 入口 独立测试启动
Example.java 示例 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 → 方向区分: closePrice>longPriceQueue[0]→processLongGrid,
│               closePrice<shortPriceQueue[0]→processShortGrid, 其余跳过(一个K线只触发一个方向)
│
├─ 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)
│           ├─ 有仓位: 标记活跃,首次成交记录入场价
│           │   ├─ 基底开仓 → 首次成交 → 记录基底入场价 → 双基底都成交后生成网格队列+挂限价单
│           │   └─ 网格开仓 → 仓位增加时按 quantity 为单位计算增量,逐个从止盈队列消费止盈价;
│           │       止盈队列不足时用 entryPrice ± step 兜底
│           └─ 无仓位(size=0): 标记不活跃
│
├─ futures.position_closes (私有, HMAC-SHA512)
│   └─ PositionClosesChannelHandler
│       └─ gridTradeService.onPositionClose(contract, side, pnl)
│           └─ cumulativePnl += pnl → checkStopConditions()
│
└─ 所有下单操作
    └─ GateTradeExecutor (单线程 + 64队列 + CallerRunsPolicy)
        ├─ openLong/Short(qty, onSuccess, onFailure)
        ├─ placeGridLimitOrder(price, size, onSuccess, onFailure) → 限价GTC单
        ├─ cancelOrder(orderId) → 取消指定挂单
        └─ 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
     │                        │                 ├─ 保证金超限 → 跳过下单,队列照常更新(止盈队列仍更新)
     │                        │                 ├─ 方向区分 → processShortGrid 或 processLongGrid(二者选一)
     │                        │                 ├─ 网格触发 → 匹配队列→更新队列→止盈队列新增元素→
     │                        │                 │   取消对方旧限价单→挂新多空限价单→额外反向开仓
     │                        │                 └─ 多>空且价格夹在中间 → 额外反向开仓
     ▼                        ▼
   STOPPED  ←──────────────────┘
状态 含义
WAITING_KLINE 等待首次K线价格
OPENING 正在异步开基底多空仓位(已提交到GateTradeExecutor)
ACTIVE 网格队列激活,K线触发网格元素 → 开仓+止盈
STOPPED 停止(盈利达标 / 亏损超限)

策略核心:网格队列机制

概述

策略采用"基底 + 价格网格队列"模式:先开一对基底多空仓位,然后以基底入场价为基准生成价格队列和止盈队列。每当K线穿破队列元素,匹配后更新队列、补充止盈队列、挂限价单。仓位推送时从止盈队列消费止盈价并挂止盈条件单。

基底开仓

K线到达 → 双开基底(市价开多 + 市价开空)
  → 成交回调: baseLongOpened=true, longActive=true
  → 成交回调: baseShortOpened=true, shortActive=true
  → 两者都成交 → generateShortQueue() + generateLongQueue() + 止盈队列初始化 + 限价单挂单 → state=ACTIVE

止盈队列初始化

基底队列生成后,两个止盈队列各填入一个元素:

止盈队列 初始元素 排序
多仓止盈队列 longTakeProfitQueue longPriceQueue[0] + step 升序(小→大)
空仓止盈队列 shortTakeProfitQueue shortPriceQueue[0] - step 降序(大→小)

初始限价单挂单

队列生成后立即用队列首元素挂两个 GTC 限价单:

方向 价格 数量
多仓限价单 longPriceQueue[0] +quantity
空仓限价单 shortPriceQueue[0] −quantity

网格队列生成

以空头基底入场价 shortBaseEntryPrice 为唯一基准,计算绝对步长 step = shortBaseEntryPrice × gridRate(保留1位小数),存入 config。

两个队列均从 shortBaseEntryPrice 出发,按 step 绝对偏移生成 N 个价格(N = gridQueueSize,默认50):

队列 计算方式 排序
空仓队列 shortPriceQueue 首元素 = shortBaseEntryPrice − step,后续依次 −step (i=0..N-1) 降序(大→小)
多仓队列 longPriceQueue 首元素 = shortBaseEntryPrice + step,后续依次 +step (i=0..N-1) 升序(小→大)

K线触发网格

K线到达(ACTIVE状态):
│
├─ closePrice > longPriceQueue[0] → processLongGrid(价格涨超队列首=最小价)
│   ├─ 匹配: 收集所有 < closePrice 的多仓队列元素(升序,一旦遇≥即停止)
│   ├─ 多仓队列: 移除 matched,尾部补充(尾价 + step 循环递增)
│   ├─ 空仓队列转移:
│   │   ├─ 以空仓队列首元素(最高价)为种子
│   │   ├─ 生成 matched.size() 个递增元素: seed + step × i
│   │   └─ 降序排列,截断到 gridQueueSize
│   ├─ 止盈队列: longTakeProfitQueue.add(新 longPriceQueue[0] + step) → 升序排列
│   ├─ 下单(队列已更新,避免竞态):
│   │   ├─ 保证金检查: positionInitialMargin / initialPrincipal < marginRatioLimit(20%)
│   │   │   ├─ 安全 → 取消旧空仓限价单(cancelOrder) → 挂新多仓限价单 + 空仓限价单
│   │   │   └─ 超限 → 跳过下单
│   └─ 额外反向: closePrice 在多/空均价之间 → openShort
│
└─ closePrice < shortPriceQueue[0] → processShortGrid(价格跌穿队列首=最高价)
    ├─ 匹配: 收集所有 > closePrice 的空仓队列元素(降序,一旦遇≤即停止)
    ├─ 空仓队列: 移除 matched,尾部补充(尾价 − step 循环递减)
    ├─ 多仓队列转移:
    │   ├─ 以多仓队列首元素(最小价)为种子
    │   ├─ 生成 matched.size() 个递减元素: seed − step × i
    │   └─ 升序排列,截断到 gridQueueSize
    ├─ 止盈队列: shortTakeProfitQueue.add(新 shortPriceQueue[0] − step) → 降序排列
    ├─ 下单(队列已更新,避免竞态):
    │   ├─ 保证金检查: 同上
    │   │   ├─ 安全 → 取消旧多仓限价单(cancelOrder) → 挂新空仓限价单 + 多仓限价单
    │   │   └─ 超限 → 跳过下单
    └─ 额外反向: closePrice 在多/空均价之间 → openLong

closePrice 既不 > longPriceQueue[0] 也不 < shortPriceQueue[0] → 跳过本次K线

一个K线只触发一个方向。 例如 closePrice=2295 时 longPriceQueue[0]=2277.9<2295 → 仅触发 processLongGrid。
只取消对方旧单。 触发方向对应的旧限价单大概率已成交,只取消对方未成交的旧限价单。
限价单为 GTC,挂新单前先取消旧单解决堆积问题。

队列转移规则

触发后**不再简单复制** matched 元素到对方队列,而是以对方队列首元素为种子,按绝对步长 step 生成新元素:

触发方向 目标队列 种子元素 生成公式 排序
空仓触发 → 多仓队列 多仓队列首元素(最小价) 种子 − step × i 升序
多仓触发 → 空仓队列 空仓队列首元素(最高价) 种子 + step × i 降序

额外反向开仓条件

当触发价夹在多/空持仓均价之间,且多仓均价大于空仓均价(多>空倒挂)时,额外反向开仓一次:

触发方向 额外操作 条件
空仓队列触发 额外开多 shortEntryPrice > 0 && longEntryPrice > shortEntryPrice && shortEntryPrice < currentPrice < longEntryPrice
多仓队列触发 额外开空 shortEntryPrice > 0 && longEntryPrice > shortEntryPrice && shortEntryPrice < currentPrice < longEntryPrice

条件统一简化:两个方向共用同一条件 shortEntryPrice < currentPrice < longEntryPrice,即当前价夹在多仓均价和空仓均价之间。

队列转移示意

ETH_USDT, gridRate=0.0035, shortBaseEntryPrice=2270, step=2270×0.0035≈7.9, gridQueueSize=4:

初始状态:
  空仓队列: [2262.1, 2254.2, 2246.3, 2238.4]  (降序, shortBaseEntryPrice−step 起递减)
  多仓队列: [2277.9, 2285.8, 2293.7, 2301.6]  (升序, shortBaseEntryPrice+step 起递增)
  多止盈队列: [2285.8]  (longPriceQueue[0]+step)
  空止盈队列: [2254.2]  (shortPriceQueue[0]−step)

价格涨到 2290 → processLongGrid 触发:
  匹配: [2277.9, 2285.8](都 < 2290)

  多仓队列: 移除[2277.9,2285.8] → [2293.7,2301.6]
    补充: max=2301.6 → 2301.6+7.9=2309.5 → 2309.5+7.9=2317.4
    → [2293.7, 2301.6, 2309.5, 2317.4]

  空仓队列转移:
    种子=空仓首元素 2262.1
    生成: 2262.1+7.9=2270.0, 2262.1+7.9×2=2277.9
    空仓队列: [2262.1, 2270.0, 2277.9, 2254.2, 2246.3, 2238.4] → 截断到4 → [2277.9, 2270.0, 2262.1, 2254.2]

  止盈队列: longTakeProfitQueue.add(2293.7+7.9) = 2301.6
    → [2285.8, 2301.6]  (升序)

  挂单: 取消旧空仓限价单 → 挂新多单(2293.7) + 新空单(2277.9)

仓位推送(多单 2277.9 成交):
  long size: 1→2,增量1
  消费止盈队列: longTakeProfitQueue.remove(0) = 2285.8
  挂止盈单: tp=2285.8, size=1, plan-close-long-position

策略时序

阶段 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 → 方向区分(一个K线只触发一个方向)

仓位推送(每次开仓成交后自动触发):
  → DUAL_LONG, size>0, 非基底:
      按 quantity 为单位计算仓位增量(newUnits),逐个消费止盈队列:
        for each newUnit:
          tpPrice = longTakeProfitQueue.remove(0) 或 (止盈队列为空时) longEntryPrice + step 兜底
          executor.placeTakeProfit(tpPrice, NUMBER_1, plan-close-long-position, -quantity)
  → DUAL_SHORT, size<0, 非基底:
      同上方式消费空仓止盈队列:
        for each newUnit:
          tpPrice = shortTakeProfitQueue.remove(0) 或 shortEntryPrice - step 兜底
          executor.placeTakeProfit(tpPrice, NUMBER_2, plan-close-short-position, quantity)

K线触发网格后:
  → processLongGrid: 限价多单成交后,仓位推送触发止盈队列消费
  → processShortGrid: 限价空单成交后,仓位推送触发止盈队列消费

额外反向开仓(多>空倒挂时):
  → 统一条件: shortEntryPrice < currentPrice < longEntryPrice
  → 空仓触发 → 额外开多(openLong)
  → 多仓触发 → 额外开空(openShort)

阶段 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%(用于过滤阈值计算)
step 运行时计算 网格绝对步长 = shortBaseEntryPrice × gridRate(队列元素生成用)
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 空闲后线程回收

回调设计:
- openLong/openShort/placeTakeProfit 接受 onSuccessonFailure 两个 Runnable
- placeGridLimitOrderonSuccessConsumer<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秒,超时强制关闭

止盈条件单 order_type 说明

order_type 用途 size 语义
plan-close-long-position 部分/全部平多仓 size<0 表示平多仓张数
plan-close-short-position 部分/全部平空仓 size>0 表示平空仓张数

为何不用 close-*-positionclose-long-positionclose-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
longTakeProfitQueue List<BigDecimal> 多仓止盈队列,升序(小→大),仓位推送时消费
shortTakeProfitQueue List<BigDecimal> 空仓止盈队列,降序(大→小),仓位推送时消费
currentLongOrderId String 当前多仓限价单 ID(用于取消旧单)
currentShortOrderId String 当前空仓限价单 ID(用于取消旧单)
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 时方向区分(closePrice>longPriceQueue[0]→processLongGrid,closePrice<shortPriceQueue[0]→processShortGrid,其余跳过)
- onPositionUpdate(contract, mode, size, entryPrice): 记录当前入场价和持仓量 → 基底:首次成交记录入场价、生成队列+止盈队列+挂限价单;非基底(仓位增加):按 quantity 为单位计算增量,逐个从止盈队列消费止盈价(队列不足时 entryPrice ± step 兜底),每批挂独立止盈条件单。无仓位时清空持仓量并标记不活跃
- onPositionClose(contract, side, pnl): 累加已实现盈亏,检查停止条件

processShortGrid / processLongGrid 核心逻辑:

步骤 processShortGrid processLongGrid
匹配 收集 shortPriceQueue 中 > currentPrice 的元素 收集 longPriceQueue 中 < currentPrice 的元素
本队补充 尾价 − 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()):

正向合约公式(含合约乘数):

方向 公式
多仓 持仓量 × contractMultiplier × (计价价格 − 开仓均价)
空仓 持仓量(绝对值)× contractMultiplier × (开仓均价 − 计价价格)

计价价格由 unrealizedPnlPriceMode 决定:
- LAST_PRICE:使用最新成交价(lastKlinePrice,每根 K 线更新)
- MARK_PRICE:使用标记价格(通过 setMarkPrice() 外部注入,如未注入则回退到最新成交价)

入场价和持仓量由 onPositionUpdate 实时推送更新。

保证金安全阀 (isMarginSafe()):
- 实时查询 positionInitialMargin / initialPrincipal
- 比例 ≥ marginRatioLimit(默认20%)→ 跳过开仓,队列照常更新
- REST 查询失败 → 默认放行(避免因查询异常阻塞策略)

止盈计算:

方向 公式 order_type size(平仓张数) rule
多头 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(≤触发价)

止盈价从止盈队列消费。止盈队列由 K线触发时新增元素(新 queue[0] ± step),仓位推送时按每批 quantity 张数逐个消费。
止盈队列空时兜底用当前入场价 ± step。每批挂独立止盈条件单,互不覆盖。

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/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()):
1. 获取用户 ID 2. 查账户 → 记录初始本金 → 如需要切持仓模式 3. 清除旧的止盈止损条件单 4. 设多/空方向杠杆 5. 重置策略状态 + 清空队列 + 清空止盈队列 + 清除 orderId 6. 等待 K 线回调 → 双开基底(市价开多+市价开空,IOC) 7. 双基底成交 → 生成网格队列 + 止盈队列初始化 + 挂限价多单+空单(GTC) → state=ACTIVE 8. 异常回退: 10s 内任一基底未成交 → state=STOPPED


GateWebSocketClientMain

独立 main() 方法入口,通过 Spring XML 上下文启动,运行后手动关闭。


Example.java

Gate SDK 使用示例,展示 FuturesApi 的基本用法。仅作参考。