修复期权币本位高危缺陷:开仓估量、卖回封顶、握库超时与条件单嵌套锁。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user