Show editable exit on live cards; price perp PnL via close-side book VWAP.
Align monitor profit-exit with the same book VWAP so card and auto-exit stay consistent. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Any, Optional
|
||||
|
||||
from lib.hedge_plan.hedge_plan_book_lib import fetch_perp_close_vwap
|
||||
from lib.hedge_plan.hedge_plan_option_primary_lib import (
|
||||
estimate_combo_net_pnl,
|
||||
fee_rate,
|
||||
@@ -129,6 +130,12 @@ def build_live_hedge_cards(cfg: dict[str, Any], conn: Any) -> list[dict[str, Any
|
||||
get_perp_metrics = cfg.get("get_live_position_exchange_metrics")
|
||||
get_cs = cfg.get("get_contract_size")
|
||||
fetch_idx = cfg.get("fetch_index_price")
|
||||
ex_perp = None
|
||||
try:
|
||||
get_pex = cfg.get("exchange")
|
||||
ex_perp = get_pex() if callable(get_pex) else get_pex
|
||||
except Exception:
|
||||
ex_perp = None
|
||||
fr = fee_rate()
|
||||
fr_opt = option_fee_rate()
|
||||
now_ms = int(datetime.now(tz=_BJ).timestamp() * 1000)
|
||||
@@ -205,6 +212,21 @@ def build_live_hedge_cards(cfg: dict[str, Any], conn: Any) -> list[dict[str, Any
|
||||
if (margin is None or margin <= 0) and contracts and perp_mark and perp_lev and perp_lev > 0:
|
||||
margin = round(float(contracts) * float(cs) * float(perp_mark) / float(perp_lev), 2)
|
||||
|
||||
# 永续净利:按平仓方向扫盘口 VWAP(方案 A);标记价仅参考
|
||||
book = fetch_perp_close_vwap(
|
||||
ex_perp,
|
||||
symbol=sym,
|
||||
position_side=perp_dir,
|
||||
contracts=float(contracts or 0),
|
||||
fallback_px=perp_mark or perp_entry,
|
||||
)
|
||||
perp_vwap = _sf(book.get("vwap")) or perp_mark or perp_entry
|
||||
perp_liq_ok = bool(book.get("liq_ok")) if book.get("ok") else False
|
||||
perp_liq_msg = str(book.get("msg") or "")
|
||||
perp_top = _sf(book.get("top_px"))
|
||||
perp_top_sz = _sf(book.get("top_sz"))
|
||||
book_side = str(book.get("book_side") or "")
|
||||
|
||||
idx = None
|
||||
if callable(fetch_idx):
|
||||
try:
|
||||
@@ -212,7 +234,7 @@ def build_live_hedge_cards(cfg: dict[str, Any], conn: Any) -> list[dict[str, Any
|
||||
except Exception:
|
||||
idx = None
|
||||
if idx is None or idx <= 0:
|
||||
idx = perp_mark or strike or 0.0
|
||||
idx = perp_vwap or perp_mark or strike or 0.0
|
||||
|
||||
net = estimate_combo_net_pnl(
|
||||
view_side=view,
|
||||
@@ -224,7 +246,7 @@ def build_live_hedge_cards(cfg: dict[str, Any], conn: Any) -> list[dict[str, Any
|
||||
ct_mult=float(ct or 0.01),
|
||||
perp_direction=perp_dir,
|
||||
perp_entry=float(perp_entry or 0),
|
||||
perp_mark=float(perp_mark or 0),
|
||||
perp_mark=float(perp_vwap or 0),
|
||||
contracts=float(contracts or 0),
|
||||
contract_size=float(cs or 0.01),
|
||||
fee=fr,
|
||||
@@ -245,6 +267,10 @@ def build_live_hedge_cards(cfg: dict[str, Any], conn: Any) -> list[dict[str, Any
|
||||
hold_sec = int((now_ms - opened_ms) / 1000) if opened_ms else None
|
||||
remain_sec = int((exp_ms - now_ms) / 1000) if exp_ms else None
|
||||
|
||||
exit_mode = str(plan.get("exit_mode") or "").strip().lower()
|
||||
if exit_mode not in ("profit", "target"):
|
||||
exit_mode = "profit" if _sf(plan.get("profit_target_usdt")) else "target"
|
||||
|
||||
out.append(
|
||||
{
|
||||
"plan_id": plan.get("id"),
|
||||
@@ -260,6 +286,12 @@ def build_live_hedge_cards(cfg: dict[str, Any], conn: Any) -> list[dict[str, Any
|
||||
"index_px": idx,
|
||||
"fee_rate": fr,
|
||||
"option_fee_rate": fr_opt,
|
||||
"exit": {
|
||||
"mode": exit_mode,
|
||||
"profit_target_usdt": _sf(plan.get("profit_target_usdt")),
|
||||
"option_target_points": _sf(plan.get("option_target_points")),
|
||||
"perp_target_points": _sf(plan.get("perp_target_points")),
|
||||
},
|
||||
"option": {
|
||||
"inst_id": inst_id or "—",
|
||||
"opt_type": opt_type,
|
||||
@@ -286,17 +318,23 @@ def build_live_hedge_cards(cfg: dict[str, Any], conn: Any) -> list[dict[str, Any
|
||||
"contract_size": cs,
|
||||
"avg_open": perp_entry,
|
||||
"mark_px": perp_mark,
|
||||
"vwap": perp_vwap,
|
||||
"book_side": book_side,
|
||||
"top_px": perp_top,
|
||||
"top_sz": perp_top_sz,
|
||||
"liq_ok": perp_liq_ok,
|
||||
"liq_msg": perp_liq_msg,
|
||||
"leverage": perp_lev or None,
|
||||
"margin": margin,
|
||||
"upl": perp_upl,
|
||||
"net_usdt": perp_net,
|
||||
"live": perp_upl is not None or (perp_mark is not None and perp_mark > 0),
|
||||
"live": bool(book.get("ok")) or perp_upl is not None,
|
||||
},
|
||||
"combo": {
|
||||
"net_usdt": combo_usdt,
|
||||
"opt_net_usdt": opt_net_usdt,
|
||||
"perp_net_usdt": perp_net,
|
||||
"note": "扣开平双边手续费后估",
|
||||
"note": "扣开平双边手续费;永续按盘口均价估",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user