diff --git a/lib/options/options_monitor_lib.py b/lib/options/options_monitor_lib.py index 3787f9a..63baadc 100644 --- a/lib/options/options_monitor_lib.py +++ b/lib/options/options_monitor_lib.py @@ -138,6 +138,11 @@ def run_options_profit_alerts( f"UPDATE options_trades SET profit_alert_sent = 1 WHERE id IN ({','.join('?' * len(bucket['ids']))})", tuple(bucket["ids"]), ) + # 立即提交,避免后续目标/翻倍/同步异常回滚后每轮重推 + try: + conn.commit() + except Exception: + pass sent += 1 except Exception: pass diff --git a/lib/options/options_profit_exit_lib.py b/lib/options/options_profit_exit_lib.py index 7723ad7..109ed67 100644 --- a/lib/options/options_profit_exit_lib.py +++ b/lib/options/options_profit_exit_lib.py @@ -125,10 +125,7 @@ def profit_exit_by_inst(conn: sqlite3.Connection) -> dict[str, dict[str, Any]]: SELECT inst_id, profit_exit_enabled, profit_exit_mult, profit_exit_state FROM options_trades WHERE status = 'open' - AND ( - CAST(COALESCE(profit_exit_enabled, 0) AS INTEGER) = 1 - OR COALESCE(profit_exit_state, 'idle') IN ('active', 'closing') - ) + AND COALESCE(profit_exit_state, 'idle') IN ('active', 'closing') ORDER BY id DESC """ ).fetchall() @@ -139,14 +136,17 @@ def profit_exit_by_inst(conn: sqlite3.Connection) -> dict[str, dict[str, Any]]: continue enabled = int(r["profit_exit_enabled"] or 0) == 1 state = str(r["profit_exit_state"] or "idle") - if not enabled and state not in ("active", "closing"): + if state not in ("active", "closing"): + continue + # closing 需续跑直到全平;active 需仍开启 + if state == "active" and not enabled: continue mult = normalize_profit_exit_mult(r["profit_exit_mult"], default=1.0) out[inst] = { "inst_id": inst, - "profit_exit_enabled": enabled or state in ("active", "closing"), + "profit_exit_enabled": enabled or state == "closing", "profit_exit_mult": mult, - "profit_exit_state": state if state in ("active", "closing") else ("active" if enabled else "idle"), + "profit_exit_state": state, "required_recycle": None, } for inst, info in out.items(): @@ -318,9 +318,7 @@ def run_options_profit_exits( continue pos = pos_by_inst.get(inst_id) if not pos: - # 持仓已平:收尾 - _mark_state(conn, inst_id, "done") - _commit(conn) + # 本轮暂无持仓:不改状态(避免接口抖动误标 done);真正平完由 sync 收尾 continue state = str(info.get("profit_exit_state") or "active") @@ -329,10 +327,25 @@ def run_options_profit_exits( if prem is None or prem <= 0: continue + # done/idle 不再扫描(查询层已过滤;此处双保险) + if state in ("done", "idle"): + continue + if state == "closing": result = close_fn(inst_id) if result.get("already_flat") or _result_fully_done(result): _mark_state(conn, inst_id, "done") + try: + conn.execute( + """ + UPDATE options_trades + SET profit_exit_enabled = 0 + WHERE inst_id = ? AND status = 'open' + """, + (inst_id,), + ) + except Exception: + pass _commit(conn) else: _mark_state(conn, inst_id, "closing") @@ -356,6 +369,17 @@ def run_options_profit_exits( result = close_fn(inst_id) if result.get("already_flat"): _mark_state(conn, inst_id, "done") + try: + conn.execute( + """ + UPDATE options_trades + SET profit_exit_enabled = 0 + WHERE inst_id = ? AND status = 'open' + """, + (inst_id,), + ) + except Exception: + pass _commit(conn) continue if not result.get("ok"): @@ -365,6 +389,19 @@ def run_options_profit_exits( done = _result_fully_done(result) _mark_state(conn, inst_id, "done" if done else "closing") + if done: + try: + conn.execute( + """ + UPDATE options_trades + SET profit_exit_enabled = 0 + WHERE inst_id = ? AND status = 'open' + """, + (inst_id,), + ) + except Exception: + pass + # 先落库再推送:同一笔只推一次;closing 重试不再进本分支 _commit(conn) triggered += 1 _notify_profit_exit_close(