修复期权币本位高危缺陷:开仓估量、卖回封顶、握库超时与条件单嵌套锁。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-07 12:00:08 +08:00
parent ea3e029eb9
commit 77fe0fa679
16 changed files with 724 additions and 201 deletions
+65 -39
View File
@@ -360,7 +360,7 @@ def _result_fully_done(result: dict[str, Any]) -> bool:
def run_options_target_closes(
conn: sqlite3.Connection,
conn_or_get_db: Any,
positions: list[dict[str, Any]],
*,
close_fn: Callable[[str], dict[str, Any]],
@@ -371,17 +371,17 @@ def run_options_target_closes(
) -> int:
"""
扫描 active 目标委托;指数到位后限价平仓.
状态先 commit 再推微信,避免 sync 失败回滚导致同一笔反复推送.
未完全成交进入 closing,仅重试平仓不再推送.
返回本次新触发(并推送)的条数.
可传 get_db:平仓在无业务连接时执行,避免嵌套锁库。
"""
get_db = conn_or_get_db if callable(conn_or_get_db) else None
conn = conn_or_get_db() if get_db else conn_or_get_db
ensure_target_tables(conn)
pos_by_inst = {str(p.get("inst_id") or p.get("instId") or ""): p for p in positions}
live_ids = {k for k in pos_by_inst if k}
cancel_orphans_without_position(conn, live_inst_ids=live_ids)
_commit_monitor(conn)
# 先处理已挂单等待成交的,绝不再发微信
retry_jobs: list[dict[str, Any]] = []
for mon in list_closing_targets(conn):
inst_id = str(mon.get("inst_id") or "")
if not inst_id:
@@ -390,32 +390,9 @@ def run_options_target_closes(
mark_monitor(conn, int(mon["id"]), status="expired", message="持仓已平")
_commit_monitor(conn)
continue
# 平仓/卖币另开连接,先提交释放锁
_commit_monitor(conn)
result = close_fn(inst_id)
idx = _safe_float(pos_by_inst[inst_id].get("idx_px") or pos_by_inst[inst_id].get("idxPx"))
if result.get("already_flat") or _result_fully_done(result):
mark_monitor(
conn,
int(mon["id"]),
status="triggered",
trigger_idx=idx,
close_ord_id=result.get("close_ord_id"),
message="目标位限价平仓完成",
)
_commit_monitor(conn)
continue
mark_monitor(
conn,
int(mon["id"]),
status="closing",
trigger_idx=idx,
close_ord_id=result.get("close_ord_id"),
message=str(result.get("msg") or result.get("stopped_reason") or "等待买一成交"),
)
_commit_monitor(conn)
retry_jobs.append(dict(mon))
triggered = 0
trigger_jobs: list[tuple[dict[str, Any], float, float]] = []
for mon in list_active_targets(conn):
inst_id = str(mon.get("inst_id") or "")
target = _safe_float(mon.get("target_index"))
@@ -433,36 +410,80 @@ def run_options_target_closes(
opt_type = mon.get("opt_type") or pos.get("opt_type") or pos.get("optType")
if not target_hit(opt_type=str(opt_type) if opt_type else None, index_px=idx, target_index=target):
continue
trigger_jobs.append((dict(mon), float(idx), float(target)))
_commit_monitor(conn)
if get_db is not None:
try:
conn.close()
except Exception:
pass
conn = None
_commit_monitor(conn)
def _ensure_conn() -> sqlite3.Connection:
nonlocal conn
if conn is not None:
return conn
assert get_db is not None
conn = get_db()
ensure_target_tables(conn)
return conn
for mon in retry_jobs:
inst_id = str(mon.get("inst_id") or "")
result = close_fn(inst_id)
c = _ensure_conn()
idx = _safe_float(pos_by_inst[inst_id].get("idx_px") or pos_by_inst[inst_id].get("idxPx"))
if result.get("already_flat") or _result_fully_done(result):
mark_monitor(
c,
int(mon["id"]),
status="triggered",
trigger_idx=idx,
close_ord_id=result.get("close_ord_id"),
message="目标位限价平仓完成",
)
else:
mark_monitor(
c,
int(mon["id"]),
status="closing",
trigger_idx=idx,
close_ord_id=result.get("close_ord_id"),
message=str(result.get("msg") or result.get("stopped_reason") or "等待买一成交"),
)
_commit_monitor(c)
triggered = 0
for mon, idx, target in trigger_jobs:
inst_id = str(mon.get("inst_id") or "")
result = close_fn(inst_id)
c = _ensure_conn()
if result.get("already_flat"):
mark_monitor(conn, int(mon["id"]), status="expired", trigger_idx=idx, message="持仓已平")
_commit_monitor(conn)
mark_monitor(c, int(mon["id"]), status="expired", trigger_idx=idx, message="持仓已平")
_commit_monitor(c)
continue
if not result.get("ok"):
mark_monitor(
conn,
c,
int(mon["id"]),
status="active",
trigger_idx=idx,
message=str(result.get("msg") or result.get("stopped_reason") or "平仓未完成,将重试"),
)
_commit_monitor(conn)
_commit_monitor(c)
continue
done = _result_fully_done(result)
status = "triggered" if done else "closing"
mark_monitor(
conn,
c,
int(mon["id"]),
status=status,
trigger_idx=idx,
close_ord_id=result.get("close_ord_id"),
message="目标位触发限价平仓" if done else "目标位已挂买一限价,等待成交",
)
# 关键:先落库,再推送——否则后续 sync 异常回滚会让同一笔反复推微信
_commit_monitor(conn)
_commit_monitor(c)
triggered += 1
_notify_target_close(
cfg,
@@ -472,6 +493,11 @@ def run_options_target_closes(
target=target,
idx=idx,
result=result,
conn=conn,
conn=c,
)
if get_db is not None and conn is not None:
try:
conn.close()
except Exception:
pass
return triggered