Add instance data dashboard (default off).

Read-only overview of live orders, key monitors, and strategy; show options/hedge only when present. Toggle via system settings nav prefs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-17 12:09:29 +08:00
parent f7ba7c2f7d
commit c7aae67881
20 changed files with 825 additions and 20 deletions
+312
View File
@@ -0,0 +1,312 @@
"""实例数据看板:本户活跃监控 / 持仓只读聚合."""
from __future__ import annotations
from datetime import datetime, timezone
from typing import Any, Callable, Optional
def _row_dict(row: Any) -> dict[str, Any]:
if row is None:
return {}
if isinstance(row, dict):
return dict(row)
try:
return dict(row)
except Exception:
return {}
def _safe_float(v: Any) -> Optional[float]:
try:
if v is None or v == "":
return None
return float(v)
except (TypeError, ValueError):
return None
def _dir_label(direction: Any) -> str:
d = str(direction or "").strip().lower()
if d == "short":
return "做空"
if d == "long":
return "做多"
return str(direction or "-")
def _format_order_item(od: dict[str, Any]) -> dict[str, Any]:
try:
from lib.strategy.strategy_trade_labels import apply_order_monitor_source_labels
od = apply_order_monitor_source_labels(od)
except Exception:
pass
try:
from lib.trade.entry_model_lib import enrich_entry_model_display
enrich_entry_model_display(od)
except Exception:
pass
sym = od.get("exchange_symbol") or od.get("symbol") or "-"
direction = str(od.get("direction") or "long").lower()
mt = od.get("monitor_type_display") or od.get("monitor_type") or ""
kst = od.get("key_signal_type") or ""
title = f"{sym} {_dir_label(direction)}"
bits = [x for x in (mt, kst) if x]
subtitle = " · ".join(bits) if bits else ""
entry = _safe_float(od.get("trigger_price"))
sl = _safe_float(od.get("stop_loss"))
tp = _safe_float(od.get("take_profit"))
return {
"id": od.get("id"),
"kind": "order",
"tab": "trade",
"title": title,
"subtitle": subtitle,
"symbol": sym,
"direction": direction,
"direction_label": _dir_label(direction),
"entry": entry,
"stop_loss": sl,
"take_profit": tp,
"status": od.get("status") or "active",
}
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()
signal = kd.get("signal_type") or kd.get("key_signal_type") or kd.get("monitor_type") or ""
upper = _safe_float(kd.get("upper"))
lower = _safe_float(kd.get("lower"))
subtitle_parts = []
if signal:
subtitle_parts.append(str(signal))
if upper is not None or lower is not None:
subtitle_parts.append(
f"{upper if upper is not None else '-'} / 下{lower if lower is not None else '-'}"
)
return {
"id": kd.get("id"),
"kind": "key",
"tab": "key_monitor",
"title": f"{sym} {_dir_label(direction)}",
"subtitle": " · ".join(subtitle_parts),
"symbol": sym,
"direction": direction,
"direction_label": _dir_label(direction),
"upper": upper,
"lower": lower,
"status": kd.get("status") or "active",
}
def _format_trend_item(td: dict[str, Any]) -> dict[str, Any]:
sym = td.get("exchange_symbol") or td.get("symbol") or "-"
direction = str(td.get("direction") or "long").lower()
status = td.get("status") or "active"
entry = _safe_float(td.get("entry_price") or td.get("trigger_price"))
return {
"id": td.get("id"),
"kind": "trend",
"tab": "strategy",
"title": f"趋势回调 {sym} {_dir_label(direction)}",
"subtitle": f"状态 {status}",
"symbol": sym,
"direction": direction,
"direction_label": _dir_label(direction),
"entry": entry,
"status": status,
}
def _format_roll_item(rd: dict[str, Any]) -> dict[str, Any]:
sym = rd.get("exchange_symbol") or rd.get("symbol") or "-"
direction = str(rd.get("direction") or "long").lower()
status = rd.get("status") or "active"
return {
"id": rd.get("id"),
"kind": "roll",
"tab": "strategy",
"title": f"顺势加仓 {sym} {_dir_label(direction)}",
"subtitle": f"状态 {status}",
"symbol": sym,
"direction": direction,
"direction_label": _dir_label(direction),
"status": status,
}
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(
"SELECT 1 FROM sqlite_master WHERE type='table' AND name=? LIMIT 1",
(name,),
).fetchone()
return bool(row)
except Exception:
return False
def collect_orders(conn) -> list[dict[str, Any]]:
if not _table_exists(conn, "order_monitors"):
return []
rows = conn.execute(
"SELECT * FROM order_monitors WHERE status='active' ORDER BY id DESC"
).fetchall()
return [_format_order_item(_row_dict(r)) for r in rows]
def collect_keys(conn) -> list[dict[str, Any]]:
if not _table_exists(conn, "key_monitors"):
return []
rows = conn.execute("SELECT * FROM key_monitors ORDER BY id DESC").fetchall()
return [_format_key_item(_row_dict(r)) for r in rows]
def collect_trends(conn) -> list[dict[str, Any]]:
if not _table_exists(conn, "trend_pullback_plans"):
return []
try:
rows = conn.execute(
"SELECT * FROM trend_pullback_plans WHERE status='active' ORDER BY id DESC"
).fetchall()
except Exception:
return []
return [_format_trend_item(_row_dict(r)) for r in rows]
def collect_rolls(conn) -> list[dict[str, Any]]:
if not _table_exists(conn, "roll_groups") or not _table_exists(conn, "order_monitors"):
return []
try:
rows = conn.execute(
"""SELECT g.* FROM roll_groups g
INNER JOIN order_monitors m ON m.id = g.order_monitor_id AND m.status='active'
WHERE g.status='active' ORDER BY g.id DESC"""
).fetchall()
except Exception:
return []
return [_format_roll_item(_row_dict(r)) for r in rows]
def collect_hedge_plans(conn) -> list[dict[str, Any]]:
if not _table_exists(conn, "hedge_plans"):
return []
try:
from lib.hedge_plan.hedge_plan_db import attach_legs_to_plans, list_plans
rows: list[dict[str, Any]] = []
for status in ("opening", "active", "partial"):
rows.extend(list_plans(conn, status=status, limit=80))
rows.sort(key=lambda row: int(row.get("id") or 0), reverse=True)
plans = attach_legs_to_plans(conn, rows)
return [_format_hedge_item(p) for p in plans]
except Exception:
return []
def collect_options_items(
fetch_options_positions: Optional[Callable[[], list[dict[str, Any]]]] = None,
) -> list[dict[str, Any]]:
if not callable(fetch_options_positions):
return []
try:
raw = fetch_options_positions() or []
except Exception:
return []
out: list[dict[str, Any]] = []
for p in raw:
if not isinstance(p, dict):
continue
out.append(_format_options_item(p))
return out
def build_instance_dashboard_payload(
conn,
*,
fetch_options_positions: Optional[Callable[[], list[dict[str, Any]]]] = None,
hedge_enabled: bool = False,
) -> dict[str, Any]:
orders = collect_orders(conn)
keys = collect_keys(conn)
trends = collect_trends(conn)
rolls = collect_rolls(conn)
strategy_items = trends + rolls
options_items = collect_options_items(fetch_options_positions)
hedge_items = collect_hedge_plans(conn) if hedge_enabled else []
now = datetime.now(timezone.utc).astimezone().strftime("%Y-%m-%d %H:%M:%S")
return {
"ok": True,
"updated_at": now,
"orders": {"title": "实盘下单", "count": len(orders), "items": orders, "tab": "trade"},
"keys": {"title": "关键位监控", "count": len(keys), "items": keys, "tab": "key_monitor"},
"strategy": {
"title": "策略交易",
"count": len(strategy_items),
"items": strategy_items,
"trends": trends,
"rolls": rolls,
"tab": "strategy",
},
"options": {
"title": "期权持仓",
"count": len(options_items),
"items": options_items,
"visible": len(options_items) > 0,
"tab": "options",
},
"hedge_plan": {
"title": "对冲计划",
"count": len(hedge_items),
"items": hedge_items,
"visible": len(hedge_items) > 0,
"tab": "hedge_plan",
},
}