Label dashboard positions from monitor sources with priority.

Match hedge/roll/trend/order/key monitors for source badges, show option target monitors in green, and refresh the dashboard with the board 5s cycle.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-17 14:25:36 +08:00
parent 0bda44248f
commit c4c8ad172a
11 changed files with 290 additions and 28 deletions
+122 -18
View File
@@ -973,9 +973,119 @@ def format_account_remark(ac: dict) -> str:
return ";".join(parts)
def _monitor_item_matches_position(item: dict, symbol: str, side: str) -> bool:
o_sym = item.get("exchange_symbol") or item.get("symbol") or ""
if not _symbols_match(symbol, o_sym):
return False
return (str(item.get("direction") or "").lower() == str(side or "").lower())
def _order_monitor_source_label(order: dict) -> tuple[int, str]:
"""返回 (优先级, 来源标签). 对冲=1 … 关键位=5."""
mt = str(
order.get("monitor_type_display")
or order.get("monitor_type_label")
or order.get("monitor_type")
or ""
).strip()
if "顺势" in mt:
return 2, "顺势加仓"
if "趋势" in mt:
return 3, "趋势回调"
if "关键位" in mt:
return 5, "关键位"
return 4, "下单监控"
def _hedge_matches_position(plan: dict, symbol: str, side: str) -> bool:
"""进行中对冲计划是否覆盖该永续仓(方向 + 永续腿/标的)."""
direction = str(plan.get("direction") or "").lower()
if direction and direction != str(side or "").lower():
return False
for leg in plan.get("legs") or []:
if not isinstance(leg, dict):
continue
if str(leg.get("leg_role") or "") != "perp":
continue
if str(leg.get("status") or "open") not in ("", "open"):
continue
if _symbols_match(symbol, str(leg.get("symbol") or "")):
return True
und = str(plan.get("underlying") or "").strip()
if und and _symbols_match(symbol, und):
return True
return False
def _hedge_source_label(plan: dict) -> str:
pt = str(plan.get("plan_type") or "").strip()
if pt == "perp_options" or str(plan.get("plan_type_label") or "") == "永期对冲":
return "永期对冲"
if pt == "options_options" or str(plan.get("plan_type_label") or "") == "期期对冲":
return "期期对冲"
return "对冲"
def resolve_position_monitor_source(pos: dict, hub_mon: Optional[dict]) -> str:
"""仓位来源:对冲 > 顺势加仓 > 趋势回调 > 下单监控 > 关键位;对不上为 —."""
if not isinstance(hub_mon, dict) or hub_mon.get("ok") is False:
return ""
sym = str(pos.get("symbol") or "")
side = str(pos.get("side") or "")
if not sym:
return ""
candidates: list[tuple[int, str]] = []
for h in hub_mon.get("hedges") or []:
if isinstance(h, dict) and _hedge_matches_position(h, sym, side):
candidates.append((1, _hedge_source_label(h)))
for r in hub_mon.get("rolls") or []:
if isinstance(r, dict) and _monitor_item_matches_position(r, sym, side):
candidates.append((2, "顺势加仓"))
for t in hub_mon.get("trends") or []:
if isinstance(t, dict) and _monitor_item_matches_position(t, sym, side):
candidates.append((3, "趋势回调"))
for o in hub_mon.get("orders") or []:
if isinstance(o, dict) and _monitor_item_matches_position(o, sym, side):
candidates.append(_order_monitor_source_label(o))
for k in hub_mon.get("keys") or []:
if isinstance(k, dict) and _monitor_item_matches_position(k, sym, side):
candidates.append((5, "关键位"))
if not candidates:
return ""
candidates.sort(key=lambda x: x[0])
return candidates[0][1]
def _options_source_label(p: dict) -> str:
"""看板期权来源:仅对冲标期期/永期;纯期权或对不上监控显示 —."""
source = str(p.get("source") or "").strip()
label = str(p.get("source_label") or "").strip()
if source == "perp_options" or label == "永期对冲":
return "永期对冲"
if source == "options_options" or label == "期期对冲":
return "期期对冲"
hedge = p.get("hedge_plan_target") if isinstance(p.get("hedge_plan_target"), dict) else None
if hedge:
return _hedge_source_label(hedge)
return ""
def _options_target_monitor_text(p: dict) -> str:
raw = p.get("target_monitor_text")
if raw not in (None, ""):
return str(raw)
try:
from lib.instance.instance_dashboard_lib import _format_options_target
return _format_options_target(p)
except Exception:
return ""
def format_dashboard_account_detail(ac: dict) -> dict[str, Any]:
"""数据看板分户卡片:监控数量,持仓逐行(含浮盈亏与来源)."""
"""数据看板分户卡片:监控数量 + 持仓表(来源=监控匹配)."""
mon = ac.get("monitor_lines") or {}
hub_mon = ac.get("hub_monitor") if isinstance(ac.get("hub_monitor"), dict) else None
position_lines: list[dict[str, Any]] = []
for p in _filter_open_positions(ac.get("positions") or []):
sym = p.get("symbol") or "?"
@@ -984,10 +1094,11 @@ def format_dashboard_account_detail(ac: dict) -> dict[str, Any]:
if contracts is None:
contracts = p.get("size")
upnl = _position_float_pnl(p)
source = resolve_position_monitor_source(p, hub_mon)
position_lines.append(
{
"kind": "position",
"source": "永续",
"source": source,
"symbol": sym,
"side": side,
"contracts": contracts,
@@ -998,28 +1109,21 @@ def format_dashboard_account_detail(ac: dict) -> dict[str, Any]:
opt_snap = ac.get("options_snapshot") if isinstance(ac.get("options_snapshot"), dict) else {}
options_positions: list[dict[str, Any]] = []
if opt_snap.get("ok") is not False and opt_snap.get("enabled") is not False:
from lib.options.options_pricing_lib import format_options_breakeven_line
for p in opt_snap.get("positions") or []:
if not isinstance(p, dict):
continue
options_positions.append(p)
inst = p.get("inst_id") or "?"
opt_type = (p.get("opt_type") or "").upper()
row = dict(p)
row["source_label"] = _options_source_label(p)
row["target_monitor_text"] = _options_target_monitor_text(p)
options_positions.append(row)
inst = row.get("inst_id") or "?"
opt_type = (row.get("opt_type") or "").upper()
label = "Call" if opt_type == "C" else "Put" if opt_type == "P" else opt_type or "OPT"
upl = p.get("upl")
be_line = format_options_breakeven_line(
expiry_be_px=p.get("expiry_be_px"),
close_be_px=p.get("close_be_px"),
idx_px=p.get("idx_px"),
)
text = f"期权 {inst} {label}"
if be_line:
text = f"{text} {be_line}"
upl = row.get("upl")
line: dict[str, Any] = {
"kind": "options",
"source": "期权",
"text": text,
"source": row.get("source_label") or "",
"text": f"期权 {inst} {label}",
}
if upl is not None:
try: