Add pre-buy expiry breakeven columns to options chain table.

Show estimated expiry balance and distance from index in the chain list and order panel using ask price before opening a position.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-07 16:21:22 +08:00
parent 3570a6900e
commit 99f13817f8
6 changed files with 96 additions and 8 deletions
+12
View File
@@ -2588,6 +2588,18 @@ html[data-theme="light"] .settings-side-export-label {
.options-page-wrap .options-strike-table code {
font-size: 0.66rem;
}
.opt-be-dist-up {
color: #5ee89a;
}
.opt-be-dist-down {
color: #ff8a8a;
}
html[data-theme="light"] .opt-be-dist-up {
color: #0d7a45;
}
html[data-theme="light"] .opt-be-dist-down {
color: #c62828;
}
.options-chain-toolbar .btn-secondary.active,
.opt-uly-btn.active,
.opt-type-btn.active {
+28 -2
View File
@@ -149,6 +149,21 @@
"指数 " + state.underlying + " ≈ " + fmt(idx, 2) + " · 实值=价内 · 虚值=价外";
}
function fmtDist(v) {
if (v === null || v === undefined || Number.isNaN(Number(v))) return "—";
const n = Number(v);
const sign = n > 0 ? "+" : "";
return sign + n.toFixed(1);
}
function distBeClass(v) {
if (v === null || v === undefined || Number.isNaN(Number(v))) return "";
const n = Number(v);
if (n > 0) return "opt-be-dist-up";
if (n < 0) return "opt-be-dist-down";
return "";
}
function renderStrikes() {
const tbody = document.getElementById("opt-strike-tbody");
const expMs = document.getElementById("opt-exp-select").value;
@@ -156,7 +171,7 @@
parkOrderPanel();
tbody.innerHTML = "";
if (!expMs || !state.chain) {
tbody.innerHTML = '<tr><td colspan="6" class="muted">请选择到期日</td></tr>';
tbody.innerHTML = '<tr><td colspan="8" class="muted">请选择到期日</td></tr>';
state.selectedInst = null;
return;
}
@@ -168,7 +183,7 @@
return c.opt_type === state.optType;
});
if (!list.length) {
tbody.innerHTML = '<tr><td colspan="6" class="muted">该到期日暂无报价</td></tr>';
tbody.innerHTML = '<tr><td colspan="8" class="muted">该到期日暂无报价</td></tr>';
state.selectedInst = null;
return;
}
@@ -184,6 +199,8 @@
"<td><code>" + c.inst_id + "</code></td>" +
"<td>" + fmt(c.ask, 4) + "</td>" +
"<td>" + fmt(c.bid, 4) + "</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">' +
'<button type="button" class="btn-secondary opt-pick-btn" data-inst="' + c.inst_id + '">选择</button> ' +
'<button type="button" class="btn-primary opt-buy-btn" data-inst="' + c.inst_id + '">买入</button>' +
@@ -216,6 +233,15 @@
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" : "—";
const beEl = document.getElementById("opt-order-expiry-be");
const distEl = document.getElementById("opt-order-dist-be");
if (beEl) {
beEl.textContent = d.expiry_be_px != null ? fmt(d.expiry_be_px, 0) : "—";
}
if (distEl) {
distEl.textContent = fmtDist(d.dist_expiry_be);
distEl.className = "v " + distBeClass(d.dist_expiry_be);
}
const msgEl = document.getElementById("opt-order-msg");
if (!d.ok) {
msgEl.textContent = d.msg || "报价失败";