From 280e59eb25a342ca56c901b7e10a24acec627496 Mon Sep 17 00:00:00 2001 From: dekun Date: Wed, 15 Jul 2026 15:45:36 +0800 Subject: [PATCH] Cancel pending option sells before target auto-close. Prevents duplicate sells from stacking into short opens when the bid book is empty and mark fallback retries. Co-authored-by: Cursor --- lib/options/options_target_lib.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/options/options_target_lib.py b/lib/options/options_target_lib.py index 7a9e192..d526803 100644 --- a/lib/options/options_target_lib.py +++ b/lib/options/options_target_lib.py @@ -246,6 +246,34 @@ def close_option_by_bid_depth( td_mode = str(pos.get("mgnMode") or cfg.get("td_mode") or "isolated") pos_side = _pos_side_from_position(pos) or "net" + # 先撤本合约未完成卖单,避免重复挂单被当成开空占用保证金 + try: + pending = ex.private_get_trade_orders_pending({"instType": "OPTION", "instId": inst_id}) or {} + for o in pending.get("data") or []: + if str(o.get("side") or "").lower() != "sell": + continue + oid = o.get("ordId") + if not oid: + continue + try: + ex.private_post_trade_cancel_order({"instId": inst_id, "ordId": oid}) + except Exception: + pass + time.sleep(0.3) + invalidate_option_positions_cache() + raw_positions = cfg["fetch_option_positions"](ex) + if raw_positions is None: + return {"ok": False, "msg": "获取期权持仓失败"} + pos = next((p for p in raw_positions if str(p.get("instId")) == inst_id), None) + if not pos: + return {"ok": False, "msg": "未找到持仓", "already_flat": True} + avail = _avail(pos) + close_sheets = min(close_sheets, avail) + if close_sheets < 1: + return {"ok": False, "msg": "可平张数不足", "already_flat": True} + except Exception: + pass + remaining = close_sheets submitted_sheets = 0 filled_or_reduced_sheets = 0