Files
crypto_okx/docs/规格-期权交易账户盈亏结算.md
T
dekun 9d77a430e5 fix期权复盘与数据统计双口径盈亏,并修复卖回封顶导致盈利单冻成亏损。
平仓卖光可卖币后再按账户差分结算复盘;数据统计改为历史币盈亏×卖回价;复盘展示初始权利金与盈利率,并附历史修复脚本。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 09:10:13 +08:00

264 lines
9.7 KiB
Markdown
Raw 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.
# 规格:期权盈亏双口径结算(一次一仓)
> 状态:已定稿(2026-10-13 修订)
> 适用范围:币本位期权(模拟盘优先;实盘同规则)
> 目标:复盘可对账、数据统计跟期权历史一致;初始权利金 / 盈利率可展示;错账可脚本修复
---
## 1. 目标与原则
### 1.1 要解决什么
此前单笔盈亏混用多套口径,且卖回按开仓权利金封顶,导致:
- 盈利单(如约 1.5 倍)在复盘被冻成亏损(账户差分在盈利币未卖回时结算)
- 复盘与数据统计共用账户冻结,与「历史币盈亏 × 卖回价」不一致
- 缺少初始权利金(U)、盈利率展示
### 1.2 原则
| 原则 | 说明 |
|------|------|
| 双口径 | **A 复盘** = 交易账户 USDT 快照差分;**B 数据统计** = 期权历史币盈亏 × 平仓卖回价 |
| 一次一仓 | 同一账户同一时间只允许一笔期权持仓 |
| 卖光再结算 | A 口径:未卖光可卖标的币前,本单不冻结 |
| 冻结 | A 结算完成后永不修改;B 按平仓卖回价冻结后不跟盘 |
| 禁划转 | 持仓 / 待卖回期间禁止资金划转 |
| 权利金不含多买 | 初始权利金 = 开仓指数 × 权利金币量(不含现货缓冲多买) |
---
## 2. 双口径定义
### 2.1 口径 A — 期权复盘(交易账户)
```
本单已实现盈亏(U) = trading_usdt_after − trading_usdt_before
```
- **消费者**:期权复盘「交易记录」「复盘记录」、复盘 KPI
- **刻意含多买缓冲 / 滑点 / 手续费**:便于交易账户对账
- **门禁**:全部期权仓位已平 **且** 标的币无可卖量(粉尘可忽略)后才拍 `after` 并冻结
### 2.2 口径 B — 期权数据统计(历史 × 卖回价)
```
统计已实现盈亏(U) = 期权历史.realized_pnl(币) × 平仓卖回价
```
- **平仓卖回价**:优先卖回成交均价 / 冻结的 `close_index_px`;缺失时再用当时指数一次性冻结
- **消费者**:期权面板「数据统计」合计/胜率/盈亏比、数据统计页 KPI、顶栏期权窗口统计
- **不含**账户多买缓冲差分;与复盘 A **独立**,禁止混用
### 2.3 初始权利金与盈利率
| 字段 | 定义 |
|------|------|
| 初始权利金(U) | `open_index_px × premium_paid`(`premium_paid` 为开仓权利金币量;**不含** `budget_usdt` 多买) |
| 盈利率(复盘) | `realized_pnl_usdt(A) / initial_premium_usdt` |
| 盈利率(统计) | `统计盈亏(B) / initial_premium_usdt`(展示层可算,不强制落库) |
复盘列表与复盘详情须展示:初始权利金(U)、盈利率。
---
## 3. 产品规则
### 3.1 开仓前
1. 有可卖标的币(ETH/BTC)→ 拒开仓(粉尘低于现货最小可卖可忽略)。
2. 拍交易账户 USDT → `trading_usdt_before`。
3. 开仓前若有多次划转:以**开仓前最后一次划转完成后**的余额为准(即开仓瞬间余额)。
4. 开仓失败:回滚卖币,并拍**最新**资金快照(不留下脏 before / 半成品桥阻挡后续)。
5. 写入 `initial_premium_usdt = open_index_px × premium_paid`(开仓成功后)。
### 3.2 持仓中
1. 划转按钮灰 + API 拒绝。
2. 面板合计盈亏(动态)= `Σ口径B已冻结` + `当前持仓浮盈`。
3. 本单未完成 A 结算前:复盘显示「待结算」,不写假 U。
### 3.3 平仓与卖回
1. 系统可多次部分平仓;**以最后一次全部平仓完成**为准进入卖回。
2. 期权空仓后:**卖光**交易账户该标的可卖币(**禁止**用开仓权利金 `coin_bought` 封顶)。
3. `coin_bought` 仅用于开仓阶段清理过量买币,不作平仓卖回上限。
4. 卖回未完成(仍有可卖币):桥保持待卖回,**不**进入 A 结算。
5. 真粉尘(低于现货最小):可关桥并进入 A 结算(差额含粉尘损失)。
### 3.4 结算与冻结(A)
1. `realized_pnl_usdt = after − before`,`pnl_settled=1`。
2. 此后不得因划转、指数、复盘同步、监控公式而修改。
3. 仅复盘读此冻结值。
### 3.5 划转
| 时机 | 行为 |
|------|------|
| 无持仓、无待卖回 | 允许划转 |
| 持仓中或待卖回 | 禁止划转 |
| 划转后 | 只影响下一笔开仓前的 `usdt_before`;不重算已冻结 A/B |
---
## 4. 状态机
```text
IDLE
│ 有可卖币? ──是──> 拒开仓
│ 快照 trading_usdt_before(划转取最后一次后余额)
▼
OPENING ──失败──> 回滚卖币 → 最新资金快照 → IDLE
│ 成功(一次一仓);写 initial_premium_usdt
▼
OPEN(禁划转)
│ 可多次部分平仓
▼
CLOSING(交易所仓位未清零则停留)
│ 仓位 = 0
▼
SELLING_SPOT(卖光可卖标的币;禁止权利金封顶)
│ 可卖币 < minSz(真粉尘)或已空
▼
SETTLE_A(after − before → 冻结;仅此态可写 pnl_settled=1)
▼
IDLE
```
**硬门禁**
| 条件 | 行为 |
|------|------|
| OPEN / CLOSING / SELLING_SPOT | 禁止划转 |
| 未进 SETTLE_A | 复盘 U 为待结算 |
| pnl_settled=1 | 禁止覆盖 A |
| SETTLE_A | 要求 open_positions=0 且无可卖标的币 |
实现上可为显式状态字段,或由 `options_trades.status` + 桥状态 + `pnl_settled` 等价表达,但**结算入口必须统一校验门禁**。
---
## 5. 数据字段
### 5.1 `options_trades`
| 字段 | 含义 |
|------|------|
| `trading_usdt_before` | 开仓前交易账户 USDT |
| `trading_usdt_after` | 卖光后交易账户 USDT |
| `realized_pnl_usdt` | **口径 A** 冻结值 |
| `pnl_settled` | 0/1,A 是否已冻结 |
| `realized_pnl` | 币数量净盈亏(期权历史展示) |
| `close_index_px` | 平仓/卖回价(口径 B 用) |
| `open_index_px` | 开仓指数 |
| `premium_paid` | 开仓权利金币量 |
| `initial_premium_usdt` | 初始权利金 U = open_index × premium_paid |
| `budget_usdt` | 买币花费(含缓冲),**不得**当权利金或 before |
### 5.2 `options_review_trades`
| 字段 | 含义 |
|------|------|
| `realized_pnl_total` | **仅口径 A**(或待结算空) |
| `initial_premium_usdt` | 初始权利金 U |
| `profit_rate` | A / 初始权利金(小数,如 1.5 = 1.5 倍) |
### 5.3 `options_exchange_pnl_freeze`
实盘统计辅助:历史 key → 口径 B 的 U 冻结。
---
## 6. 模块行为
### 6.1 开仓 `open_coin_option_buy_full`
1. 一次一仓 / 未完成桥检查;可卖币拒开。
2. `trading_usdt_before`;买币、下单、写库(`pnl_settled=0`,`initial_premium_usdt`)。
3. 桥 `coin_bought` 可记为权利金币量(供开仓清过量),**平仓卖回不得用其封顶**。
### 6.2 划转 `POST /api/options/transfer`
持仓或桥 ∈ {bought, holding, pending_sell} → 拒绝。
### 6.3 卖回与 A 结算
`sell_residual_after_option_flat`(及 retry / sweep):
1. 空仓后卖光可用标的币(`coin_amount=None`)。
2. 仍有可卖 → 桥 `pending_sell`,返回未完成,**不结算**。
3. 仅粉尘/已空 → 关桥 → `try_settle_after_sellback`(内再校验无可卖币)→ A 冻结。
### 6.4 数据统计(口径 B)
- `net_realized_pnl` / 胜率 / 盈亏比:历史币盈亏 × 卖回价。
- **不读** `pnl_settled` 账户差分。
- 数据统计页不得再打复盘 stats API 作为盈亏真源。
### 6.5 期权复盘(口径 A)
- 同步本地已平:优先 `pnl_settled=1` 的 `realized_pnl_usdt`。
- 未结算:显示待结算,不导入假 U。
- 同步 `initial_premium_usdt`、`profit_rate`。
### 6.6 期权历史列表
仍按**币**展示权利金/币盈亏;U 只用于复盘(A)与数据统计(B)。
---
## 7. 对账关系
```
口径 A: Σ 已冻结单笔 A + 期间净划转 ≈ 交易账户相对首笔 before 的累计变化
口径 B: Σ (历史币盈亏 × 卖回价) ≈ 面板数据统计已实现
```
差异应可归因:粉尘、滑点、手续费(A 内已含);B 不含多买缓冲。
---
## 8. 非目标 / 不做
- 不用 `budget_usdt` 当单笔盈利或初始权利金。
- 不用口径 A 覆盖数据统计,也不用口径 B 覆盖复盘。
- 持仓中不因行情重算已冻结 A/B。
- 不把期权历史列表强制改为 U。
---
## 9. 历史数据修复
对已错误冻结的账户差分(典型:币盈亏>0 且 A 为负,且 `coin_sold≈premium_paid≪premium_received`):
1. 回填 `initial_premium_usdt = open_index_px × premium_paid`。
2. 口径 B:按币盈亏 × 卖回价重算统计侧(含 `options_exchange_pnl_freeze`)。
3. 口径 A:卖回完整可重建则重算;否则 `pnl_settled=0` 标 `needs_resettle` / 异常,勿盲信错账。
4. 重刷 `options_review_trades.realized_pnl_total` / `profit_rate`。
脚本:`scripts/repair_options_dual_pnl.py`(dry-run → CSV → apply)。
---
## 10. 验收清单
- [ ] 盈利约 1.5 倍单:卖回含盈利币;复盘 A 为正,约等于账户差分
- [ ] 卖回不得按开仓权利金封顶
- [ ] 仍有可卖币时不 `pnl_settled=1`
- [ ] 复盘展示初始权利金、盈利率
- [ ] 数据统计 = 历史币盈亏 × 卖回价,与复盘 A 可不同
- [ ] 开仓写入 before + initial_premium;失败有最新快照/回滚
- [ ] 持仓禁划转;空仓划转不影响已冻结
- [ ] 历史错账可用脚本修复
---
## 11. 修订记录
| 日期 | 说明 |
|------|------|
| 2026-10-09 | 初版:交易账户快照差分 + 一次一仓 + 持仓禁划转 + 卖回后冻结 |
| 2026-10-13 | 修订:双口径 A/B;卖光再结算;初始权利金/盈利率;状态机;历史修复脚本 |