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:
@@ -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"
|
||||
|
||||
@@ -797,6 +797,7 @@ def reconcile_monitors_without_position(conn, mode: str, *, grace_sec: int = 120
|
||||
cancel_monitor_exit_orders(conn, mon, mode=mode)
|
||||
except Exception as exc:
|
||||
logger.warning("cancel exit orders monitor=%s: %s", mon.get("id"), exc)
|
||||
clear_close_pending(ms, md)
|
||||
conn.execute("UPDATE trade_order_monitors SET status='closed' WHERE id=?", (mon["id"],))
|
||||
closed += 1
|
||||
if closed:
|
||||
|
||||
Reference in New Issue
Block a user