fix复盘交易记录盈亏与数据统计同口径,并展示期权手续费。

列表盈亏改为币盈亏×卖回价;手续费仅计期权开/平,不含现货。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-13 09:29:40 +08:00
parent fe08fa5270
commit bdc9eb532a
5 changed files with 65 additions and 37 deletions
+2
View File
@@ -133,6 +133,8 @@ def init_options_review_tables(conn: sqlite3.Connection) -> None:
_ensure_column(conn, "options_review_trades", "profit_rr", "REAL")
_ensure_column(conn, "options_review_trades", "initial_premium_usdt", "REAL")
_ensure_column(conn, "options_review_trades", "profit_rate", "REAL")
# 仅期权开/平手续费折 U(不含现货买币/卖回)
_ensure_column(conn, "options_review_trades", "option_fee_usdt", "REAL")
_ensure_column(conn, "options_review_entries", "prev_entry_tf", "TEXT")
+29 -19
View File
@@ -148,6 +148,7 @@ def upsert_option_history_row(conn: sqlite3.Connection, row: dict[str, Any]) ->
"realized_pnl": pnl,
"initial_premium_usdt": _safe_float(row.get("initial_premium_usdt")),
"profit_rate": _safe_float(row.get("profit_rate")),
"option_fee_usdt": _safe_float(row.get("option_fee_usdt")),
}
cols = list(fields.keys())
if existing:
@@ -319,7 +320,8 @@ def sync_options_from_local_trades(
open_quote, close_quote, premium_paid, premium_received, realized_pnl,
realized_pnl_usdt, close_index_px, open_index_px, budget_usdt,
premium_ccy, created_at, closed_at, signal_note, status,
trading_usdt_before, pnl_settled, initial_premium_usdt
trading_usdt_before, pnl_settled, initial_premium_usdt,
open_fee, close_fee
FROM options_trades
WHERE status = 'closed'
ORDER BY id DESC
@@ -411,16 +413,9 @@ def sync_options_from_local_trades(
ccy = str(r["premium_ccy"] or "").strip().upper()
if not ccy:
ccy = premium_ccy_for_mode(margin_mode_from_inst_id(inst), underly)
frozen_usdt = _safe_float(r["realized_pnl_usdt"])
try:
settled = int(r["pnl_settled"] or 0) == 1
except Exception:
settled = False
# 账户快照路径:未结算不写 U,避免指数假数进复盘
acct_pending = _safe_float(r["trading_usdt_before"]) is not None and not settled
close_idx = _safe_float(r["close_index_px"])
open_idx = _safe_float(r["open_index_px"])
# 折算指数:平仓冻结 > 开仓 > 实时(仅无冻结时兜底)
# 折算指数:平仓卖回价 > 开仓 > 实时(仅无冻结时兜底)
idx = None
if close_idx is not None and close_idx > 0:
idx = close_idx
@@ -435,22 +430,36 @@ def sync_options_from_local_trades(
if paid0 is not None and recv0 is not None:
pnl = recv0 - paid0
prem = _safe_float(r["premium_paid"])
if acct_pending:
pnl_u = None
elif frozen_usdt is not None and (settled or _safe_float(r["trading_usdt_before"]) is None):
pnl_u = round(float(frozen_usdt), 4)
else:
pnl_u = _to_usdt(pnl, ccy=ccy, idx=idx)
# 期权交易记录盈亏与数据统计同口径 B:币盈亏 × 平仓卖回价(不用账户差分 A)
pnl_u = _to_usdt(pnl, ccy=ccy, idx=idx)
# 初始权利金(U)=开仓指数×权利金币量;不含多买
stored_initial = _safe_float(r["initial_premium_usdt"])
open_idx_for_prem = open_idx if (open_idx is not None and open_idx > 0) else idx
prem_u = stored_initial
if prem_u is None:
prem_u = _to_usdt(prem, ccy=ccy, idx=open_idx_for_prem)
if ccy in ("ETH", "BTC") and pnl_u is None and not acct_pending:
pnl_u = pnl
if ccy in ("ETH", "BTC") and pnl_u is None:
pnl_u = None
if ccy in ("ETH", "BTC") and prem_u is None:
prem_u = prem
# 仅期权开/平手续费折 U(不含现货)
ofee = abs(_safe_float(r["open_fee"]) or 0.0)
cfee = abs(_safe_float(r["close_fee"]) or 0.0)
fee_u = None
if ccy in ("ETH", "BTC"):
fee_parts = 0.0
has_fee = False
if ofee > 0 and open_idx_for_prem is not None and open_idx_for_prem > 0:
fee_parts += ofee * float(open_idx_for_prem)
has_fee = True
sell_idx = close_idx if (close_idx is not None and close_idx > 0) else idx
if cfee > 0 and sell_idx is not None and sell_idx > 0:
fee_parts += cfee * float(sell_idx)
has_fee = True
if has_fee:
fee_u = round(fee_parts, 4)
elif ofee > 0 or cfee > 0:
fee_u = round(ofee + cfee, 4)
profit_rate = None
if pnl_u is not None and prem_u is not None and abs(float(prem_u)) > 1e-12:
profit_rate = round(float(pnl_u) / float(prem_u), 6)
@@ -470,12 +479,13 @@ def sync_options_from_local_trades(
"open_avg_px": r["open_quote"],
"close_avg_px": r["close_quote"],
"premium_paid": prem_u if prem_u is not None else prem,
"realized_pnl": pnl_u if pnl_u is not None else (None if acct_pending else pnl),
"realized_pnl": pnl_u,
"initial_premium_usdt": prem_u,
"profit_rate": profit_rate,
"option_fee_usdt": fee_u,
"created_at": opened_at,
"closed_at": closed_at,
"status_label": "待结算" if acct_pending else "已平",
"status_label": "已平",
},
)
if action == "inserted":
@@ -77,7 +77,7 @@
.or-list-loading{opacity:.55;pointer-events:none;transition:opacity .12s ease}
.or-trades-table-wrap,.or-reviewed-table-wrap{min-height:9.5rem;overflow-x:auto}
.or-reviewed-table{min-width:1180px}
.or-trades-table{min-width:960px}
.or-trades-table{min-width:1080px}
.or-kpi-row{
display:grid;grid-template-columns:repeat(6,minmax(0,1fr));
gap:8px;margin-bottom:12px;
@@ -241,6 +241,7 @@
<th>初始权利金</th>
<th>盈亏</th>
<th>盈利率</th>
<th>手续费</th>
<th>开仓时间</th>
<th>平仓时间</th>
<th>持有</th>
@@ -248,7 +249,7 @@
</tr>
</thead>
<tbody id="or-trades-tbody">
<tr><td colspan="9" class="muted">加载中…</td></tr>
<tr><td colspan="10" class="muted">加载中…</td></tr>
</tbody>
</table>
</div>
@@ -285,6 +286,7 @@
autocomplete="off" inputmode="decimal" data-lpignore="true" data-1p-ignore="true" data-form-type="other">
<input type="text" id="or-f-initial-prem" name="or_f_initial_prem" placeholder="初始权利金(U)" readonly autocomplete="off">
<input type="text" id="or-f-profit-rate" name="or_f_profit_rate" placeholder="盈利率" readonly autocomplete="off">
<input type="text" id="or-f-option-fee" name="or_f_option_fee" placeholder="期权手续费(U)" readonly autocomplete="off" title="仅期权开/平手续费,不含现货">
<input type="text" id="or-f-hold" name="or_f_hold" placeholder="持有时长" readonly autocomplete="off">
</div>
<div class="or-form-grid2">