| | |
| | | |
| | | ``` |
| | | okxNewPrice/ |
| | | ├── OkxConfig.java # 全局配置(Builder模式) |
| | | ├── OkxGridTradeService.java # 核心策略引擎 |
| | | ├── OkxTradeExecutor.java # REST API 异步执行器 |
| | | ├── OkxGridElement.java # 网格价格层级 + 8个全局O(1)索引 |
| | | ├── OkxTraderParam.java # 单笔挂单参数 |
| | | ├── OkxGridWsClient.java # WebSocket 客户端(双连接) |
| | | ├── OkxWebSocketClientManager.java # Spring容器入口 + WS组装 |
| | | ├── OkxConfig.java # 全局配置(Builder模式,策略唯一参数入口) |
| | | ├── OkxGridTradeService.java # 核心策略引擎(状态机 + 事件驱动循环) |
| | | ├── OkxTradeExecutor.java # REST API 异步执行器(单线程池 + 背压) |
| | | ├── OkxGridElement.java # 网格价格层级 + 8个全局O(1)静态索引 |
| | | ├── OkxTraderParam.java # 单笔挂单参数(方向/触发价/数量/订单ID) |
| | | ├── OkxGridWsClient.java # WebSocket 客户端(双连接:business + private) |
| | | ├── OkxWebSocketClientManager.java # Spring容器入口 + Bean组装 + 生命周期 |
| | | ├── ExchangeInfoEnum.java # 账户枚举 |
| | | │ |
| | | ├── gridWs/ |
| | | │ ├── OkxGridChannelHandler.java # 频道处理器接口 |
| | | │ ├── OkxKlineChannelHandler.java # candle1m → onKline() |
| | | │ ├── OkxKlineChannelHandler.java # candle1m → onKline(closePrice) |
| | | │ ├── OkxPositionsChannelHandler.java # positions → onPositionUpdate() |
| | | │ ├── OkxOrdersChannelHandler.java # orders → onOrderUpdate()(替代orders-algo) |
| | | │ └── OkxAlgoOrdersChannelHandler.java # orders-algo(测试网不可用,保留备用) |
| | | │ ├── OkxOrdersChannelHandler.java # orders → onOrderUpdate() (替代orders-algo) |
| | | │ └── OkxAlgoOrdersChannelHandler.java # orders-algo(测试网60018不可用,备用) |
| | | │ |
| | | └── okxpi/config/ # OKX API 底层HTTP/签名工具 |
| | | └── okxpi/config/ # OKX V5 API 底层HTTP签名/请求工具链 |
| | | ├── Account.java / OKXAccount.java |
| | | ├── RequestHandler.java / ResponseHandler.java |
| | | └── utils/ (SignUtils, UrlBuilder, OkHttpUtils...) |
| | | ``` |
| | | |
| | | ## 二、策略生命周期 |
| | | ## 二、Spring 容器入口 |
| | | |
| | | ``` |
| | | ┌─────────────────────────────────────────────────────────────────┐ |
| | | │ init() → startGrid() → WAITING_KLINE │ |
| | | │ ↓ │ |
| | | │ onKline(首根K线) → OPENING → 市价双开基底 │ |
| | | │ ├── openLong(baseQuantity张) │ |
| | | │ └── openShort(baseQuantity张) │ |
| | | │ ↓ │ |
| | | │ onPositionUpdate() → 双基底成交 → tryGenerateQueues() │ |
| | | │ ├── generateShortQueue() 空仓队列(基准价向下步进) │ |
| | | │ ├── generateLongQueue() 多仓队列(基准价向上步进) │ |
| | | │ ├── updateGridElements() 构建OkxGridElement双向链表 │ |
| | | │ ├── 多仓止损 -2~-11: algo(sell+long, slTriggerPx, sz=qty) │ |
| | | │ └── 空仓止损 2~11: algo(buy+short, slTriggerPx, sz=qty) │ |
| | | │ ↓ │ |
| | | │ state = ACTIVE │ |
| | | └─────────────────────────────────────────────────────────────────┘ |
| | | `OkxWebSocketClientManager` 是 `@Component + @PostConstruct` 驱动的组装点。 |
| | | |
| | | ### 2.1 激活条件 |
| | | |
| | | ```yaml |
| | | # application-test.yml |
| | | app: |
| | | quant: true # @ConditionalOnProperty 控制是否启动 |
| | | ``` |
| | | |
| | | ### 状态机 |
| | | ### 2.2 初始化顺序 (@PostConstruct) |
| | | |
| | | | 状态 | 含义 | 进入条件 | |
| | | |------|------|---------| |
| | | | `WAITING_KLINE` | 等待首根K线 | startGrid() | |
| | | | `OPENING` | 基底开仓中 | 首根K线到达 | |
| | | | `ACTIVE` | 策略运行中 | 网格初始化完成 | |
| | | | `STOPPED` | 已停止(等待重启) | 盈亏达标/持仓归零 | |
| | | ``` |
| | | 1. ExchangeInfoEnum 取首个账户 |
| | | 2. 构建 OkxAccount(baseUrl + apiKey/secretKey/passphrase) |
| | | 3. OkxConfig.builder() 构建配置(BTC-USDT-SWAP, 100x, cross, gridRate=0.001) |
| | | 4. OkxGridTradeService.init() |
| | | ├── GET /api/v5/account/balance → 取 USDT details[].eq 作为初始本金 |
| | | ├── POST /api/v5/trade/cancel-algos → 清旧条件单 |
| | | ├── GET /api/v5/account/positions → 遍历平已有仓位 |
| | | └── POST /api/v5/account/set-leverage → 设置杠杆 |
| | | 5. 创建双 WS 客户端并注册频道处理器: |
| | | ├── gridWsClientPublic → /v5/business → candle1m (无需登录) |
| | | └── gridWsClientPrivate → /v5/private → positions + orders (先登录) |
| | | 6. gridTradeService.startGrid() → WAITING_KLINE |
| | | ``` |
| | | |
| | | ### 2.3 销毁顺序 (@PreDestroy) |
| | | |
| | | ``` |
| | | stopGrid() → cancelAllAlgoOrders + shutdown → gridWsClientPublic.destroy() → gridWsClientPrivate.destroy() |
| | | ``` |
| | | |
| | | ### 2.4 当前活跃配置 |
| | | |
| | | | 参数 | 值 | 说明 | |
| | | |------|-----|------| |
| | | | `instId` | `BTC-USDT-SWAP` | 合约 | |
| | | | `leverage` | `100` | 杠杆 | |
| | | | `tdMode` | `cross` | 全仓 | |
| | | | `gridRate` | `0.001` | 网格间距 0.1% | |
| | | | `expectedProfit` | `20` USDT | 盈亏达标重置线 | |
| | | | `maxLoss` | `30` USDT | 亏损风控告警线 | |
| | | | `quantity` | `1` | 每格下单张数 | |
| | | | `baseQuantity` | `10` | 基底开仓张数 | |
| | | | `priceScale` | `2` | 价格精度 | |
| | | | `ctVal` | `0.1` | 合约面值 | |
| | | | `gridQueueSize` | `300` | 价格队列容量 | |
| | | |
| | | ## 三、WS连接架构 |
| | | |
| | | ``` |
| | | ┌──────────────────────────────────────────────────────┐ |
| | | │ OkxWebSocketClientManager (@PostConstruct) │ |
| | | ┌──────────────────────────────────────────────────────────┐ |
| | | │ OkxWebSocketClientManager │ |
| | | │ │ |
| | | │ ┌─ gridWsClientPublic ───────────────────────────┐ │ |
| | | │ │ URL: /ws/v5/business (无需登录,直连订阅) │ │ |
| | | │ │ ├── OkxKlineChannelHandler (candle1m) │ │ |
| | | │ └────────────────────────────────────────────────┘ │ |
| | | │ gridWsClientPublic (isPublic=true) │ |
| | | │ ├── URL: wss://wspap.okx.com:8443/ws/v5/business │ |
| | | │ ├── 连接后立即 subscribeAllHandlers()(无需登录) │ |
| | | │ └── OkxKlineChannelHandler(candle1m, instId) │ |
| | | │ │ |
| | | │ ┌─ gridWsClientPrivate ──────────────────────────┐ │ |
| | | │ │ URL: /ws/v5/private (先登录再订阅) │ │ |
| | | │ │ ├── OkxPositionsChannelHandler (positions) │ │ |
| | | │ │ └── OkxOrdersChannelHandler (orders) │ │ |
| | | │ └────────────────────────────────────────────────┘ │ |
| | | └──────────────────────────────────────────────────────┘ |
| | | │ gridWsClientPrivate (isPublic=false) │ |
| | | │ ├── URL: wss://wspap.okx.com:8443/ws/v5/private │ |
| | | │ ├── 连接后 wsLogin() → 登录成功 → subscribeAllHandlers()│ |
| | | │ ├── OkxPositionsChannelHandler(positions, instType:SWAP)│ |
| | | │ └── OkxOrdersChannelHandler(orders, instType:SWAP) │ |
| | | └──────────────────────────────────────────────────────────┘ |
| | | ``` |
| | | |
| | | | 连接 | URL | 频道 | 是否登录 | 回调 | |
| | | |------|-----|------|---------|------| |
| | | | 业务WS | `/ws/v5/business` | `candle1m` | 否 | `onKline(closePrice)` | |
| | | | 私有WS | `/ws/v5/private` | `positions` | 是 | `onPositionUpdate(instId, posSide, pos, avgPx)` | |
| | | | 私有WS | `/ws/v5/private` | `orders` | 是 | `onOrderUpdate(algoId, state, ordType)` | |
| | | | 连接 | URL | 频道 | 订阅参数 | 回调方法 | |
| | | |------|-----|------|---------|---------| |
| | | | business | `/v5/business` | `candle1m` | `instId` | `onKline(closePrice)` | |
| | | | private | `/v5/private` | `positions` | `instType:SWAP` | `onPositionUpdate(instId, posSide, pos, avgPx)` | |
| | | | private | `/v5/private` | `orders` | `instType:SWAP` | `onOrderUpdate(algoId, state, ordType)` | |
| | | |
| | | > **注意**:`orders-algo` 频道在测试网不可用(60018),已替换为 `orders` 频道。algo触发后生成普通订单,fill数据中带 `algoId` 字段可匹配回原始条件单。 |
| | | > **orders 频道替代 orders-algo**:`orders-algo` 在测试网不可用(60018),改订阅 `orders` 频道。 |
| | | > algo 触发后生成普通市价单,fill 数据中 `algoId` 字段非空时可匹配回原始条件单。 |
| | | > `OkxOrdersChannelHandler` 过滤逻辑:`state=filled` AND `algoId` 非空。 |
| | | |
| | | ## 四、网格ID体系 |
| | | ### 3.1 心跳机制 |
| | | |
| | | ``` |
| | | 价格方向: 低 ←────────────────── 基准价 ──────────────────→ 高 |
| | | ID: -N ... -3 -2 -1 0 1 2 3 ... N |
| | | 用途: 多仓止损区 基底 空仓止损区 |
| | | (初始化: -2~-11) (初始化: 2~11) |
| | | 10s 无消息 → send("ping") → server reply "pong" → 重置计时器 |
| | | 25s 定时检查 → 超时则 send("ping") |
| | | LostConnectionChecker: setConnectionLostTimeout(0) 已关闭(协议级ping OKX不响应) |
| | | ``` |
| | | |
| | | ## 四、策略生命周期 |
| | | |
| | | ### 4.1 状态机 |
| | | |
| | | | 状态 | 含义 | 进入条件 | 退出动作 | |
| | | |------|------|---------|---------| |
| | | | `WAITING_KLINE` | 等待首根K线 | startGrid() | 首根K线→OPENING | |
| | | | `OPENING` | 基底开仓中 | 首根K线 | 双基底成交→ACTIVE | |
| | | | `ACTIVE` | 策略运行 | 网格初始化完成 | 盈亏达标/持仓归零→STOPPED | |
| | | | `STOPPED` | 已停止 | 重置/达标 | 下根K线自动 startGrid() | |
| | | |
| | | ### 4.2 完整流程 |
| | | |
| | | ``` |
| | | ┌──────────────────────────────────────────────────────────────┐ |
| | | │ init() → startGrid() → WAITING_KLINE │ |
| | | │ ↓ │ |
| | | │ onKline(首根) → OPENING → executor.openLong/Short(10张) │ |
| | | │ ↓ │ |
| | | │ onPositionUpdate → 基底成交 → tryGenerateQueues() │ |
| | | │ ├── generateShortQueue(): shortBasePrice - step 向下步进 │ |
| | | │ ├── generateLongQueue(): shortBasePrice + step 向上步进 │ |
| | | │ ├── updateGridElements(): 构建 601个 OkxGridElement │ |
| | | │ │ ├── ID≤-1: 空仓区(降序) ID=0:基底 ID≥1:多仓区(升序)│ |
| | | │ │ └── ID索引 + 价格索引 + 6个订单ID索引 (O(1)) │ |
| | | │ ├── 多仓止损 -2~-11: POST order-algo │ |
| | | │ │ ordType=conditional, side=sell, posSide=long, │ |
| | | │ │ slTriggerPx=网格价, slOrdPx=-1, sz=quantity │ |
| | | │ └── 空仓止损 +2~+11: POST order-algo │ |
| | | │ ordType=conditional, side=buy, posSide=short, │ |
| | | │ slTriggerPx=网格价, slOrdPx=-1, sz=quantity │ |
| | | │ ↓ │ |
| | | │ state = ACTIVE ─────────────────────────────────────────────│ |
| | | └──────────────────────────────────────────────────────────────┘ |
| | | ``` |
| | | |
| | | ## 五、事件驱动循环 (ACTIVE 状态) |
| | | |
| | | ### 5.1 K线回调 `onKline(closePrice)` |
| | | |
| | | ``` |
| | | lastKlinePrice = closePrice |
| | | updateUnrealizedPnl() |
| | | |
| | | if STOPPED: |
| | | cancelAllAlgoOrders() + closeExistingPositions() + startGrid() → WAITING_KLINE |
| | | |
| | | if WAITING_KLINE: |
| | | 市价双开 baseQuantity 张 (openLong + openShort) → OPENING |
| | | |
| | | if ACTIVE: |
| | | checkProfitAndReset() // 每根K线检查盈亏达标 |
| | | ``` |
| | | |
| | | ### 5.2 仓位推送 `onPositionUpdate` |
| | | |
| | | ``` |
| | | long 有仓位: |
| | | 首次(基底) → 记录 baseLongOpened + 均价 → tryGenerateQueues() |
| | | 后续 → 更新 positionSize / entryPrice |
| | | 归零 → handlePositionZeroAndReset("多仓") |
| | | |
| | | short 有仓位: |
| | | 首次(基底) → 记录 baseShortOpened + 均价 → tryGenerateQueues() |
| | | 后续 → 更新 positionSize / entryPrice |
| | | 归零 → handlePositionZeroAndReset("空仓") |
| | | ``` |
| | | |
| | | ### 5.3 订单成交 `onOrderUpdate(algoId, state, ordType)` — 核心事件 |
| | | |
| | | 触发条件:`state == "filled"` (来自 `orders` 频道的成交推送) |
| | | |
| | | ``` |
| | | ┌─ findByLongStopLossOrderId(algoId) |
| | | │ → handleLongStopLossTriggered() |
| | | │ 止损-ID=-N → 清空止损ID |
| | | │ → 在 -(N-1) 挂 count×qty 张多单 |
| | | │ (ordType=trigger, triggerPx, orderPx=-1) |
| | | │ → N>2 时取消 -(N-2) 旧多单 |
| | | │ |
| | | ├─ findByShortStopLossOrderId(algoId) |
| | | │ → handleShortStopLossTriggered() |
| | | │ 止损ID=N → 清空止损ID |
| | | │ → 在 N-1 挂 count×qty 张空单 |
| | | │ (ordType=trigger, triggerPx, orderPx=-1) |
| | | │ → N>2 时取消 N-2 旧空单 |
| | | algoId 匹配 ────────┤ |
| | | ├─ findByShortOrderId(algoId) && hasShortOrder |
| | | │ → shortEntryTraderIdParam(null, false) |
| | | │ → extendShortStopLoss(filledQty) |
| | | │ 到最远空仓止损外扩 stopLossCount 个网格 |
| | | │ 每格挂 quantity 张止损 |
| | | │ |
| | | └─ findByLongOrderId(algoId) && hasLongOrder |
| | | → longEntryTraderIdParam(null, false) |
| | | → extendLongStopLoss(filledQty) |
| | | 到最远多仓止损外扩 stopLossCount 个网格 |
| | | 每格挂 quantity 张止损 |
| | | ``` |
| | | |
| | | ### 5.4 平仓推送 `onPositionClose` |
| | | |
| | | ``` |
| | | cumulativePnl += pnl |
| | | 总盈亏 ≤ -maxLoss → 钉钉告警(仅通知,不停止) |
| | | ``` |
| | | |
| | | ## 六、网格ID体系 |
| | | |
| | | ``` |
| | | 价格方向: 低 ←────────────── 基底价 ──────────────→ 高 |
| | | ID: ... -3 -2 -1 0 1 2 3 ... |
| | | 用途: 多仓止损/追单区 基底 空仓止损/追单区 |
| | | 初始化止损:-2~-11 初始化止损:2~11 |
| | | |
| | | 链表: ... ← -3 ← -2 ← -1 ← 0 → 1 → 2 → 3 → ... |
| | | (通过 upId/downId + INDEX 实现 O(1) 遍历) |
| | | (upId/downId + INDEX → O(1) 遍历) |
| | | ``` |
| | | |
| | | ### GridElement 字段 |
| | | ### 6.1 GridElement 字段 |
| | | |
| | | | 类别 | 字段 | 说明 | |
| | | |------|------|------| |
| | | | 标识 | `id`, `gridPrice`, `upId`, `downId` | 编号、价格、双向链表指针 | |
| | | | 多仓订单 | `hasLongOrder`, `longOrderId`, `longTraderParam` | 多仓条件单状态 | |
| | | | 空仓订单 | `hasShortOrder`, `shortOrderId`, `shortTraderParam` | 空仓条件单状态 | |
| | | | 多仓 | `hasLongOrder`, `longOrderId`, `longTraderParam` | 多仓挂单状态 | |
| | | | 空仓 | `hasShortOrder`, `shortOrderId`, `shortTraderParam` | 空仓挂单状态 | |
| | | | 止盈 | `longTakeProfitOrderId`, `shortTakeProfitOrderId` | 止盈algoId | |
| | | | 止损 | `longStopLossOrderId`, `shortStopLossOrderId` | 止损algoId | |
| | | |
| | | ### 8个全局O(1)索引 |
| | | ### 6.2 8个全局O(1)索引 |
| | | |
| | | ``` |
| | | INDEX → findById(int) |
| | |
| | | SHORT_SL_ORDER_ID_INDEX→ findByShortStopLossOrderId(String) |
| | | ``` |
| | | |
| | | ## 五、事件驱动循环(ACTIVE状态) |
| | | 每次订单状态变更后调用 `OkxGridElement.refreshIndices()` 增量重建,同时 `logAll()` 打印全量网格数据。 |
| | | |
| | | ### 5.1 K线回调 `onKline(closePrice)` |
| | | ## 七、关键公式 |
| | | |
| | | ### 7.1 网格步长 |
| | | |
| | | ``` |
| | | 更新 lastKlinePrice → updateUnrealizedPnl() |
| | | → STOPPED: 清条件单+平仓+startGrid() |
| | | → WAITING_KLINE: 市价双开基底 |
| | | → ACTIVE: checkProfitAndReset()(每根K线检查盈亏达标) |
| | | step = shortBaseEntryPrice × gridRate (priceScale 精度对齐) |
| | | ``` |
| | | |
| | | ### 5.2 仓位推送 `onPositionUpdate(instId, posSide, posSize, avgPx)` |
| | | |
| | | ``` |
| | | 基底首次成交 → tryGenerateQueues() |
| | | 后续仓位变化 → 更新 positionSize/entryPrice |
| | | 仓位归零 → handlePositionZeroAndReset() |
| | | ``` |
| | | |
| | | ### 5.3 订单成交 `onOrderUpdate(algoId, state, ordType)` |
| | | |
| | | ``` |
| | | state == "filled" 时: |
| | | |
| | | ┌─ findByLongStopLossOrderId(algoId) → handleLongStopLossTriggered() |
| | | │ 清空止损ID → grid -(N-1) 挂 count×qty 张多单 |
| | | │ → 若 N>2, 取消 grid -(N-2) 旧多单 |
| | | │ |
| | | ├─ findByShortStopLossOrderId(algoId) → handleShortStopLossTriggered() |
| | | │ 清空止损ID → grid N-1 挂 count×qty 张空单 |
| | | │ → 若 N>2, 取消 grid N-2 旧空单 |
| | | │ |
| | | ├─ findByShortOrderId(algoId) → extendShortStopLoss(filledQty) |
| | | │ 从最远空仓止损向外扩展 stopLossCount 个网格止损 |
| | | │ |
| | | └─ findByLongOrderId(algoId) → extendLongStopLoss(filledQty) |
| | | 从最远多仓止损向外扩展 stopLossCount 个网格止损 |
| | | ``` |
| | | |
| | | ### 5.4 平仓推送 `onPositionClose(side, pnl)` |
| | | |
| | | ``` |
| | | cumulativePnl += pnl |
| | | → 总盈亏 ≤ -maxLoss → 钉钉告警(不停止,仅通知) |
| | | ``` |
| | | |
| | | ## 六、关键公式 |
| | | |
| | | ### 6.1 网格步长 |
| | | |
| | | ``` |
| | | step = shortBaseEntryPrice × gridRate (对齐到 priceScale 精度) |
| | | ``` |
| | | |
| | | ### 6.2 止损触发 → 追单数量 |
| | | ### 7.2 止损触发 → 追单 |
| | | |
| | | ``` |
| | | priceDiff = |avgEntryPrice - newEntryGridPrice|.abs() |
| | | count = priceDiff / step (DOWN取整, 最小1) |
| | | entryQty = count × quantity |
| | | count = priceDiff / step (RoundingMode.DOWN, 最小1) |
| | | entryQty = count × quantity → 挂 ordType=trigger 条件单 |
| | | ``` |
| | | |
| | | ### 6.3 挂单成交 → 追挂止损 |
| | | ### 7.3 挂单成交 → 追挂止损 |
| | | |
| | | ``` |
| | | stopLossCount = filledQty / quantity |
| | | 从最远止损ID向外扩展 stopLossCount 个网格,每格挂 1个 quantity张的止损单 |
| | | 从最远止损ID向外扩展 stopLossCount 个网格 |
| | | 每格挂 1 个 quantity 张止损 (ordType=conditional, slTriggerPx) |
| | | ``` |
| | | |
| | | ### 6.4 未实现盈亏 |
| | | ### 7.4 未实现盈亏 |
| | | |
| | | ``` |
| | | 多仓Pnl = longPositionSize × ctVal × (lastKlinePrice - longEntryPrice) |
| | | 空仓Pnl = shortPositionSize × ctVal × (shortEntryPrice - lastKlinePrice) |
| | | unrealizedPnl = 多仓Pnl + 空仓Pnl |
| | | longPnl = longPositionSize × ctVal × (lastKlinePrice - longEntryPrice) |
| | | shortPnl = shortPositionSize × ctVal × (shortEntryPrice - lastKlinePrice) |
| | | unrealizedPnl = longPnl + shortPnl |
| | | ``` |
| | | |
| | | ### 6.5 盈亏达标检查 |
| | | ### 7.5 盈亏达标检查 |
| | | |
| | | ``` |
| | | upl + availEq > initialPrincipal + expectedProfit → 重置策略 |
| | | GET balance → upl (未实现盈亏) + availEq (可用保证金) |
| | | if upl + availEq > initialPrincipal + expectedProfit → STOPPED → 平仓+清条件单+startGrid() |
| | | ``` |
| | | |
| | | ## 七、REST API 映射 |
| | | ## 八、REST API 映射 |
| | | |
| | | | OkxTradeExecutor方法 | OKX API | 用途 | |
| | | |------|---------|------| |
| | | | `openLong(size)` / `openShort(size)` | `POST /api/v5/trade/order` (market) | 市价基底开仓 | |
| | | | `marketClose(side, posSide, sz)` | `POST /api/v5/trade/order` (market, reduceOnly) | 市价平仓 | |
| | | | `placeConditionalEntryOrder(tp, side, posSide, sz)` | `POST /api/v5/trade/order-algo` (triggerPx) | 条件开仓单 | |
| | | | `placeTakeProfit(tp, side, posSide, sz)` | `POST /api/v5/trade/order-algo` (slTriggerPx) | 止损/止盈条件单 | |
| | | | `cancelAlgoOrder(algoId)` | `POST /api/v5/trade/cancel-algos` | 取消单个条件单 | |
| | | | `getBalance()` | `GET /api/v5/account/balance` | 查询余额 | |
| | | | `getPositions()` | `GET /api/v5/account/positions` | 查询持仓 | |
| | | | `setLeverage(lever)` | `POST /api/v5/account/set-leverage` | 设置杠杆 | |
| | | | 方法 | OKX API | ordType | 触发参数 | 用途 | |
| | | |------|---------|---------|---------|------| |
| | | | `openLong(size)` | `POST /api/v5/trade/order` | `market` | — | 市价开多 | |
| | | | `openShort(size)` | `POST /api/v5/trade/order` | `market` | — | 市价开空 | |
| | | | `marketClose(s,p,sz)` | `POST /api/v5/trade/order` | `market` | reduceOnly | 市价平仓 | |
| | | | `placeConditionalEntryOrder` | `POST /api/v5/trade/order-algo` | **`trigger`** | `triggerPx` | 计划委托开仓 | |
| | | | `placeTakeProfit` | `POST /api/v5/trade/order-algo` | **`conditional`** | `slTriggerPx` | 止损/止盈平仓 | |
| | | | `cancelAlgoOrder(id)` | `POST /api/v5/trade/cancel-algos` | — | array body | 取消单个条件单 | |
| | | | `cancelAllAlgoOrders()` | `POST /api/v5/trade/cancel-algos` | — | array body | 清除全部条件单 | |
| | | | `getBalance()` | `GET /api/v5/account/balance` | — | ccy=USDT | 查询余额 | |
| | | | `getPositions()` | `GET /api/v5/account/positions` | — | instId | 查询持仓 | |
| | | | `setLeverage(l)` | `POST /api/v5/account/set-leverage` | — | lever+mgnMode | 设置杠杆 | |
| | | |
| | | ## 八、配置参数(OkxConfig.Builder默认值) |
| | | ### 8.1 ordType 对照表 |
| | | |
| | | | 参数 | 默认值 | 说明 | |
| | | |------|--------|------| |
| | | | `instId` | `ETH-USDT-SWAP` | 合约名称 | |
| | | | `leverage` | `100` | 杠杆倍数 | |
| | | | `tdMode` | `cross` | 全仓保证金 | |
| | | | `gridRate` | `0.0025` | 网格间距 0.25% | |
| | | | `expectedProfit` | `2` | 预期收益 2 USDT | |
| | | | `maxLoss` | `15` | 最大亏损 15 USDT | |
| | | | `quantity` | `1` | 每格下单张数 | |
| | | | `baseQuantity` | `10` | 基底开仓张数 | |
| | | | `priceScale` | `2` | 价格精度 | |
| | | | `ctVal` | `0.1` | 合约面值 | |
| | | | `gridQueueSize` | `300` | 队列容量 | |
| | | | `marginRatioLimit` | `0.2` | 保证金占比上限 20% | |
| | | | ordType | OKX含义 | 我们用途 | 触发价参数 | |
| | | |---------|--------|---------|-----------| |
| | | | `trigger` | 计划委托 | **开仓挂单**(等价格到位开仓) | `triggerPx` | |
| | | | `conditional` | 单向止盈止损 | **止损单**(等价格到位平仓) | `slTriggerPx` | |
| | | |
| | | ## 九、线程模型 |
| | | ## 九、网格ID示例(BTC-USDT, step≈70) |
| | | |
| | | ``` |
| | | WS回调线程(串行) Executor线程(单线程池) |
| | | ID=-11 price=69309.67 ← 最远多仓止损 |
| | | ID=-10 price=69379.97 |
| | | ID= -9 price=69450.27 |
| | | ID= -8 price=69520.57 |
| | | ID= -7 price=69590.87 |
| | | ID= -6 price=69661.17 |
| | | ID= -5 price=69731.47 |
| | | ID= -4 price=69801.77 |
| | | ID= -3 price=69872.07 |
| | | ID= -2 price=69942.37 ← 多仓止损起点 |
| | | ID= -1 price=70012.67 |
| | | ID= 0 price=70082.97 ← 基底 (shortBaseEntryPrice) |
| | | ID= 1 price=70153.27 |
| | | ID= 2 price=70223.57 ← 空仓止损起点 |
| | | ID= 3 price=70293.87 |
| | | ID= 4 price=70364.17 |
| | | ID= 5 price=70434.47 |
| | | ID= 6 price=70504.77 |
| | | ID= 7 price=70575.07 |
| | | ID= 8 price=70645.37 |
| | | ID= 9 price=70715.67 |
| | | ID= 10 price=70785.97 |
| | | ID= 11 price=70856.27 ← 最远空仓止损 |
| | | ``` |
| | | |
| | | ## 十、线程模型 |
| | | |
| | | ``` |
| | | [ctReadThread-XX] WS回调线程(串行) [okx-trade-worker] Executor(单线程池) |
| | | │ │ |
| | | ├─ onKline() ├─ openLong/openShort |
| | | ├─ onPositionUpdate() ├─ marketClose |
| | | ├─ onOrderUpdate() ──下单──→ ├─ placeConditionalEntryOrder |
| | | │ ├─ placeTakeProfit |
| | | │ └─ cancelAlgoOrder |
| | | ├─ onKline(closePrice) ├─ openLong / openShort |
| | | │ └─ updateUnrealizedPnl() ├─ marketClose |
| | | │ └─ checkProfitAndReset()(同步REST) ├─ placeConditionalEntryOrder (trigger) |
| | | │ ├─ placeTakeProfit (conditional) |
| | | ├─ onPositionUpdate(...) └─ cancelAlgoOrder / cancelAllAlgoOrders |
| | | │ └─ tryGenerateQueues() → 批量挂止损 |
| | | │ └─ handlePositionZeroAndReset() |
| | | │ |
| | | └─ checkProfitAndReset() (REST同步查余额) |
| | | └─ onOrderUpdate(algoId, state, ordType) |
| | | ├─ handleLongStopLossTriggered → placeConditionalEntryOrder |
| | | ├─ handleShortStopLossTriggered → placeConditionalEntryOrder |
| | | ├─ extendLongStopLoss → placeTakeProfit |
| | | └─ extendShortStopLoss → placeTakeProfit |
| | | ``` |
| | | |
| | | - WS回调在 `[ctReadThread-XX]` 中**串行**执行,避免并发问题 |
| | | - REST API 提交到 `okx-trade-worker` 单线程池异步执行,避免阻塞WS线程 |
| | | - `closeExistingPositions()` 和 `handlePositionZeroAndReset()` 在WS线程中同步调用REST,需注意耗时 |
| | | - `LostConnectionChecker` 已关闭(`setConnectionLostTimeout(0)`),由应用层 `ping`/`pong` 心跳接管 |
| | | - WS 回调线程串行执行,天然线程安全 |
| | | - REST 提交到 `okx-trade-worker` 单线程异步执行,避免阻塞 WS |
| | | - `closeExistingPositions()` / `handlePositionZeroAndReset()` 在 WS 线程中同步调用 REST(IOC 市价单,秒级完成) |
| | | - `LostConnectionChecker(0)` 已禁用,由应用层 `send("ping")`/`handle "pong"` 接管 |