Polish dashboard tables: hub-style orders, options source/expiry, hedge status.

Show 进行中 in green for active hedges; options columns include source/target/expiry; merge live mark/contracts/pnl from price snapshot.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-17 12:23:25 +08:00
parent cd2dfac2ba
commit 35117ba84e
7 changed files with 365 additions and 85 deletions
+129 -47
View File
@@ -67,12 +67,137 @@ def _format_order_item(od: dict[str, Any]) -> dict[str, Any]:
"direction": direction,
"direction_label": _dir_label(direction),
"entry": entry,
"mark_price": None,
"contracts": _safe_float(od.get("order_amount")),
"tp_profit": None,
"float_pnl": None,
"stop_loss": sl,
"take_profit": tp,
"status": od.get("status") or "active",
}
OPTIONS_SOURCE_LABELS = {
"option": "纯期权",
"perp_options": "永期对冲",
"options_options": "期期对冲",
}
HEDGE_ACTIVE_STATUSES = frozenset({"opening", "active", "partial"})
def _resolve_options_source(conn, inst_id: str) -> tuple[str, str]:
"""根据进行中对冲计划腿判定来源;默认纯期权."""
if not inst_id or not _table_exists(conn, "hedge_plans") or not _table_exists(conn, "hedge_plan_legs"):
return "option", OPTIONS_SOURCE_LABELS["option"]
try:
row = conn.execute(
"""
SELECT p.plan_type
FROM hedge_plans p
JOIN hedge_plan_legs l ON l.plan_id = p.id
WHERE p.status IN ('opening', 'active', 'partial')
AND l.status = 'open'
AND l.inst_id = ?
ORDER BY p.id DESC
LIMIT 1
""",
(inst_id,),
).fetchone()
except Exception:
return "option", OPTIONS_SOURCE_LABELS["option"]
if not row:
return "option", OPTIONS_SOURCE_LABELS["option"]
pt = str((_row_dict(row).get("plan_type") if isinstance(row, dict) else row[0]) or "").strip()
if pt in OPTIONS_SOURCE_LABELS:
return pt, OPTIONS_SOURCE_LABELS[pt]
return "option", OPTIONS_SOURCE_LABELS["option"]
def _format_options_target(p: dict[str, Any]) -> str:
hedge = p.get("hedge_plan_target") if isinstance(p.get("hedge_plan_target"), dict) else None
opt_type = str(p.get("opt_type") or p.get("optType") or "").upper()
if hedge:
ot = str(hedge.get("opt_type") or opt_type).upper()
side = "Put ≤" if ot == "P" else "Call ≥"
tgt = _safe_float(hedge.get("target_index"))
pid = hedge.get("plan_id")
if tgt is not None:
return f"对冲#{pid} {side} {tgt:g}" if pid is not None else f"{side} {tgt:g}"
tgt = _safe_float(p.get("target_index"))
if tgt is not None and tgt > 0:
side = "Put ≤" if opt_type == "P" else "Call ≥"
return f"{side} {tgt:g}"
return ""
def _format_options_item(p: dict[str, Any], *, conn=None) -> dict[str, Any]:
inst = str(p.get("inst_id") or p.get("instId") or "-").strip() or "-"
opt_type = str(p.get("opt_type") or p.get("optType") or "").upper()
label = "Call" if opt_type == "C" else "Put" if opt_type == "P" else (opt_type or "OPT")
upl = _safe_float(p.get("upl"))
net = None
try:
from lib.options.options_positions_lib import net_pnl_from_display_row
net = net_pnl_from_display_row(p)
except Exception:
net = None
pnl = net if net is not None else upl
pos = _safe_float(p.get("pos"))
exp_ms = p.get("exp_time_ms")
if exp_ms is None:
exp_ms = p.get("exp_time")
try:
exp_ms = int(float(exp_ms)) if exp_ms not in (None, "") else None
except (TypeError, ValueError):
exp_ms = None
source_key, source_label = (
_resolve_options_source(conn, inst) if conn is not None else ("option", OPTIONS_SOURCE_LABELS["option"])
)
return {
"id": inst,
"kind": "options",
"tab": "options",
"title": f"{inst} {label}",
"subtitle": f"张数 {pos if pos is not None else '-'}",
"inst_id": inst,
"opt_type": opt_type,
"opt_type_label": label,
"source": source_key,
"source_label": source_label,
"pos": pos,
"exp_time_ms": exp_ms,
"target_monitor": _format_options_target(p),
"pnl": round(pnl, 4) if pnl is not None else None,
}
def _format_hedge_item(plan: dict[str, Any]) -> dict[str, Any]:
pid = plan.get("id")
underlying = plan.get("underlying") or "-"
plan_type = plan.get("plan_type") or ""
status = str(plan.get("status") or "")
summary = plan.get("contracts_summary") or ""
plan_type_label = OPTIONS_SOURCE_LABELS.get(plan_type, plan_type)
active = status in HEDGE_ACTIVE_STATUSES
status_label = "进行中" if active else (status or "")
return {
"id": pid,
"kind": "hedge_plan",
"tab": "hedge_plan",
"title": f"对冲 #{pid} {underlying}",
"subtitle": " · ".join(x for x in (plan_type_label, status_label, summary) if x),
"underlying": underlying,
"plan_type": plan_type,
"plan_type_label": plan_type_label,
"status": status,
"status_label": status_label,
"status_active": active,
"contracts_summary": summary,
}
def _format_key_item(kd: dict[str, Any]) -> dict[str, Any]:
sym = kd.get("exchange_symbol") or kd.get("symbol") or "-"
direction = str(kd.get("direction") or "long").lower()
@@ -137,51 +262,6 @@ def _format_roll_item(rd: dict[str, Any]) -> dict[str, Any]:
}
def _format_options_item(p: dict[str, Any]) -> dict[str, Any]:
inst = p.get("inst_id") or p.get("instId") or "-"
opt_type = str(p.get("opt_type") or p.get("optType") or "").upper()
label = "Call" if opt_type == "C" else "Put" if opt_type == "P" else (opt_type or "OPT")
upl = _safe_float(p.get("upl"))
net = None
try:
from lib.options.options_positions_lib import net_pnl_from_display_row
net = net_pnl_from_display_row(p)
except Exception:
net = None
pnl = net if net is not None else upl
pos = _safe_float(p.get("pos"))
return {
"id": inst,
"kind": "options",
"tab": "options",
"title": f"{inst} {label}",
"subtitle": f"张数 {pos if pos is not None else '-'}",
"inst_id": inst,
"opt_type": opt_type,
"pnl": round(pnl, 4) if pnl is not None else None,
"pos": pos,
}
def _format_hedge_item(plan: dict[str, Any]) -> dict[str, Any]:
pid = plan.get("id")
underlying = plan.get("underlying") or "-"
plan_type = plan.get("plan_type") or ""
status = plan.get("status") or ""
summary = plan.get("contracts_summary") or ""
return {
"id": pid,
"kind": "hedge_plan",
"tab": "hedge_plan",
"title": f"对冲 #{pid} {underlying}",
"subtitle": " · ".join(x for x in (plan_type, status, summary) if x),
"underlying": underlying,
"plan_type": plan_type,
"status": status,
}
def _table_exists(conn, name: str) -> bool:
try:
row = conn.execute(
@@ -253,6 +333,8 @@ def collect_hedge_plans(conn) -> list[dict[str, Any]]:
def collect_options_items(
fetch_options_positions: Optional[Callable[[], list[dict[str, Any]]]] = None,
*,
conn=None,
) -> list[dict[str, Any]]:
if not callable(fetch_options_positions):
return []
@@ -264,7 +346,7 @@ def collect_options_items(
for p in raw:
if not isinstance(p, dict):
continue
out.append(_format_options_item(p))
out.append(_format_options_item(p, conn=conn))
return out
@@ -279,7 +361,7 @@ def build_instance_dashboard_payload(
trends = collect_trends(conn)
rolls = collect_rolls(conn)
strategy_items = trends + rolls
options_items = collect_options_items(fetch_options_positions)
options_items = collect_options_items(fetch_options_positions, conn=conn)
hedge_items = collect_hedge_plans(conn) if hedge_enabled else []
now = datetime.now(timezone.utc).astimezone().strftime("%Y-%m-%d %H:%M:%S")
return {