From d366344b0f7d9f7c800e500b82724d6f5eb3b406 Mon Sep 17 00:00:00 2001 From: dekun Date: Mon, 29 Jun 2026 09:26:54 +0800 Subject: [PATCH] Fix trailing break-even stop loss not linked to CTP positions. Match pending monitors to filled positions, reconcile pending on fast refresh, and refresh CTP before promote. Co-authored-by: Cursor --- install_trading.py | 32 +++++++++++++++++++++++++++++++- order_pending.py | 2 +- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/install_trading.py b/install_trading.py index fe0347c..aa9def8 100644 --- a/install_trading.py +++ b/install_trading.py @@ -698,6 +698,26 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se return row return None + def _find_pending_monitor(conn, symbol: str, direction: str) -> Optional[dict]: + """开仓委托 pending 仍带止损/移动保本元数据,需与 CTP 持仓关联展示。""" + direction = (direction or "long").strip().lower() + for r in conn.execute( + "SELECT * FROM trade_order_monitors WHERE status='pending' ORDER BY id DESC" + ).fetchall(): + row = dict(r) + if (row.get("direction") or "long") != direction: + continue + if _match_ctp_symbol(symbol, row.get("symbol") or ""): + return row + return None + + def _has_pending_monitors(conn) -> bool: + return bool( + conn.execute( + "SELECT 1 FROM trade_order_monitors WHERE status='pending' LIMIT 1" + ).fetchone() + ) + def _revive_closed_monitor(conn, symbol: str, direction: str) -> Optional[dict]: """柜台仍有持仓但本地监控被误关时,恢复最近一条同品种记录。""" direction = (direction or "long").strip().lower() @@ -1459,6 +1479,10 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se mon = mv break ths = _ctp_pos_to_ths_code(p) or (p.get("symbol") or "") + if not mon: + mon = _find_pending_monitor( + conn, ths, p.get("direction") or "long", + ) if mon and not fast: _sync_monitor_from_ctp( conn, int(mon["id"]), mon.get("symbol") or ths, @@ -1495,8 +1519,9 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se mode = get_trading_mode(get_setting) ctp_st = ctp_status(mode) capital = _capital(conn) - if ctp_st.get("connected") and not fast: + if ctp_st.get("connected") and (not fast or _has_pending_monitors(conn)): _reconcile_pending(conn, mode, capital=capital) + if ctp_st.get("connected") and not fast: _sync_trade_monitors_with_ctp(conn, mode) rows = _build_trading_live_rows(conn, fast=fast) active_orders = _build_active_orders( @@ -2281,6 +2306,11 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se order_price=price, ) conn.commit() + try: + with _ctp_td_lock: + get_bridge().refresh_positions() + except Exception: + pass _reconcile_pending(conn, mode, capital=_capital(conn)) st_row = conn.execute( "SELECT status FROM trade_order_monitors WHERE id=?", (mid,), diff --git a/order_pending.py b/order_pending.py index 4f703fc..be08e3c 100644 --- a/order_pending.py +++ b/order_pending.py @@ -156,7 +156,7 @@ def reconcile_pending_orders( match = match_symbol_fn or _match_symbol positions = ( - list_positions_fn(mode, refresh_if_empty=False, refresh_margin=False) + list_positions_fn(mode, refresh_if_empty=True, refresh_margin=False) if list_positions_fn else [] )