Block option auto-close on stub bids far below mark.
Reject target and depth closes when bid is a residual tick, and show invalid-bid UI instead of recycling at junk prices. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -13,8 +13,12 @@ from lib.options.options_db import init_options_tables
|
||||
from lib.options.options_monitor_lib import options_monitor_loop
|
||||
from lib.options.options_pricing_lib import (
|
||||
calc_order_size,
|
||||
close_ref_prices,
|
||||
ct_mult_from_meta,
|
||||
estimate_close_by_bids,
|
||||
fetch_option_mark_px,
|
||||
filter_bids_for_close,
|
||||
is_stub_bid_px,
|
||||
min_sz_from_meta,
|
||||
premium_per_sheet,
|
||||
total_premium,
|
||||
@@ -707,6 +711,41 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
|
||||
return jsonify(order)
|
||||
elif depth_split:
|
||||
ct_mult = float(q.get("ct_mult") or 0.01)
|
||||
from lib.exchange.okx_options_lib import option_fields_from_inst_id
|
||||
|
||||
mark_px = _safe_float(pos.get("markPx")) or _safe_float(q.get("mark_px") or q.get("mark"))
|
||||
if mark_px is None:
|
||||
mark_px = fetch_option_mark_px(ex, inst_id)
|
||||
opt_type = pos.get("optType") or q.get("opt_type")
|
||||
strike = _safe_float(pos.get("stk")) or _safe_float(q.get("strike"))
|
||||
if not opt_type or strike is None:
|
||||
pt, ps = option_fields_from_inst_id(inst_id)
|
||||
opt_type = opt_type or pt
|
||||
if strike is None:
|
||||
strike = ps
|
||||
idx_px = _safe_float(pos.get("idxPx")) or _safe_float(q.get("index_px"))
|
||||
mark_px, intrinsic_px = close_ref_prices(
|
||||
mark_px=mark_px, opt_type=str(opt_type or ""), strike=strike, index_px=idx_px
|
||||
)
|
||||
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
|
||||
)
|
||||
if stub_only0 or not usable0:
|
||||
bid_chk = None
|
||||
if book0.get("bids"):
|
||||
bid_chk = _safe_float((book0.get("bids") or [{}])[0].get("px"))
|
||||
bid_chk = bid_chk or _safe_float(bid)
|
||||
stub, stub_reason = is_stub_bid_px(bid_chk, mark_px=mark_px, intrinsic_px=intrinsic_px)
|
||||
if stub or stub_only0:
|
||||
return jsonify(
|
||||
{
|
||||
"ok": False,
|
||||
"msg": stub_reason0 or stub_reason or "暂无有效买盘,禁止按买盘自动平仓",
|
||||
"stopped_reason": "stub_bid",
|
||||
"auto_close_blocked": True,
|
||||
}
|
||||
)
|
||||
remaining = close_sheets
|
||||
submitted_sheets = 0
|
||||
filled_or_reduced_sheets = 0
|
||||
@@ -726,7 +765,22 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
|
||||
break
|
||||
remaining = min(remaining, current_avail)
|
||||
book = cfg["fetch_option_book_depth"](ex, inst_id, 5)
|
||||
preview = estimate_close_by_bids(book.get("bids") or [], remaining, ct_mult=ct_mult)
|
||||
preview = estimate_close_by_bids(
|
||||
book.get("bids") or [],
|
||||
remaining,
|
||||
ct_mult=ct_mult,
|
||||
mark_px=mark_px,
|
||||
intrinsic_px=intrinsic_px,
|
||||
)
|
||||
if preview.get("auto_close_blocked") or preview.get("bid_invalid"):
|
||||
return jsonify(
|
||||
{
|
||||
"ok": False,
|
||||
"msg": preview.get("bid_invalid_reason") or "暂无有效买盘,禁止按买盘自动平仓",
|
||||
"stopped_reason": "stub_bid",
|
||||
"auto_close_blocked": True,
|
||||
}
|
||||
)
|
||||
levels = preview.get("levels") or []
|
||||
if not levels:
|
||||
stopped_reason = "no_bid_depth"
|
||||
@@ -829,7 +883,33 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
|
||||
}
|
||||
)
|
||||
else:
|
||||
from lib.exchange.okx_options_lib import option_fields_from_inst_id
|
||||
|
||||
mark_px = _safe_float(pos.get("markPx")) or _safe_float(q.get("mark_px") or q.get("mark"))
|
||||
if mark_px is None:
|
||||
mark_px = fetch_option_mark_px(ex, inst_id)
|
||||
opt_type = pos.get("optType") or q.get("opt_type")
|
||||
strike = _safe_float(pos.get("stk")) or _safe_float(q.get("strike"))
|
||||
if not opt_type or strike is None:
|
||||
pt, ps = option_fields_from_inst_id(inst_id)
|
||||
opt_type = opt_type or pt
|
||||
if strike is None:
|
||||
strike = ps
|
||||
idx_px = _safe_float(pos.get("idxPx")) or _safe_float(q.get("index_px"))
|
||||
mark_px, intrinsic_px = close_ref_prices(
|
||||
mark_px=mark_px, opt_type=str(opt_type or ""), strike=strike, index_px=idx_px
|
||||
)
|
||||
close_px = float(bid)
|
||||
stub, stub_reason = is_stub_bid_px(close_px, mark_px=mark_px, intrinsic_px=intrinsic_px)
|
||||
if stub:
|
||||
return jsonify(
|
||||
{
|
||||
"ok": False,
|
||||
"msg": stub_reason or "暂无有效买盘,禁止按买盘自动平仓",
|
||||
"stopped_reason": "stub_bid",
|
||||
"auto_close_blocked": True,
|
||||
}
|
||||
)
|
||||
order = cfg["place_option_limit_order"](
|
||||
ex,
|
||||
inst_id=inst_id,
|
||||
|
||||
Reference in New Issue
Block a user