Gate option closes behind 2x recycle sustained for 2 minutes.
Require bid-side recoverable premium at least 2x cost continuously before target auto-close or depth close can fire. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import time
|
||||
from typing import Any, Callable
|
||||
|
||||
from lib.options.options_db import init_options_tables
|
||||
from lib.options.options_close_gate_lib import update_close_gate
|
||||
from lib.options.options_pricing_lib import (
|
||||
close_ref_prices,
|
||||
estimate_close_by_bids,
|
||||
@@ -333,28 +334,74 @@ def close_option_by_bid_depth(
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 残档买盘:禁止自动按买盘平仓(并撤掉可能已挂的异常低价卖单)
|
||||
# 残档买盘 / 回收未达 2×权利金持续门槛:禁止自动按买盘平仓
|
||||
premium_paid = None
|
||||
try:
|
||||
book0 = cfg["fetch_option_book_depth"](ex, inst_id, 5)
|
||||
usable0, stub_only0, stub_reason0 = filter_bids_for_close(
|
||||
book0.get("bids") or [], mark_px=mark_px, intrinsic_px=intrinsic_px
|
||||
)
|
||||
raw_bid0 = None
|
||||
if book0.get("bids"):
|
||||
raw_bid0 = _safe_float((book0.get("bids") or [{}])[0].get("px"))
|
||||
if not usable0:
|
||||
bid_chk = raw_bid0 or _safe_float(q.get("bid"))
|
||||
stub, stub_reason = is_stub_bid_px(bid_chk, mark_px=mark_px, intrinsic_px=intrinsic_px)
|
||||
if stub or stub_only0:
|
||||
_cancel_sell_pending()
|
||||
return {
|
||||
"ok": False,
|
||||
"msg": stub_reason0 or stub_reason or "暂无有效买盘,禁止自动平仓",
|
||||
"stopped_reason": "stub_bid",
|
||||
"auto_close_blocked": True,
|
||||
}
|
||||
conn_p = cfg["get_db"]()
|
||||
try:
|
||||
from lib.options.options_db import init_options_tables
|
||||
|
||||
init_options_tables(conn_p)
|
||||
prow = conn_p.execute(
|
||||
"SELECT premium_paid FROM options_trades WHERE inst_id = ? AND status = 'open' ORDER BY id DESC LIMIT 1",
|
||||
(inst_id,),
|
||||
).fetchone()
|
||||
if prow and prow["premium_paid"] is not None:
|
||||
premium_paid = float(prow["premium_paid"])
|
||||
finally:
|
||||
conn_p.close()
|
||||
except Exception:
|
||||
pass
|
||||
premium_paid = _safe_float(pos.get("premium_paid"))
|
||||
|
||||
book0 = cfg["fetch_option_book_depth"](ex, inst_id, 5)
|
||||
usable0, stub_only0, stub_reason0 = filter_bids_for_close(
|
||||
book0.get("bids") or [], mark_px=mark_px, intrinsic_px=intrinsic_px
|
||||
)
|
||||
raw_bid0 = None
|
||||
if book0.get("bids"):
|
||||
raw_bid0 = _safe_float((book0.get("bids") or [{}])[0].get("px"))
|
||||
if not usable0:
|
||||
bid_chk = raw_bid0 or _safe_float(q.get("bid"))
|
||||
stub, stub_reason = is_stub_bid_px(bid_chk, mark_px=mark_px, intrinsic_px=intrinsic_px)
|
||||
if stub or stub_only0:
|
||||
_cancel_sell_pending()
|
||||
update_close_gate(inst_id, recycle_usdc=None, premium_paid=premium_paid)
|
||||
return {
|
||||
"ok": False,
|
||||
"msg": stub_reason0 or stub_reason or "暂无有效买盘,禁止自动平仓",
|
||||
"stopped_reason": "stub_bid",
|
||||
"auto_close_blocked": True,
|
||||
}
|
||||
preview0 = estimate_close_by_bids(
|
||||
book0.get("bids") or [],
|
||||
close_sheets,
|
||||
ct_mult=ct_mult,
|
||||
premium_paid=premium_paid,
|
||||
mark_px=mark_px,
|
||||
intrinsic_px=intrinsic_px,
|
||||
)
|
||||
if preview0.get("bid_invalid"):
|
||||
_cancel_sell_pending()
|
||||
update_close_gate(inst_id, recycle_usdc=None, premium_paid=premium_paid)
|
||||
return {
|
||||
"ok": False,
|
||||
"msg": preview0.get("bid_invalid_reason") or "暂无有效买盘,禁止自动平仓",
|
||||
"stopped_reason": "stub_bid",
|
||||
"auto_close_blocked": True,
|
||||
}
|
||||
gate0 = update_close_gate(
|
||||
inst_id,
|
||||
recycle_usdc=_safe_float(preview0.get("total_received")),
|
||||
premium_paid=premium_paid,
|
||||
)
|
||||
if not gate0.get("ready"):
|
||||
return {
|
||||
"ok": False,
|
||||
"msg": gate0.get("msg") or "平仓门控未就绪",
|
||||
"stopped_reason": "close_gate",
|
||||
"auto_close_blocked": True,
|
||||
"close_gate": gate0,
|
||||
}
|
||||
|
||||
# 已有未成交卖平单时先等成交,避免每轮撤单重挂反复推送/吃档
|
||||
try:
|
||||
@@ -372,6 +419,9 @@ def close_option_by_bid_depth(
|
||||
return {"ok": False, "msg": "获取期权持仓失败"}
|
||||
pos = next((p for p in raw_positions if str(p.get("instId")) == inst_id), None)
|
||||
if not pos or _avail(pos) < 1:
|
||||
from lib.options.options_close_gate_lib import clear_close_gate
|
||||
|
||||
clear_close_gate(inst_id)
|
||||
return {
|
||||
"ok": True,
|
||||
"already_flat": True,
|
||||
@@ -564,6 +614,9 @@ def close_option_by_bid_depth(
|
||||
prem_recv = round(total_received, 4)
|
||||
fully_submitted = submitted_sheets >= close_sheets and stopped_reason is None
|
||||
close_ord_id = ",".join(ord_ids) if ord_ids else None
|
||||
from lib.options.options_close_gate_lib import clear_close_gate
|
||||
|
||||
clear_close_gate(inst_id)
|
||||
|
||||
conn = cfg["get_db"]()
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user