auto_trade_sys/docs/bian/订单记录简化流程(支付式闭环).md
薇薇安 13a0e7d580 delete: 移除过时的文档与代码文件
删除了多个不再使用的文档和代码文件,包括交易更新推送、条件订单推送、REST API 文档、WebSocket API 文档及相关的策略分析文档。这些文件的移除有助于清理代码库,确保项目的整洁性与可维护性。
2026-02-20 17:49:00 +08:00

133 lines
7.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 订单记录简化流程(支付式闭环)
参考 `订单交易更新推送.txt`、`条件订单交易更新推送.txt`,把订单记录做成「先本地单号 → 写 DB + 下单 → 仅靠 WS 推送更新状态」的闭环,和支付系统类似。
---
## 一、目标流程(你期望的)
1. **先本地生成订单号**(如 `client_order_id = SYS_时间戳_随机`)。
2. **写 DB 与下单尽量一体**:先插入一条「待成交」记录(带 `client_order_id`),再立刻用该 id 去交易所下单REST 或 WS选更稳的方式逻辑上视为「同一事务」——下单失败则把该条记录标为失败/取消。
3. **状态只跟 WS 走**:用币安 **ORDER_TRADE_UPDATE**(和必要时 **ALGO_UPDATE**驱动所有「成交、平仓、取消」等状态与字段更新DB 只根据推送更新,不依赖 REST 轮询结果做主数据。
这样:**一条 DB 记录 = 一次「开仓意图」或「平仓意图」**,用本地 id 和交易所 id 串联WS 是唯一事实来源,逻辑简单、易对账。
---
## 二、币安推送里用到的字段docs/bian
### ORDER_TRADE_UPDATE订单交易更新推送
| 字段 | 含义 | 用途 |
|------|------|------|
| `e` | 事件类型 | ORDER_TRADE_UPDATE |
| `o.c` | 客户端自定义订单 ID | **clientOrderId**,我们下单时传的,用来唯一匹配「本地这条记录」 |
| `o.i` | 订单 ID | **orderId**,交易所订单号,写 entry_order_id / exit_order_id |
| `o.x` | 本次事件类型 | NEW / TRADE / CANCELED / EXPIRED 等 |
| `o.X` | 订单当前状态 | NEW / PARTIALLY_FILLED / **FILLED** / CANCELED 等 |
| `o.ap` | 订单平均成交价 | 成交后更新 entry_price 或 exit_price |
| `o.z` | 订单累计成交量 | 成交数量 |
| `o.R` | 是否只减仓 | true = 平仓单 |
| `o.rp` | 该笔实现盈亏 | 平仓时写 pnl/realized_pnl |
**开仓**`o.R != true` 且 `o.X == FILLED` → 用 `o.c` 找到 pending 记录,更新为 open写入 `entry_order_id=o.i`、`entry_price=o.ap`、`quantity=o.z`。
**平仓**`o.R == true` 且 `o.X == FILLED` → 用 `o.s`(symbol) + 当前 open 记录匹配,写入 `exit_order_id=o.i`、`exit_price=o.ap`、`pnl` 等(可用 `o.rp`)。
### ALGO_UPDATE条件订单交易更新推送
| 字段 | 含义 | 用途 |
|------|------|------|
| `o.X` | 条件单状态 | TRIGGERED / FINISHED 表示已触发 |
| `o.ai` | 触发后普通订单 id | 平仓单触发后,用 **ai** 作为 exit_order_id并等 ORDER_TRADE_UPDATE(ai) 拿成交价、rp |
止损/止盈是「条件单」:先下 Algo 单,触发后生成一笔普通订单,推送里给 `ai`。我们应:
1在 ALGO_UPDATE 里用 `ai` 回写 `exit_order_id`
2在随后收到的 ORDER_TRADE_UPDATE`o.i == ai`)里用 `ap/z/rp` 回写 exit_price、pnl 等,这样平仓数据也闭环。
---
## 三、闭环流程(按事件串起来)
### 开仓
```
1. 生成 client_order_id = SYS_<ts>_<rand>
2. 写 DBINSERT 一条 status=pending, client_order_id=client_order_id, symbol/side/quantity/...
3. 下单REST 或 WS order.place带 newClientOrderId=client_order_id
- 若下单失败UPDATE 该条为 status=canceled 或 failed保证「有记录」且状态明确
4. 之后只依赖 WS
- 收到 ORDER_TRADE_UPDATEo.c=client_order_ido.X=FILLED非 R
- → UPDATE 该条status=open, entry_order_id=o.i, entry_price=o.ap, quantity=o.z
```
这样:**开仓是否成交、成交价/量、交易所 orderId** 全部由 WS 一次更新完成,不依赖 REST 轮询。
### 平仓(市价/限价主动平)
```
1. 不新建 DB 记录,只「选一条当前 open 记录」准备关仓
2. 下单reduceOnly 市价/限价单(可带 newClientOrderId 便于对账)
3. 只依赖 WS
- 收到 ORDER_TRADE_UPDATEo.R=trueo.X=FILLEDo.s=symbol
- → 按 symbol(+ 可选 orderId/clientOrderId) 匹配那条 open
- → UPDATEstatus=closed, exit_order_id=o.i, exit_price=o.ap, pnl/realized_pnl 等(可用 o.rp
```
### 平仓(条件单触发:止损/止盈)
```
1. 不新建 DB 记录,只为当前 open 挂 Algo 单STOP_MARKET/TAKE_PROFIT_MARKET 等)
2. 触发后只依赖 WS
- 先收到 ALGO_UPDATEo.X=TRIGGERED/FINISHEDo.ai=触发后订单 id
→ UPDATE 该 openexit_order_id=o.ai先占位
- 再收到 ORDER_TRADE_UPDATEo.i=o.aio.X=FILLEDo.R=true
→ 同一条记录exit_price=o.appnl/realized_pnl 用 o.rp必要时补 duration/exit_time
```
这样:**条件单触发的平仓**也完全由 WS 闭环,不依赖 REST 或定时同步做主数据。
---
## 四、和当前实现的对应关系
| 目标步骤 | 当前实现 | 说明 |
|----------|----------|------|
| 本地先生成 client_order_id | ✅ 已有 | position_manager 里 `SYS_ts_rand`,并传 `newClientOrderId` |
| 先写 DB 再下单 | ✅ 已有 | 先 `Trade.create(..., status='pending', client_order_id=...)`,再下单 |
| 下单失败把记录标失败 | ⚠️ 部分 | 有失败路径,但不一定统一 UPDATE 为 canceled/failed |
| 开仓成交只靠 WS 更新 | ✅ 已有 | User Data Stream 里 ORDER_TRADE_UPDATE FILLED + 非 R → `update_pending_to_filled(client_order_id, ..., order_id, ap, z)` |
| 平仓成交只靠 WS 更新 exit_order_id | ✅ 已有 | ORDER_TRADE_UPDATE FILLED + R → `set_exit_order_id_for_open_trade(symbol, account_id, order_id)` |
| 平仓成交用 WS 更新 exit_price / pnl | ❌ 缺口 | 目前只写了 exit_order_id**没有**在 WS 里用 `ap/rp``update_exit(..., exit_price, pnl, ...)`,条件单触发的平仓尤其缺 |
| 条件单触发用 ai 写 exit_order_id | ✅ 已有 | ALGO_UPDATE 里 `set_exit_order_id_for_open_trade(symbol, account_id, ai)` |
| 「DB + 下单」原子性 | ⚠️ 语义上的 | DB 与交易所是两套系统,无法真 2PC只能「先写 DB 再下单,失败则把该条标为失败」 |
所以:**主流程已经接近「支付式」**,真正缺的闭环是:**WS 收到平仓成交(含条件单触发的 ai 那笔)时,不仅要写 exit_order_id还要用推送里的 ap/rp 等把 exit_price、pnl、exit_time 等一次更新掉**。
---
## 五、建议补的一步(闭环平仓数据)
**User Data Stream** 里,当 `ORDER_TRADE_UPDATE``o.R == true``o.X == FILLED` 时,除现有 `set_exit_order_id_for_open_trade(symbol, account_id, order_id)` 外,建议:
- 用同一推送里的 `o.ap`、`o.z`、`o.rp`(及可选 `o.N`/`o.n` 手续费)和当前时间(或 `o.T` 成交时间),对**同一条 open 记录**再调一次 **update_exit**(或等价的「按 exit_order_id 补全 exit_price / pnl / commission」接口
- exit_price
- pnl / pnl_percent或 realized_pnl
- commission若有
- exit_time
都从 WS 一次写库。这样:
- 市价/限价平仓ORDER_TRADE_UPDATE 一次即可完成「exit_order_id + 价格 + 盈亏」闭环。
- 条件单平仓ALGO_UPDATE 写 exit_order_id → 等 ORDER_TRADE_UPDATE(ai) 再按上面补全价格和盈亏,也闭环。
---
## 六、小结
- **你的理解**:先本地单号 → 写 DB + 下单(尽量一体)→ 只靠 WS 通知更新订单状态与成交数据,是正确且更清晰的设计。
- **当前实现**:开仓侧已经是「先生成 client_order_id、先写 pending、再下单、WS 完善」;平仓侧 **exit_order_id** 已由 WS 回写,但 **exit_price / pnl 等还未在 WS 路径里统一写库**,算一个遗漏。
- **补上这一块**WS 平仓成交时顺带 update_exit 价格与盈亏),就能在「不依赖 REST 轮询、不依赖同步接口做主数据」的前提下,做到订单记录与币安完全以 WS 为源的闭环。
- **事务**DB 与交易所无法真事务,只能「先 DB 再下单,失败则把该条记录标为失败/取消」,当前逻辑已接近,可再统一失败态标记。
文档参考:`docs/bian/订单交易更新推送.txt`、`docs/bian/条件订单交易更新推送.txt`。