fix: 持仓接口实时拉取并回写本地监控,修复有仓不显示
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+79
-20
@@ -128,22 +128,80 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
def _ctp_positions(mode: str) -> list:
|
||||
def _ctp_positions(mode: str, *, refresh_if_empty: bool = True) -> list:
|
||||
try:
|
||||
return ctp_list_positions(mode)
|
||||
return ctp_list_positions(mode, refresh_if_empty=refresh_if_empty)
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
def _ctp_pos_to_ths_code(p: dict) -> str:
|
||||
sym = (p.get("symbol") or "").strip()
|
||||
if not sym:
|
||||
return ""
|
||||
codes = ths_to_codes(sym)
|
||||
if codes:
|
||||
return codes.get("ths_code") or sym
|
||||
return sym
|
||||
|
||||
def _ensure_monitors_from_ctp(conn, mode: str) -> None:
|
||||
"""CTP 有持仓但本地无监控时,自动补写一条 active 记录供展示。"""
|
||||
if not ctp_status(mode).get("connected"):
|
||||
return
|
||||
for p in _ctp_positions(mode, refresh_if_empty=True):
|
||||
lots = int(p.get("lots") or 0)
|
||||
if lots <= 0:
|
||||
continue
|
||||
direction = p.get("direction") or "long"
|
||||
ths = _ctp_pos_to_ths_code(p)
|
||||
if not ths:
|
||||
continue
|
||||
if _find_active_monitor(conn, ths, direction):
|
||||
continue
|
||||
codes = ths_to_codes(ths) or {}
|
||||
now_s = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
ensure_monitor_order_columns(conn)
|
||||
conn.execute(
|
||||
"""INSERT INTO trade_order_monitors (
|
||||
symbol, symbol_name, market_code, direction, lots, entry_price,
|
||||
stop_loss, take_profit, initial_stop_loss, trailing_be,
|
||||
open_time, monitor_type, status
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?, 'active')""",
|
||||
(
|
||||
ths,
|
||||
codes.get("name", ths) if codes else ths,
|
||||
codes.get("market_code", "") if codes else "",
|
||||
direction,
|
||||
lots,
|
||||
float(p.get("avg_price") or 0),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
0,
|
||||
now_s,
|
||||
"ctp_sync",
|
||||
),
|
||||
)
|
||||
|
||||
def _match_ctp_symbol(ctp_sym: str, ths: str) -> bool:
|
||||
a = (ctp_sym or "").lower()
|
||||
b = (ths or "").lower()
|
||||
if a == b:
|
||||
return True
|
||||
if a and b and a.split(".")[0] == b.split(".")[0]:
|
||||
return True
|
||||
try:
|
||||
vnpy_sym, _ = ths_to_vnpy_symbol(ths)
|
||||
return a == vnpy_sym.lower()
|
||||
if a == vnpy_sym.lower():
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
pass
|
||||
try:
|
||||
vnpy_sym, _ = ths_to_vnpy_symbol(ctp_sym)
|
||||
if vnpy_sym.lower() == b.split(".")[0]:
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
def _holding_duration(open_time: str, now_iso: str) -> str:
|
||||
try:
|
||||
@@ -543,11 +601,14 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
mon.get("direction") or "long", mode,
|
||||
)
|
||||
mon = _find_active_monitor(conn, mon.get("symbol") or "", mon.get("direction") or "long") or mon
|
||||
row = _compose_position_row(
|
||||
conn, mon=mon, ctp=ctp, mode=mode, capital=capital, now_iso=now_iso,
|
||||
)
|
||||
if row:
|
||||
rows.append(row)
|
||||
try:
|
||||
row = _compose_position_row(
|
||||
conn, mon=mon, ctp=ctp, mode=mode, capital=capital, now_iso=now_iso,
|
||||
)
|
||||
if row:
|
||||
rows.append(row)
|
||||
except Exception as exc:
|
||||
logger.warning("compose monitor row failed: %s", exc)
|
||||
|
||||
for key, ctp in ctp_by_key.items():
|
||||
if key in used_ctp_keys:
|
||||
@@ -570,11 +631,14 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
mon = _find_active_monitor(
|
||||
conn, ctp.get("symbol") or "", ctp.get("direction") or "long",
|
||||
)
|
||||
row = _compose_position_row(
|
||||
conn, mon=mon, ctp=ctp, mode=mode, capital=capital, now_iso=now_iso,
|
||||
)
|
||||
if row:
|
||||
rows.append(row)
|
||||
try:
|
||||
row = _compose_position_row(
|
||||
conn, mon=mon, ctp=ctp, mode=mode, capital=capital, now_iso=now_iso,
|
||||
)
|
||||
if row:
|
||||
rows.append(row)
|
||||
except Exception as exc:
|
||||
logger.warning("compose ctp row failed: %s", exc)
|
||||
|
||||
seen: set[str] = set()
|
||||
deduped: list[dict] = []
|
||||
@@ -589,7 +653,7 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
def _build_trading_live_payload(conn) -> dict:
|
||||
mode = get_trading_mode(get_setting)
|
||||
ctp_st = ctp_status(mode)
|
||||
_sync_trade_monitors_with_ctp(conn, mode)
|
||||
_ensure_monitors_from_ctp(conn, mode)
|
||||
rows = _build_trading_live_rows(conn)
|
||||
pending_orders = _build_pending_orders(conn, mode)
|
||||
capital = _capital(conn)
|
||||
@@ -638,7 +702,6 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
init_strategy_tables(conn)
|
||||
mode = get_trading_mode(get_setting)
|
||||
ctp_st = ctp_status(mode)
|
||||
_sync_trade_monitors_with_ctp(conn, mode)
|
||||
capital = _capital(conn)
|
||||
risk = get_risk_status(conn, active_count=_effective_active_position_count(conn, mode))
|
||||
ctp_acc = _ctp_account(mode) if ctp_st.get("connected") else {}
|
||||
@@ -709,9 +772,6 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
@app.route("/api/trading/live")
|
||||
@login_required
|
||||
def api_trading_live():
|
||||
cached = position_hub.get_snapshot()
|
||||
if cached:
|
||||
return jsonify(cached)
|
||||
conn = get_db()
|
||||
try:
|
||||
init_strategy_tables(conn)
|
||||
@@ -1314,7 +1374,6 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
|
||||
init_strategy_tables(conn)
|
||||
mode = get_trading_mode(get_setting)
|
||||
ctp_st = ctp_status(mode)
|
||||
_sync_trade_monitors_with_ctp(conn, mode)
|
||||
capital = _capital(conn)
|
||||
risk = get_risk_status(conn, active_count=_effective_active_position_count(conn, mode))
|
||||
conn.commit()
|
||||
|
||||
Reference in New Issue
Block a user