Stream real-time position quotes via tick-driven SSE with incremental UI updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-29 21:14:41 +08:00
parent 94c566fbe5
commit df79017b30
4 changed files with 148 additions and 8 deletions
+57
View File
@@ -138,6 +138,7 @@ from vnpy_bridge import (
get_bridge,
set_position_refresh_callback,
set_tick_sl_tp_callback,
set_tick_quote_callback,
set_ctp_connected_callback,
)
@@ -1622,6 +1623,61 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
threading.Thread(target=_run, daemon=True).start()
def _build_position_quotes_payload(mode: str) -> dict:
"""轻量现价/浮盈(仅读 tick 缓存,不走 SQLite)。"""
if not ctp_status(mode).get("connected"):
return {"ok": True, "quotes": []}
from contract_specs import get_contract_spec
positions = trading_state.get_positions()
if not positions:
positions = _ctp_positions(mode, refresh_if_empty=False)
quotes: list[dict] = []
for p in positions:
lots = int(p.get("lots") or 0)
if lots <= 0:
continue
ths = _ctp_pos_to_ths_code(p) or (p.get("symbol") or "")
if not ths:
continue
entry = float(p.get("avg_price") or 0)
if entry <= 0:
continue
direction = (p.get("direction") or "long").strip().lower()
mark = ctp_get_tick_price(mode, ths)
if not mark or mark <= 0:
continue
mult = float(get_contract_spec(ths).get("mult") or 10)
if direction == "long":
float_pnl = round((mark - entry) * mult * lots, 2)
else:
float_pnl = round((entry - mark) * mult * lots, 2)
row_key = _canonical_position_key(
ths, direction, (p.get("exchange") or ""),
)
quotes.append({
"key": row_key,
"position_key": row_key,
"mark_price": mark,
"current_price": mark,
"float_pnl": float_pnl,
})
return {"ok": True, "quotes": quotes}
def _push_position_quotes_async() -> None:
def _run() -> None:
try:
if not is_trading_session():
return
mode = get_trading_mode(get_setting)
payload = _build_position_quotes_payload(mode)
if payload.get("quotes"):
position_hub.push_event("position_quotes", payload)
except Exception as exc:
logger.debug("push position quotes: %s", exc)
threading.Thread(target=_run, daemon=True, name="position-quotes").start()
def _on_tick_sl_tp(exchange: str, symbol: str, price: float) -> None:
from sl_tp_guard import check_sl_tp_on_tick
from db_conn import DB_PATH, connect_db
@@ -1651,6 +1707,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
set_position_refresh_callback(
lambda: _push_position_snapshot_async(fast=True)
)
set_tick_quote_callback(_push_position_quotes_async)
set_tick_sl_tp_callback(_on_tick_sl_tp)
set_ctp_connected_callback(_on_ctp_connected)