fix期权复盘与数据统计双口径盈亏,并修复卖回封顶导致盈利单冻成亏损。
平仓卖光可卖币后再按账户差分结算复盘;数据统计改为历史币盈亏×卖回价;复盘展示初始权利金与盈利率,并附历史修复脚本。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -59,11 +59,16 @@ def _underlying_index_usdt(ex: Any, underly: str) -> float | None:
|
||||
return None
|
||||
|
||||
|
||||
def history_pnl_to_usdt(history: list[dict[str, Any]], ex: Any = None) -> list[dict[str, Any]]:
|
||||
"""
|
||||
统计用:优先已冻结的 realized_pnl_usdt(平仓当时口径,含手续费后净额);
|
||||
否则币本位用 close_index_px(再否则实时指数)折 U;USDC 原样.
|
||||
折算失败的币仓剔除盈亏字段,避免把「币数量」当成 U.
|
||||
def history_pnl_to_usdt(
|
||||
history: list[dict[str, Any]],
|
||||
ex: Any = None,
|
||||
*,
|
||||
prefer_frozen_usdt: bool = True,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""折 U.
|
||||
|
||||
prefer_frozen_usdt=True:优先行内 realized_pnl_usdt(实盘 exchange freeze / 旧兼容).
|
||||
prefer_frozen_usdt=False:口径 B — 币盈亏 × 平仓卖回价(close_index_px),忽略账户差分 A.
|
||||
"""
|
||||
from lib.options.options_margin_mode_lib import margin_mode_from_inst_id, premium_ccy_for_mode
|
||||
|
||||
@@ -75,7 +80,7 @@ def history_pnl_to_usdt(history: list[dict[str, Any]], ex: Any = None) -> list[d
|
||||
out.append(r)
|
||||
continue
|
||||
frozen = _safe_float(r.get("realized_pnl_usdt"))
|
||||
if frozen is not None:
|
||||
if prefer_frozen_usdt and frozen is not None:
|
||||
r["realized_pnl"] = round(float(frozen), 4)
|
||||
out.append(r)
|
||||
continue
|
||||
@@ -104,6 +109,11 @@ def history_pnl_to_usdt(history: list[dict[str, Any]], ex: Any = None) -> list[d
|
||||
return out
|
||||
|
||||
|
||||
def history_pnl_to_usdt_stats(history: list[dict[str, Any]], ex: Any = None) -> list[dict[str, Any]]:
|
||||
"""数据统计口径 B:期权历史币盈亏 × 平仓卖回价."""
|
||||
return history_pnl_to_usdt(history, ex, prefer_frozen_usdt=False)
|
||||
|
||||
|
||||
def _parse_ts(raw: Any) -> datetime | None:
|
||||
if raw is None or raw == "":
|
||||
return None
|
||||
@@ -286,7 +296,8 @@ def _closed_trade_dicts(closed_rows) -> list[dict[str, Any]]:
|
||||
{
|
||||
"status": "closed",
|
||||
"realized_pnl": _row_get(row, "realized_pnl"),
|
||||
"realized_pnl_usdt": _row_get(row, "realized_pnl_usdt"),
|
||||
# 口径 B 不读账户 realized_pnl_usdt;保留键位兼容旧调用
|
||||
"realized_pnl_usdt": None,
|
||||
"close_index_px": _row_get(row, "close_index_px"),
|
||||
"created_at": _row_get(row, "created_at"),
|
||||
"closed_at": _row_get(row, "closed_at"),
|
||||
@@ -298,16 +309,13 @@ def _closed_trade_dicts(closed_rows) -> list[dict[str, Any]]:
|
||||
return out
|
||||
|
||||
|
||||
# 口径 B:凡有币盈亏的已平均计入;U 由 history_pnl_to_usdt_stats 按卖回价折算
|
||||
_CLOSED_STATS_SELECT = """
|
||||
SELECT realized_pnl, realized_pnl_usdt, close_index_px,
|
||||
SELECT realized_pnl, close_index_px,
|
||||
created_at, closed_at, inst_id, underlying, premium_ccy
|
||||
FROM options_trades
|
||||
WHERE status = 'closed'
|
||||
AND (
|
||||
(COALESCE(pnl_settled, 0) = 1 AND realized_pnl_usdt IS NOT NULL)
|
||||
OR (trading_usdt_before IS NULL
|
||||
AND (realized_pnl IS NOT NULL OR realized_pnl_usdt IS NOT NULL))
|
||||
)
|
||||
AND realized_pnl IS NOT NULL
|
||||
"""
|
||||
|
||||
|
||||
@@ -634,7 +642,7 @@ def apply_exchange_pnl_freeze(
|
||||
|
||||
|
||||
def compute_options_stats(get_db, ex: Any = None) -> dict[str, Any]:
|
||||
"""模拟盘:本地交易结算.实盘请用 compute_options_stats_live_exchange."""
|
||||
"""模拟盘数据统计:口径 B(历史币盈亏×卖回价)."""
|
||||
conn = get_db()
|
||||
try:
|
||||
history = load_local_options_stats_history(conn, ex)
|
||||
@@ -642,7 +650,7 @@ def compute_options_stats(get_db, ex: Any = None) -> dict[str, Any]:
|
||||
conn.commit()
|
||||
except Exception:
|
||||
pass
|
||||
return compute_options_stats_from_history(history_pnl_to_usdt(history, ex))
|
||||
return compute_options_stats_from_history(history_pnl_to_usdt_stats(history, ex))
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
@@ -717,9 +725,11 @@ def load_live_exchange_stats_history(cfg: dict[str, Any], ex: Any) -> list[dict[
|
||||
|
||||
|
||||
def compute_options_stats_live_exchange(cfg: dict[str, Any], ex: Any) -> dict[str, Any]:
|
||||
"""实盘:与「期权历史」同一数据源(交易所 positions-history),盈亏以交易所为准."""
|
||||
"""实盘:与「期权历史」同一数据源;口径 B=币盈亏×卖回价(freeze)."""
|
||||
history = load_live_exchange_stats_history(cfg, ex)
|
||||
return compute_options_stats_from_history(history_pnl_to_usdt(history, ex))
|
||||
return compute_options_stats_from_history(
|
||||
history_pnl_to_usdt(history, ex, prefer_frozen_usdt=True)
|
||||
)
|
||||
|
||||
|
||||
def _apply_exchange_pnl_freeze_with_hints(
|
||||
@@ -812,7 +822,7 @@ def _stats_from_option_trade_rows(closed_rows, open_rows, *, ex: Any = None) ->
|
||||
history = _closed_trade_dicts(closed_rows)
|
||||
for row in open_rows or []:
|
||||
history.append({"status": "open", "created_at": _row_get(row, "created_at")})
|
||||
return compute_options_stats_from_history(history_pnl_to_usdt(history, ex))
|
||||
return compute_options_stats_from_history(history_pnl_to_usdt_stats(history, ex))
|
||||
|
||||
|
||||
def header_options_stats_for_window(
|
||||
@@ -821,32 +831,20 @@ def header_options_stats_for_window(
|
||||
app_tz,
|
||||
ex: Any = None,
|
||||
) -> dict[str, Any]:
|
||||
"""顶栏总交易/胜率/盈亏比:与期权统计同一结算口径.
|
||||
|
||||
新单(有 trading_usdt_before):仅 pnl_settled=1 的账户差分计入;
|
||||
旧单(无 before):仍按原 realized 兼容.币数量须折 U 后再算盈亏比.
|
||||
"""
|
||||
"""顶栏总交易/胜率/盈亏比:口径 B(历史币盈亏×卖回价)."""
|
||||
from lib.common.history_window_lib import utc_window_to_bj_sql_strings
|
||||
|
||||
init_options_tables(conn)
|
||||
start_bj, end_bj = utc_window_to_bj_sql_strings(
|
||||
list_window["start_utc"], list_window["end_utc"], app_tz
|
||||
)
|
||||
try:
|
||||
freeze_missing_realized_pnl_usdt(conn, ex)
|
||||
except Exception:
|
||||
pass
|
||||
closed_rows = conn.execute(
|
||||
"""
|
||||
SELECT realized_pnl, realized_pnl_usdt, close_index_px,
|
||||
SELECT realized_pnl, close_index_px,
|
||||
created_at, closed_at, inst_id, underlying, premium_ccy
|
||||
FROM options_trades
|
||||
WHERE status = 'closed'
|
||||
AND (
|
||||
(COALESCE(pnl_settled, 0) = 1 AND realized_pnl_usdt IS NOT NULL)
|
||||
OR (trading_usdt_before IS NULL
|
||||
AND (realized_pnl IS NOT NULL OR realized_pnl_usdt IS NOT NULL))
|
||||
)
|
||||
AND realized_pnl IS NOT NULL
|
||||
AND COALESCE(closed_at, created_at) >= ?
|
||||
AND COALESCE(closed_at, created_at) <= ?
|
||||
""",
|
||||
@@ -858,7 +856,7 @@ def header_options_stats_for_window(
|
||||
history = _closed_trade_dicts(closed_rows)
|
||||
for row in open_rows:
|
||||
history.append({"status": "open", "created_at": _row_get(row, "created_at")})
|
||||
stats = compute_options_stats_from_history(history_pnl_to_usdt(history, ex))
|
||||
stats = compute_options_stats_from_history(history_pnl_to_usdt_stats(history, ex))
|
||||
return {
|
||||
"total": int(stats.get("total_closed") or 0),
|
||||
"rate": float(stats.get("win_rate") or 0),
|
||||
|
||||
Reference in New Issue
Block a user