Fix monitor closed too early on manual close: keep active until CTP flat and revive for roll.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-03 22:20:53 +08:00
parent 75d9c86593
commit 3c7da47bfb
2 changed files with 47 additions and 3 deletions
+46 -3
View File
@@ -1220,9 +1220,22 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
def _revive_closed_monitor(conn, symbol: str, direction: str) -> Optional[dict]:
"""柜台仍有持仓但本地监控被误关时,恢复最近一条同品种记录。"""
if should_skip_monitor_revive(symbol, direction):
return None
direction = (direction or "long").strip().lower()
ctp_still_open = False
mode = get_trading_mode(get_setting)
if ctp_status(mode).get("connected"):
for p in list(_ctp_positions(mode) or []) + list(trading_state.get_positions() or []):
if int(p.get("lots") or 0) <= 0:
continue
if (p.get("direction") or "long") != direction:
continue
if _match_ctp_symbol(symbol, p.get("symbol") or ""):
ctp_still_open = True
break
if should_skip_monitor_revive(symbol, direction) and not ctp_still_open:
return None
if ctp_still_open and close_pending_active(symbol, direction):
clear_close_pending(symbol, direction)
for r in conn.execute(
"SELECT * FROM trade_order_monitors WHERE status='closed' ORDER BY id DESC LIMIT 40"
).fetchall():
@@ -3455,7 +3468,8 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
symbol_name=(mon.get("symbol_name") or "") if mon else "",
market_code=(mon.get("market_code") or "") if mon else "",
)
_close_all_monitors_for_sym_dir(conn, sym, direction)
if mon:
cancel_monitor_exit_orders(conn, mon, mode=mode)
conn.commit()
try:
on_user_initiated_close(conn, trading_day=trading_day_label())
@@ -3714,6 +3728,32 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
return val
return None
def _revive_monitors_for_open_ctp(conn, mode: str) -> int:
"""柜台有持仓但本地监控被误关时恢复(策略页/滚仓用,不做全量同步)。"""
if not ctp_status(mode).get("connected"):
return 0
revived = 0
seen: set[tuple[str, str]] = set()
for p in list(_ctp_positions(mode) or []) + list(trading_state.get_positions() or []):
lots = int(p.get("lots") or 0)
if lots <= 0:
continue
direction = (p.get("direction") or "long").strip().lower()
ths = _ctp_pos_to_ths_code(p) or (p.get("symbol") or "").strip()
if not ths:
continue
key = _canonical_position_key(ths, direction)
if key in seen:
continue
seen.add(key)
if _find_active_monitor(conn, ths, direction):
continue
if _revive_closed_monitor(conn, ths, direction):
revived += 1
if revived:
commit_retry(conn)
return revived
def _revive_roll_monitors_light(conn) -> int:
"""策略页:仅恢复滚仓组关联的误关监控,不做 CTP 同步(避免阻塞页面)。"""
rows = conn.execute(
@@ -3740,6 +3780,9 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se
try:
init_strategy_tables(conn)
capital = _capital(conn)
mode = get_trading_mode(get_setting)
if ctp_status(mode).get("connected"):
_revive_monitors_for_open_ctp(conn, mode)
_revive_roll_monitors_light(conn)
need_initial = conn.execute(
"SELECT id FROM roll_groups WHERE status='active' AND COALESCE(initial_lots, 0)=0 LIMIT 1"