Show bid/ask liquidity as price per sheet in options chain.
Display OKX askSz and bidSz beside top-of-book prices in the chain table and order panel using price/sheets format. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2588,6 +2588,10 @@ html[data-theme="light"] .settings-side-export-label {
|
||||
.options-page-wrap .options-strike-table code {
|
||||
font-size: 0.66rem;
|
||||
}
|
||||
.opt-px-sz {
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.opt-be-dist-up {
|
||||
color: #5ee89a;
|
||||
}
|
||||
|
||||
@@ -149,6 +149,15 @@
|
||||
"指数 " + state.underlying + " ≈ " + fmt(idx, 2) + " · 实值=价内 · 虚值=价外";
|
||||
}
|
||||
|
||||
function fmtPxSz(px, sz) {
|
||||
if (px === null || px === undefined || Number.isNaN(Number(px))) return "—";
|
||||
const price = Number(px).toFixed(4).replace(/\.?0+$/, "");
|
||||
if (sz === null || sz === undefined || sz === "" || Number.isNaN(Number(sz))) return price;
|
||||
const s = Number(sz);
|
||||
const size = Math.abs(s - Math.round(s)) < 1e-9 ? String(Math.round(s)) : String(s);
|
||||
return price + "/" + size;
|
||||
}
|
||||
|
||||
function fmtDist(v) {
|
||||
if (v === null || v === undefined || Number.isNaN(Number(v))) return "—";
|
||||
const n = Number(v);
|
||||
@@ -197,8 +206,8 @@
|
||||
"<td>" + c.strike + "</td>" +
|
||||
"<td>" + moneynessBadge(c) + "</td>" +
|
||||
"<td><code>" + c.inst_id + "</code></td>" +
|
||||
"<td>" + fmt(c.ask, 4) + "</td>" +
|
||||
"<td>" + fmt(c.bid, 4) + "</td>" +
|
||||
"<td class=\"opt-px-sz\">" + fmtPxSz(c.ask, c.ask_sz) + "</td>" +
|
||||
"<td class=\"opt-px-sz\">" + fmtPxSz(c.bid, c.bid_sz) + "</td>" +
|
||||
"<td>" + (c.expiry_be_px != null ? fmt(c.expiry_be_px, 0) : "—") + "</td>" +
|
||||
'<td class="' + distBeClass(c.dist_expiry_be) + '">' + fmtDist(c.dist_expiry_be) + "</td>" +
|
||||
'<td class="opt-row-actions">' +
|
||||
@@ -229,7 +238,9 @@
|
||||
function fillOrderPanel(d) {
|
||||
const sz = d.sizing || {};
|
||||
document.getElementById("opt-order-inst").textContent = d.inst_id || state.selectedInst || "";
|
||||
document.getElementById("opt-order-ask").textContent = fmt(d.ask, 4);
|
||||
document.getElementById("opt-order-ask").textContent = fmtPxSz(d.ask, d.ask_sz);
|
||||
const bidEl = document.getElementById("opt-order-bid");
|
||||
if (bidEl) bidEl.textContent = fmtPxSz(d.bid, d.bid_sz);
|
||||
document.getElementById("opt-order-sheets").textContent = sz.sheets != null ? sz.sheets : "—";
|
||||
document.getElementById("opt-order-eth").textContent = sz.eth_amount != null ? sz.eth_amount : "—";
|
||||
document.getElementById("opt-order-premium").textContent = sz.total_premium != null ? fmt(sz.total_premium, 4) + " USDC" : "—";
|
||||
|
||||
@@ -116,18 +116,27 @@ def format_option_px(px: float, tick_sz: Any) -> str:
|
||||
|
||||
|
||||
def _fetch_book_bid_ask(ex: ccxt.okx, inst_id: str) -> tuple[float | None, float | None]:
|
||||
bid, ask, _, _ = _fetch_book_top(ex, inst_id)
|
||||
return bid, ask
|
||||
|
||||
|
||||
def _fetch_book_top(
|
||||
ex: ccxt.okx, inst_id: str
|
||||
) -> tuple[float | None, float | None, float | None, float | None]:
|
||||
try:
|
||||
rows = ex.public_get_market_books({"instId": inst_id, "sz": "1"}).get("data") or []
|
||||
if not rows:
|
||||
return None, None
|
||||
return None, None, None, None
|
||||
row = rows[0]
|
||||
asks = row.get("asks") or []
|
||||
bids = row.get("bids") or []
|
||||
ask = _safe_float(asks[0][0]) if asks else None
|
||||
bid = _safe_float(bids[0][0]) if bids else None
|
||||
return bid, ask
|
||||
ask_sz = _safe_float(asks[0][1]) if asks and len(asks[0]) > 1 else None
|
||||
bid_sz = _safe_float(bids[0][1]) if bids and len(bids[0]) > 1 else None
|
||||
return bid, ask, bid_sz, ask_sz
|
||||
except Exception:
|
||||
return None, None
|
||||
return None, None, None, None
|
||||
|
||||
|
||||
def _pos_side_from_position(pos: dict[str, Any] | None) -> str | None:
|
||||
@@ -338,6 +347,8 @@ def build_option_chain(
|
||||
ask = _safe_float(t.get("askPx"))
|
||||
bid = _safe_float(t.get("bidPx"))
|
||||
mark = _safe_float(t.get("markPx"))
|
||||
ask_sz = _safe_float(t.get("askSz"))
|
||||
bid_sz = _safe_float(t.get("bidSz"))
|
||||
if ask is None and bid is None and mark is None:
|
||||
continue
|
||||
expiry_be = expiry_breakeven_from_ask(
|
||||
@@ -356,6 +367,8 @@ def build_option_chain(
|
||||
"exp_time": exp_ms,
|
||||
"ask": ask,
|
||||
"bid": bid,
|
||||
"ask_sz": ask_sz,
|
||||
"bid_sz": bid_sz,
|
||||
"mark_px": mark,
|
||||
"expiry_be_px": expiry_be,
|
||||
"dist_expiry_be": idx_distance_to_be(idx, expiry_be),
|
||||
@@ -385,12 +398,18 @@ def quote_option_contract(ex: ccxt.okx, inst_id: str) -> dict[str, Any]:
|
||||
t = t_rows[0] if t_rows else {}
|
||||
ask = _safe_float(t.get("askPx"))
|
||||
bid = _safe_float(t.get("bidPx"))
|
||||
if ask is None or bid is None:
|
||||
book_bid, book_ask = _fetch_book_bid_ask(ex, inst_id)
|
||||
ask_sz = _safe_float(t.get("askSz"))
|
||||
bid_sz = _safe_float(t.get("bidSz"))
|
||||
if ask is None or bid is None or ask_sz is None or bid_sz is None:
|
||||
book_bid, book_ask, book_bid_sz, book_ask_sz = _fetch_book_top(ex, inst_id)
|
||||
if ask is None:
|
||||
ask = book_ask
|
||||
if bid is None:
|
||||
bid = book_bid
|
||||
if ask_sz is None:
|
||||
ask_sz = book_ask_sz
|
||||
if bid_sz is None:
|
||||
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:
|
||||
@@ -413,6 +432,8 @@ def quote_option_contract(ex: ccxt.okx, inst_id: str) -> dict[str, Any]:
|
||||
"meta": meta,
|
||||
"ask": ask,
|
||||
"bid": bid,
|
||||
"ask_sz": ask_sz,
|
||||
"bid_sz": bid_sz,
|
||||
"mark": mark,
|
||||
"index_px": idx,
|
||||
"expiry_be_px": expiry_be,
|
||||
|
||||
@@ -28,6 +28,24 @@ def premium_per_sheet(quote_per_unit: float, ct_mult: float = 0.01) -> float:
|
||||
return float(quote_per_unit) * float(ct_mult)
|
||||
|
||||
|
||||
def format_quote_liquidity(px: float | None, sz: float | None, *, px_decimals: int = 4) -> str | None:
|
||||
"""盘口展示:价格/张数,如 17.2/150。"""
|
||||
if px is None:
|
||||
return None
|
||||
try:
|
||||
price = f"{float(px):.{px_decimals}f}".rstrip("0").rstrip(".")
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
if sz is None:
|
||||
return price
|
||||
try:
|
||||
s = float(sz)
|
||||
size = str(int(s)) if abs(s - int(s)) < 1e-9 else str(s).rstrip("0").rstrip(".")
|
||||
except (TypeError, ValueError):
|
||||
return price
|
||||
return f"{price}/{size}"
|
||||
|
||||
|
||||
def total_premium(quote_per_unit: float, eth_amount: float, ct_mult: float = 0.01) -> float:
|
||||
return float(quote_per_unit) * float(eth_amount)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="options-dual-grid">
|
||||
<div class="card options-order-card">
|
||||
<h2>期权下单</h2>
|
||||
<p class="muted options-hint">报价单位为每 1 ETH/BTC;1 张 = 0.01。链展示近 <span id="opt-chain-dte">14</span> 日到期,标注实值/虚值;<strong>到期平衡</strong>按卖一预估(无卖一按标记价)。资金划转与 USDT/USDC 兑换见「系统设置 → 期权设置」。</p>
|
||||
<p class="muted options-hint">报价单位为每 1 ETH/BTC;1 张 = 0.01。卖一/买一列为 <strong>价格/张数</strong>。链展示近 <span id="opt-chain-dte">14</span> 日到期,标注实值/虚值;<strong>到期平衡</strong>按卖一预估(无卖一按标记价)。资金划转与 USDT/USDC 兑换见「系统设置 → 期权设置」。</p>
|
||||
<div class="form-row options-chain-toolbar">
|
||||
<button type="button" class="btn-secondary opt-uly-btn active" data-uly="ETH">ETH</button>
|
||||
<button type="button" class="btn-secondary opt-uly-btn" data-uly="BTC">BTC</button>
|
||||
@@ -24,8 +24,8 @@
|
||||
<th>行权价</th>
|
||||
<th>类型</th>
|
||||
<th>合约</th>
|
||||
<th>卖一</th>
|
||||
<th>买一</th>
|
||||
<th>卖一/张</th>
|
||||
<th>买一/张</th>
|
||||
<th>到期平衡</th>
|
||||
<th>距平衡</th>
|
||||
<th>操作</th>
|
||||
@@ -41,7 +41,8 @@
|
||||
<h3 class="opt-order-title">下单</h3>
|
||||
<div id="opt-order-inst" class="options-order-inst"></div>
|
||||
<div class="options-order-grid">
|
||||
<div><span class="k">卖一(每1币)</span><span id="opt-order-ask" class="v">—</span></div>
|
||||
<div><span class="k">卖一/张</span><span id="opt-order-ask" class="v">—</span></div>
|
||||
<div><span class="k">买一/张</span><span id="opt-order-bid" class="v">—</span></div>
|
||||
<div><span class="k">张数</span><span id="opt-order-sheets" class="v">—</span></div>
|
||||
<div><span class="k">ETH/BTC 数量</span><span id="opt-order-eth" class="v">—</span></div>
|
||||
<div><span class="k">预估权利金</span><span id="opt-order-premium" class="v">—</span></div>
|
||||
|
||||
Reference in New Issue
Block a user