Require real ask depth for options and hedge opens.

Block mark-as-ask opens, show reference mark when no depth, cap sheets to ask size; leave close paths unchanged. Document in docs/更新文档.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-16 12:48:53 +08:00
parent 195eeae295
commit 4686cf049a
10 changed files with 339 additions and 21 deletions
+49 -5
View File
@@ -779,6 +779,38 @@ def build_option_chain(
return out
def option_buy_liquidity_ok(ask: Any, ask_sz: Any) -> tuple[bool, str]:
"""开仓仅认真实卖一价+卖一深度;不接受标记价/内在价值顶包."""
a = _safe_float(ask)
s = _safe_float(ask_sz)
if a is None or a <= 0:
return False, "暂无卖一价,无法买入"
if s is None or s <= 0:
return False, "暂无卖一深度,无法买入"
return True, ""
def cap_option_buy_sheets_to_ask_depth(
sheets: int,
ask_sz: Any,
*,
min_sz: int = 1,
) -> tuple[int | None, str]:
"""将买入张数限制在卖一深度内(向下取整)."""
depth = _safe_float(ask_sz)
if depth is None or depth <= 0:
return None, "暂无卖一深度,无法买入"
max_sheets = int(math.floor(depth + 1e-12))
need = max(1, int(min_sz or 1))
if max_sheets < need:
return None, f"卖一深度不足 {need} 张(当前 {depth:g})"
want = max(0, int(sheets))
capped = min(want, max_sheets)
if capped < need:
return None, f"卖一深度不足 {need} 张(当前 {depth:g})"
return capped, ""
def quote_option_contract(ex: ccxt.okx, inst_id: str) -> dict[str, Any]:
inst_id = (inst_id or "").strip()
if not inst_id:
@@ -805,6 +837,7 @@ def quote_option_contract(ex: ccxt.okx, inst_id: str) -> dict[str, Any]:
return {"ok": False, "msg": "行情限频,请稍后重试"}
return {"ok": False, "msg": "合约不存在"}
t = t_rows[0] if t_rows else {}
# 开仓用真实盘口卖一;绝不把标记价写入 ask
ask = _safe_float(t.get("askPx"))
bid = _safe_float(t.get("bidPx"))
ask_sz = _safe_float(t.get("askSz"))
@@ -821,10 +854,15 @@ def quote_option_contract(ex: ccxt.okx, inst_id: str) -> dict[str, Any]:
bid_sz = book_bid_sz
mark = _safe_float(t.get("markPx"))
tick_sz = meta.get("tickSz")
if ask is None and mark is not None:
ask = round_option_px(mark, tick_sz, "buy")
# 买一缺失时仍可用标记价补展示(平仓路径读 bid);开仓 ask 不顶包
if bid is None and mark is not None:
bid = round_option_px(mark, tick_sz, "sell")
ref_ask = None
if ask is None and mark is not None and mark > 0:
ref_ask = round_option_px(mark, tick_sz, "buy")
can_open, open_block_msg = option_buy_liquidity_ok(ask, ask_sz)
book_ask = ask
book_ask_sz = ask_sz
uly = str(meta.get("uly") or "")
idx = fetch_index_price(ex, uly)
opt_type = meta.get("optType")
@@ -832,18 +870,24 @@ def quote_option_contract(ex: ccxt.okx, inst_id: str) -> dict[str, Any]:
expiry_be = expiry_breakeven_from_ask(
opt_type=str(opt_type or ""),
strike=strike,
ask_px=ask,
ask_px=book_ask if can_open else None,
mark_px=mark,
)
return {
"ok": True,
"inst_id": inst_id,
"meta": meta,
"ask": ask,
"ask": book_ask if can_open else None,
"bid": bid,
"ask_sz": ask_sz,
"ask_sz": book_ask_sz if can_open else None,
"bid_sz": bid_sz,
"mark": mark,
"ref_ask": ref_ask,
"book_ask": book_ask,
"book_ask_sz": book_ask_sz,
"can_open": can_open,
"ask_source": "book" if can_open else "none",
"open_block_msg": "" if can_open else open_block_msg,
"index_px": idx,
"expiry_be_px": expiry_be,
"dist_expiry_be": idx_distance_to_be(idx, expiry_be),