Fix ghost finalize on unknown perp size and open rollback hazards.

Distinguish exchange query None from flat zero; keep opening when size unknown; idempotent half_open cash; scan options while opening; continue manage after recover.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-29 20:47:29 +08:00
parent e2a19a1614
commit 101cb3c045
6 changed files with 153 additions and 76 deletions
+35 -8
View File
@@ -197,11 +197,11 @@ class BinanceLiveExecutor(Matcher):
)
except Exception:
live_perp = None
if live_perp is not None and live_perp > 1e-8:
if live_perp is None or live_perp > 1e-8:
return OpenResult(
ok=False,
detail=(
f"永续可能已成交但未确认成交明细(保留 opening): {e}; "
f"永续开仓未确认(保留 opening,禁止回滚期权): {e}; "
f"ex_perp={live_perp}"
),
)
@@ -397,13 +397,18 @@ class BinanceLiveExecutor(Matcher):
"""期权已成交、永续未开且回滚失败 → 落 half_open,禁止新开,待 repair。"""
perp_inst = resolve_perp_inst_id(self.db, group_id=group_id)
initial_premium = of_px * opt_qty
self.ledger.apply_cash(
-(of_px * opt_qty + of_fee),
kind="open_option",
group_id=group_id,
note=f"LIVE-BN half_open option {group_id}",
allow_negative=True,
prior_cash = self.db.fetchone(
"SELECT id FROM ledger_entries WHERE group_id=? AND kind='open_option' LIMIT 1",
(group_id,),
)
if prior_cash is None:
self.ledger.apply_cash(
-(of_px * opt_qty + of_fee),
kind="open_option",
group_id=group_id,
note=f"LIVE-BN half_open option {group_id}",
allow_negative=True,
)
now = int(time.time() * 1000)
with self.db._lock:
existing = self.db._conn.execute(
@@ -598,6 +603,18 @@ class BinanceLiveExecutor(Matcher):
pf_px = entry_index if entry_index > 0 else of_px
initial_premium = of_px * opt_qty
mgn = self._perp_margin_mode()
prior_cash = self.db.fetchone(
"SELECT id FROM ledger_entries WHERE group_id=? AND kind='open_option' LIMIT 1",
(group_id,),
)
if prior_cash is None and of_px > 0 and opt_qty > 0:
self.ledger.apply_cash(
-(of_px * opt_qty),
kind="open_option",
group_id=group_id,
note=f"LIVE-BN recover promote open_option {group_id}",
allow_negative=True,
)
now = int(time.time() * 1000)
with self.db._lock:
existing = self.db._conn.execute(
@@ -822,6 +839,11 @@ class BinanceLiveExecutor(Matcher):
perp_qty_eth=perp_qty,
allow_db_fallback=not pending_perp_only,
)
if perp_qty_close is None:
return CloseResult(
ok=False,
detail="期权已平,永续待平(无法核对交易所仓位,禁止空仓 finalize)",
)
if perp_qty_close <= 0:
pf_px = float(pos.get("perp_entry_px") or 0) or 0.0
pf_fee = 0.0
@@ -1135,6 +1157,11 @@ class BinanceLiveExecutor(Matcher):
perp_side=perp_side,
perp_qty_eth=perp_qty,
)
if perp_qty_close is None or perp_qty_close <= 0:
return CloseResult(
ok=False,
detail="币安平永续失败: 无法取得有效永续仓位数量",
)
perp_live = client.place_perp_market(
symbol=perp_inst,
side=side,