From 066c90fd96914de314eb75d24786a92876360667 Mon Sep 17 00:00:00 2001 From: dekun Date: Wed, 7 Oct 2026 10:56:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=9B=91=E6=8E=A7=E6=8F=A1?= =?UTF-8?q?=E9=94=81=E5=8D=96=E5=B8=81=E5=AF=BC=E8=87=B4=E4=B8=AD=E6=8E=A7?= =?UTF-8?q?=E5=BF=AB=E7=85=A7=E8=B6=85=E6=97=B6=E3=80=81=E5=AE=9E=E4=BE=8B?= =?UTF-8?q?=E5=85=A8=E9=83=A8=E7=A6=BB=E7=BA=BF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- lib/options/options_monitor_lib.py | 32 +++++++++++++++++++++++++----- lib/options/options_register.py | 14 +++---------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/lib/options/options_monitor_lib.py b/lib/options/options_monitor_lib.py index afa100d..8b34c93 100644 --- a/lib/options/options_monitor_lib.py +++ b/lib/options/options_monitor_lib.py @@ -375,15 +375,16 @@ def sync_open_options_trades( pass if notify_cfg is not None: _notify_recent_unsent_expiry_closes(conn, notify_cfg) - _sell_spot_after_synced_closes(notify_cfg, closed_inst_ids) + # 卖币不在此处做:调用方须先 commit/close 本连接,再调 sell_spot_after_options_sync, + # 否则监控线程握锁时中控快照会超时,表现为全部离线。 return updated -def _sell_spot_after_synced_closes( - cfg: dict[str, Any], - closed_inst_ids: list[str], +def sell_spot_after_options_sync( + cfg: dict[str, Any] | None, + closed_inst_ids: list[str] | None = None, ) -> None: - """同步关仓(含到期)后卖回币本位残留;空仓时再扫一遍交易户.""" + """在释放业务 DB 连接后调用:同步关仓/到期后的币本位卖回.""" if not isinstance(cfg, dict): return ex = cfg.get("exchange_options") @@ -540,9 +541,14 @@ def options_monitor_loop( pe_cfg = dict(profit_exit_cfg or {}) pe_cfg.setdefault("send_wechat", send_wechat) pe_cfg.setdefault("account_label", account_label) + # 平仓/卖币会另开 DB 连接;先提交释放写锁,避免中控快照被锁超时→全部离线 if target_close_fn is not None: from lib.options.options_target_lib import run_options_target_closes + try: + conn.commit() + except Exception: + pass run_options_target_closes( conn, positions, @@ -554,6 +560,10 @@ def options_monitor_loop( if profit_exit_close_fn is not None: from lib.options.options_profit_exit_lib import run_options_profit_exits + try: + conn.commit() + except Exception: + pass run_options_profit_exits( conn, positions, @@ -564,10 +574,22 @@ def options_monitor_loop( ex=pe_cfg.get("exchange_options"), ) if sync_trades_fn is not None: + try: + conn.commit() + except Exception: + pass sync_trades_fn(conn) conn.commit() finally: conn.close() + # 币本位扫尾卖回:必须在监控连接关闭之后 + try: + pe_sell = dict(profit_exit_cfg or {}) + pe_sell.setdefault("send_wechat", send_wechat) + pe_sell.setdefault("account_label", account_label) + sell_spot_after_options_sync(pe_sell) + except Exception: + pass # 平仓限价挂单超时撤单(独立于 DB 事务) if stale_pending_fn is not None: try: diff --git a/lib/options/options_register.py b/lib/options/options_register.py index 7638ca4..d1d9007 100644 --- a/lib/options/options_register.py +++ b/lib/options/options_register.py @@ -459,9 +459,9 @@ def _sync_options_trades( finally: conn.close() try: - from lib.options.options_coin_open_lib import sweep_spot_after_options_flat + from lib.options.options_monitor_lib import sell_spot_after_options_sync - sweep_spot_after_options_flat(cfg, ex) + sell_spot_after_options_sync(cfg) _mark_balances_stale(cfg) except Exception: pass @@ -1991,20 +1991,12 @@ def _start_monitor_thread(app: Flask, cfg: dict[str, Any]) -> None: return 0 live_ids = {str(p.get("instId") or "") for p in raw if str(p.get("instId") or "")} reconcile_live_open_trades(conn, live_inst_ids=live_ids) - n = sync_open_options_trades( + return sync_open_options_trades( conn, live_inst_ids=live_ids, fetch_history_fn=lambda inst_id: fetch_option_position_history(ex, inst_id), notify_cfg=cfg, ) - try: - from lib.options.options_coin_open_lib import sweep_spot_after_options_flat - - sweep_spot_after_options_flat(cfg, ex) - _mark_balances_stale(cfg) - except Exception: - pass - return n def _target_close(inst_id: str) -> dict[str, Any]: from lib.options.options_target_lib import close_option_by_bid_depth