Fix ghost finalize on unknown perp size and open rollback hazards.

Distinguish exchange query None from flat zero; keep opening when size unknown; idempotent half_open cash; scan options while opening; continue manage after recover.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-29 20:47:29 +08:00
parent e2a19a1614
commit 101cb3c045
6 changed files with 153 additions and 76 deletions
@@ -1,49 +1,36 @@
# 审计说明 — 开/平仓逻辑与实盘安全(2026-07-29)
## 范围
## 结论(四轮后)
- 开仓 / 平仓 / 到期双腿 / 弃期权 / stuck `opening` 恢复
- LIVE OKX / 币安执行器与本地账本一致性
- 交易所对账(永续 + 期权)
开平仓主路径已闭环:占槽 → 意图落库 → 期权 → 永续 → open;平仓先 mark pending 再平永续;崩溃可 `recover_opening`。第四轮修掉「查仓失败当空仓 finalize」等回归。
## 结论摘要(三轮)
## 四轮关键项
| 严重度 | 问题 | 处置 |
|--------|------|------|
| Critical | 到期双平期权二次入账 | **已修** |
| Critical | abandon 账本拒记 / 假 residual 双计 | **已修** |
| Critical | 币安 `orderId=` 保留 opening 实际不匹配 → 可能重复开 | **已修**:错误文案带 `orderId=` |
| Critical | `opening` 无元数据,崩溃后无法恢复 | **已修**`stamp_opening_intent` + `recover_opening` |
| High | 对账只查永续 | **已修**:期权仓位 + flat 时任意期权残留 |
| High | pending 时永续已空仍用 DB 数量下单 | **已修**`allow_db_fallback=False` → 直接 finalize |
| High | 期权已空仍再卖 / 未 mark | **已修**:查仓跳过再卖;有 close fill 不二次入账 |
| High | 永续开仓异常时可能已成交仍回滚期权 | **已修**:先查永续仓再决定 |
| High | `_wait_fill` 部分成交当全成 | **已修** |
| High | residual LIVE 无 `allow_negative` | **已修** |
| Med | 币安缺保证金模式 | **已修**:落库 + `set_margin_type` |
| 轮次 | 关键修复 |
|------|----------|
| 1 | 到期双入账;abandon `allow_negative`;保证金模式;引擎锁;AUTH;盈亏查询 |
| 2 | abandon 假 residual;部分成交不当全成;residual LIVE 账本 |
| 3 | stamp + recover_opening;期权对账;已空不重卖/不下单;币安 orderId= |
| 4 | 查仓 `None``0`;回滚仅确认空仓;half_open/promote 现金幂等;opening any-option;开仓张数独立 |
## 开仓状态机(自检)
## 开仓
1. `claim_open_slot``opening`
2. `stamp_opening_intent`(写入 group_id / option_inst_id / 数量)
3. 下期权 → 再 stamp 成交均价
4. 下永续;失败则查永续仓:有仓保留 opening;无仓则回滚期权,回滚失败 → `half_open`
5. 成功 → `open`;启动/tick/`close_group``opening``recover_opening`
1. `claim``assert`(永续+期权残留)→ `stamp` → 买期权 → `stamp` 均价
2. 开永续用 `perp_open_contracts_okx`(不跟残留)
3. 永续失败:查仓 `None`/有仓 → 保留 opening;确认空 → 回滚期权 / half_open
4. tick/启动/紧急:`recover_opening`(空清槽 / 仅期权 half_open / 双边 promote
## 平仓状态机(自检)
## 平仓
1. 卖期权(或到期本地结算)→ `_mark_option_closed_perp_pending`(只一次)
2. 永续;交易所已空则不下单,直接 finalize
3. abandon已 pending只续平永续,不记 residual
4. finalize 在 pending 时 `skip_option_cash`
1. 卖期权(已空则跳过)→ mark pending 仅一次
2. 永续`None` → 失败返回;`0` → finalize`>0` → 下单
3. abandon:已 pending 只续平;禁止假 residual
## 仍需人工场景(极少)
## 已知极少人工场景
- `opening``option_inst_id` 且交易所有不明期权:禁止自动清槽,企微告警
- 提升为 `open` 时永续入场价用指数近似(本地镜像;实盘盈亏可走交易所对账)
- opening 无 `option_inst_id` 且交易所有不明期权:禁止自动清槽
- promote 入场价可能用指数近似(本地镜像;实盘盈亏可走交易所对账)
## 涉及文件
- `backend/app/live/reconcile.py`(核心恢复/对账)
- `executor.py` / `binance_executor.py` / `okx_trade.py` / `binance_trade.py`
- `strategy/engine.py` / `sim/matcher.py`
`live/reconcile.py` · `executor.py` · `binance_executor.py` · `okx_trade.py` · `binance_trade.py` · `strategy/engine.py` · `sim/matcher.py`
+15
View File
@@ -5,6 +5,21 @@
---
## 2026-07-29 — 第四轮:查仓失败≠空仓;回滚/账本幂等
### 变更
1. 平仓查仓 `None``0` 分离:查失败禁止空仓 finalize(防幽灵平仓)。
2. 永续开仓异常且查仓失败时禁止回滚期权(保留 opening)。
3. `half_open` / promote 权利金入账幂等(按 group 已有 `open_option` 跳过)。
4. `opening` 未 stamp 时仍扫任意期权残留;OKX 开仓改用 `perp_open_contracts_okx`opening 恢复成功后同 tick 继续 manage。
### 审计
详见 [`docs/审计说明-2026-07-29-开平仓与实盘安全.md`](./审计说明-2026-07-29-开平仓与实盘安全.md)。
---
## 2026-07-29 — 第三轮:opening 恢复 / 期权对账 / 平仓兜底
### 变更