Align OO Call/Put position cards with per-leg mark, size, leverage.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -72,13 +72,16 @@ def enrich_live_unrealized(
|
||||
logger.warning("live unrealized exchange overlay failed: %s", e)
|
||||
|
||||
option_upl = float(base.get("option_upl") or 0.0) # 期权净盈亏(本地)
|
||||
option2_upl = float(base.get("option2_upl") or 0.0) # 期期 Put 腿
|
||||
# 盯盘/达标:离场费 ≈ 入场费 → 合计扣 已付×2
|
||||
est_close = float(fees_paid)
|
||||
net_pnl = perp_upl + option_upl - fees_paid * 2.0 + funding
|
||||
# 期期无永续:perp_upl 一般为 0;仍加 option2
|
||||
net_pnl = perp_upl + option_upl + option2_upl - fees_paid * 2.0 + funding
|
||||
|
||||
out = dict(base)
|
||||
out["perp_upl"] = perp_upl
|
||||
out["option_upl"] = option_upl
|
||||
out["option2_upl"] = option2_upl
|
||||
out["fees_paid"] = fees_paid
|
||||
out["funding_usdt"] = funding
|
||||
out["est_close_fees"] = est_close
|
||||
|
||||
@@ -2012,15 +2012,23 @@ class Matcher:
|
||||
index_px = snap.perp.mark_px
|
||||
qty = float(pos.get("option_qty_eth") or 0)
|
||||
qty2 = float(pos.get("option2_qty_eth") or qty)
|
||||
contracts1 = float(pos.get("option_qty_contracts") or 0)
|
||||
contracts2 = float(pos.get("option2_qty_contracts") or 0)
|
||||
prem1 = float(pos.get("initial_premium") or 0)
|
||||
prem2 = float(pos.get("initial_premium2") or 0)
|
||||
call_id = str(pos.get("option_inst_id") or "")
|
||||
put_id = str(pos.get("option2_inst_id") or "")
|
||||
entry1 = float(pos.get("option_entry_px") or 0)
|
||||
entry2 = float(pos.get("option2_entry_px") or 0)
|
||||
oq1 = self._quote_held_option(call_id) if call_id else None
|
||||
oq2 = self._quote_held_option(put_id) if put_id else None
|
||||
option_upl = 0.0
|
||||
option2_upl = 0.0
|
||||
fees = 0.0
|
||||
opt_mark = None
|
||||
opt_bid_sz = None
|
||||
opt2_mark = None
|
||||
opt2_bid_sz = None
|
||||
if oq1 and oq1.bid is not None and qty > 0:
|
||||
bid = float(oq1.bid)
|
||||
of = option_fill(
|
||||
@@ -2032,6 +2040,13 @@ class Matcher:
|
||||
)
|
||||
fees += of.fee
|
||||
option_upl = bid * qty - prem1
|
||||
opt_mark = bid
|
||||
opt_bid_sz = float(oq1.bid_sz) if oq1.bid_sz is not None else None
|
||||
elif oq1:
|
||||
opt_mark = oq1.bid or oq1.mark_px
|
||||
opt_bid_sz = float(oq1.bid_sz) if oq1.bid_sz is not None else None
|
||||
if opt_mark is not None and qty > 0:
|
||||
option_upl = float(opt_mark) * qty - prem1
|
||||
if oq2 and oq2.bid is not None and qty2 > 0:
|
||||
bid = float(oq2.bid)
|
||||
of = option_fill(
|
||||
@@ -2043,15 +2058,51 @@ class Matcher:
|
||||
)
|
||||
fees += of.fee
|
||||
option2_upl = bid * qty2 - prem2
|
||||
opt2_mark = bid
|
||||
opt2_bid_sz = float(oq2.bid_sz) if oq2.bid_sz is not None else None
|
||||
elif oq2:
|
||||
opt2_mark = oq2.bid or oq2.mark_px
|
||||
opt2_bid_sz = float(oq2.bid_sz) if oq2.bid_sz is not None else None
|
||||
if opt2_mark is not None and qty2 > 0:
|
||||
option2_upl = float(opt2_mark) * qty2 - prem2
|
||||
g = None
|
||||
gid = pos.get("group_id")
|
||||
if gid:
|
||||
g = self.db.fetchone("SELECT * FROM groups WHERE group_id=?", (gid,))
|
||||
paid = float(g["fees"] or 0) if g else 0.0
|
||||
net = option_upl + option2_upl - paid - fees
|
||||
# SIM:浮盈 − 估平仓费;有入场费时离场按入场估算(对齐永期口径)
|
||||
if paid > 1e-12:
|
||||
est_close = paid
|
||||
net = option_upl + option2_upl - paid * 2.0
|
||||
else:
|
||||
est_close = fees
|
||||
net = option_upl + option2_upl - fees
|
||||
entry_idx = float(pos.get("entry_index_px") or 0)
|
||||
move = abs(float(index_px) - entry_idx) if index_px is not None and entry_idx else 0.0
|
||||
move_pct = (move / entry_idx * 100.0) if entry_idx > 0 else 0.0
|
||||
from ..strategy.selection import option_leverage as _opt_lev
|
||||
|
||||
opt_lev = (
|
||||
_opt_lev(entry_idx, entry1) if entry_idx > 0 and entry1 > 0 else None
|
||||
)
|
||||
opt2_lev = (
|
||||
_opt_lev(entry_idx, entry2) if entry_idx > 0 and entry2 > 0 else None
|
||||
)
|
||||
if opt_lev is not None:
|
||||
opt_lev = round(float(opt_lev), 1)
|
||||
if opt2_lev is not None:
|
||||
opt2_lev = round(float(opt2_lev), 1)
|
||||
expiry_ymd = str(g["expiry_ymd"]) if g and g["expiry_ymd"] else None
|
||||
expiry_ms = None
|
||||
if expiry_ymd and len(expiry_ymd) == 6:
|
||||
try:
|
||||
from ..exchange.expiry import expiry_ms_from_ymd
|
||||
|
||||
expiry_ms = expiry_ms_from_ymd(expiry_ymd)
|
||||
except Exception:
|
||||
expiry_ms = None
|
||||
strike1 = float(g["strike"]) if g and g["strike"] is not None else None
|
||||
strike2 = float(pos.get("strike2") or 0) or None
|
||||
return {
|
||||
"has_position": True,
|
||||
"hedge_mode": "option_option",
|
||||
@@ -2062,23 +2113,33 @@ class Matcher:
|
||||
"option2_upl": option2_upl,
|
||||
"net_pnl": net,
|
||||
"fees_paid": paid,
|
||||
"est_close_fees": fees,
|
||||
"est_close_fees": est_close,
|
||||
"index_px": float(index_px) if index_px is not None else None,
|
||||
"entry_index_px": entry_idx,
|
||||
"move_points": move,
|
||||
"move_pct": move_pct,
|
||||
"initial_premium": prem1 + prem2,
|
||||
"initial_premium": prem1,
|
||||
"initial_premium2": prem2,
|
||||
"option_inst_id": call_id,
|
||||
"option2_inst_id": put_id,
|
||||
"option_side": "call",
|
||||
"option2_side": "put",
|
||||
"option_qty_eth": qty,
|
||||
"option2_qty_eth": qty2,
|
||||
"option_entry_px": float(pos.get("option_entry_px") or 0),
|
||||
"option2_entry_px": float(pos.get("option2_entry_px") or 0),
|
||||
"strike": float(g["strike"]) if g and g["strike"] is not None else None,
|
||||
"strike2": float(pos.get("strike2") or 0) or None,
|
||||
"expiry_ymd": g["expiry_ymd"] if g else None,
|
||||
"option_qty_contracts": contracts1,
|
||||
"option2_qty_contracts": contracts2,
|
||||
"option_entry_px": entry1,
|
||||
"option2_entry_px": entry2,
|
||||
"option_mark_px": float(opt_mark) if opt_mark is not None else None,
|
||||
"option_bid_sz": float(opt_bid_sz) if opt_bid_sz is not None else None,
|
||||
"option2_mark_px": float(opt2_mark) if opt2_mark is not None else None,
|
||||
"option2_bid_sz": float(opt2_bid_sz) if opt2_bid_sz is not None else None,
|
||||
"option_leverage": float(opt_lev) if opt_lev is not None else None,
|
||||
"option2_leverage": float(opt2_lev) if opt2_lev is not None else None,
|
||||
"strike": strike1,
|
||||
"strike2": strike2,
|
||||
"expiry_ymd": expiry_ymd,
|
||||
"expiry_ms": expiry_ms,
|
||||
"open_at_ms": int(g["open_at_ms"]) if g and g["open_at_ms"] else None,
|
||||
"perp_side": None,
|
||||
"perp_qty_eth": 0.0,
|
||||
|
||||
Reference in New Issue
Block a user