fix复盘真盈亏按权利金USDT波动公式计算,忽略现货多买。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-13 10:16:44 +08:00
parent c2c69e580c
commit 3416996ae5
10 changed files with 249 additions and 280 deletions
+28 -87
View File
@@ -236,68 +236,6 @@ def try_settle_after_sellback(
pass
def resolve_true_pnl_usdt(
conn,
*,
trading_usdt_before: Any = None,
trading_usdt_after: Any = None,
bridge_id: Any = None,
realized_pnl_usdt: Any = None,
pnl_settled: Any = False,
) -> tuple[float | None, str]:
"""真盈亏(口径 A)=卖光标的币收回 USDT − 开仓买币花费.
优先账户快照 after−before(与上式等价);其次已关桥的「卖回累计−买币预算」.
绝不回退权利金×指数(那是口径 B / 期权腿).
返回 (pnl_u, source): account | bridge | frozen | none
"""
before = _safe_float(trading_usdt_before)
after = _safe_float(trading_usdt_after)
if before is not None and after is not None:
return round(float(after) - float(before), 4), "account"
bid = None
try:
if bridge_id is not None and str(bridge_id).strip() != "":
bid = int(bridge_id)
except (TypeError, ValueError):
bid = None
if bid is not None:
try:
from lib.options.options_spot_bridge_lib import (
BRIDGE_CLOSED,
cash_pnl_usdt_from_bridge,
ensure_bridge_table,
)
ensure_bridge_table(conn)
brow = conn.execute(
"SELECT status, usdt_recovered FROM options_spot_bridge WHERE id=?",
(bid,),
).fetchone()
if brow:
st = str(brow["status"] if hasattr(brow, "keys") else brow[0] or "")
recovered = _safe_float(
brow["usdt_recovered"] if hasattr(brow, "keys") else brow[1]
)
if st == BRIDGE_CLOSED and recovered is not None:
bp = cash_pnl_usdt_from_bridge(conn, bid)
if bp is not None:
return bp, "bridge"
except Exception:
pass
try:
settled = int(pnl_settled or 0) == 1
except (TypeError, ValueError):
settled = bool(pnl_settled)
frozen = _safe_float(realized_pnl_usdt)
# 仅承认「有 before 且已账户结算」的旧冻结;无快照的指数折 U 不算真盈亏
if settled and before is not None and frozen is not None:
return round(float(frozen), 4), "frozen"
return None, "none"
def settle_closed_trades_from_trading_account(
conn,
*,
@@ -305,15 +243,17 @@ def settle_closed_trades_from_trading_account(
bridge_id: int | None = None,
trade_id: int | None = None,
) -> int:
"""卖回后:对本桥/本单未结算已平仓位冻结真盈亏.
"""卖回后:拍 after 快照,并冻结复盘真盈亏(权利金 USDT 波动口径).
优先 after−before;账户 after 缺失时用桥「卖回−买币」.
已 pnl_settled=1 的行永不改写.
realized_pnl_usdt = 历史币盈亏×卖回价 − (权利金×开仓价 − 权利金×卖回价);
不含现货多买.账户 after 仅审计.已 pnl_settled=1 的行永不改写.
"""
from lib.options.options_pnl_settle_lib import resolve_true_pnl_usdt_from_trade
after = _safe_float(trading_usdt_after)
if after is not None:
after = round(float(after), 8)
clauses = ["status='closed'", "COALESCE(pnl_settled, 0)=0", "trading_usdt_before IS NOT NULL"]
clauses = ["status='closed'", "COALESCE(pnl_settled, 0)=0"]
params: list[Any] = []
if trade_id is not None:
clauses.append("id=?")
@@ -325,7 +265,8 @@ def settle_closed_trades_from_trading_account(
return 0
rows = conn.execute(
f"""
SELECT id, trading_usdt_before, realized_pnl_usdt, bridge_id
SELECT id, trading_usdt_before, premium_paid, premium_received, realized_pnl,
open_index_px, close_index_px, open_fee, close_fee, premium_ccy, fee_ccy
FROM options_trades
WHERE {" AND ".join(clauses)}
""",
@@ -334,30 +275,30 @@ def settle_closed_trades_from_trading_account(
updated = 0
for row in rows:
tid = int(row["id"] if hasattr(row, "keys") else row[0])
before = _safe_float(row["trading_usdt_before"] if hasattr(row, "keys") else row[1])
if before is None:
continue
row_bid = row["bridge_id"] if hasattr(row, "keys") else row[3]
if row_bid is None and bridge_id is not None:
row_bid = bridge_id
before = _safe_float(
row["trading_usdt_before"] if hasattr(row, "keys") else row[1]
)
after_use = after
if after_use is not None:
pnl_u = round(float(after_use) - float(before), 4)
else:
pnl_u, src = resolve_true_pnl_usdt(
conn,
trading_usdt_before=before,
trading_usdt_after=None,
bridge_id=row_bid,
pnl_settled=0,
)
if pnl_u is None or src != "bridge":
continue
after_use = round(float(before) + float(pnl_u), 8)
if after_use is None and before is not None:
# 无 after 读数时不编造;仍可用权利金公式冻结
after_use = None
pnl_u, src = resolve_true_pnl_usdt_from_trade(
premium_paid=row["premium_paid"] if hasattr(row, "keys") else row[2],
premium_received=row["premium_received"] if hasattr(row, "keys") else row[3],
realized_pnl=row["realized_pnl"] if hasattr(row, "keys") else row[4],
open_index_px=row["open_index_px"] if hasattr(row, "keys") else row[5],
close_index_px=row["close_index_px"] if hasattr(row, "keys") else row[6],
open_fee=row["open_fee"] if hasattr(row, "keys") else row[7],
close_fee=row["close_fee"] if hasattr(row, "keys") else row[8],
premium_ccy=row["premium_ccy"] if hasattr(row, "keys") else row[9],
fee_ccy=row["fee_ccy"] if hasattr(row, "keys") else row[10],
)
if pnl_u is None or src == "none":
continue
conn.execute(
"""
UPDATE options_trades
SET trading_usdt_after = ?,
SET trading_usdt_after = COALESCE(?, trading_usdt_after),
realized_pnl_usdt = ?,
pnl_settled = 1
WHERE id = ? AND COALESCE(pnl_settled, 0)=0