Add ITM and OTM filter toggles to options chain.

Default to in-the-money view with at-the-money contracts included; update expiry counts and empty states for the active filter.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-10 11:25:24 +08:00
parent b70ce510ef
commit 9f255f13dd
3 changed files with 37 additions and 7 deletions
+2
View File
@@ -3034,6 +3034,7 @@ html[data-theme="light"] .opt-be-dist-down {
.options-chain-toolbar .btn-secondary.active,
.opt-uly-btn.active,
.opt-type-btn.active,
.opt-money-btn.active,
.opt-pos-tab.active {
border-color: #5b8cff;
color: #cfe0ff;
@@ -3681,6 +3682,7 @@ html[data-theme="light"] .options-page-wrap .options-stat-item .v {
html[data-theme="light"] .options-chain-toolbar .btn-secondary.active,
html[data-theme="light"] .opt-uly-btn.active,
html[data-theme="light"] .opt-type-btn.active,
html[data-theme="light"] .opt-money-btn.active,
html[data-theme="light"] .opt-pos-tab.active {
border-color: rgba(0, 95, 140, 0.45) !important;
color: #004d6e !important;
+32 -6
View File
@@ -11,6 +11,7 @@
const state = {
underlying: root.dataset.defaultUnderly || "ETH",
optType: "C",
moneyFilter: "itm",
chain: panelCache.chain || null,
selectedInst: null,
orderQuote: null,
@@ -116,6 +117,22 @@
return url;
}
function matchesMoneyFilter(moneyness) {
const m = (moneyness || "").toLowerCase();
if (state.moneyFilter === "otm") return m === "otm";
return m === "itm" || m === "atm";
}
function moneyFilterLabel() {
return state.moneyFilter === "otm" ? "虚值" : "实值";
}
function filterChainContracts(contracts) {
return (contracts || []).filter(function (c) {
return c.opt_type === state.optType && matchesMoneyFilter(c.moneyness);
});
}
function moneynessBadge(c) {
const m = (c && c.moneyness) || "";
const label = (c && c.moneyness_label) || "—";
@@ -145,7 +162,7 @@
exps.forEach(function (e) {
const o = document.createElement("option");
o.value = String(e.exp_time);
o.textContent = expLabel(e.exp_time) + " (" + e.contracts.length + ")";
o.textContent = expLabel(e.exp_time) + " (" + filterChainContracts(e.contracts).length + ")";
sel.appendChild(o);
});
const idx = state.chain && state.chain.index_px;
@@ -155,7 +172,7 @@
if (el) el.textContent = String(Math.round(dte));
}
document.getElementById("opt-index-line").textContent =
"指数 " + state.underlying + " ≈ " + fmt(idx, 2) + " · 实值=价内 · 虚值=价外";
"指数 " + state.underlying + " ≈ " + fmt(idx, 2) + " · 实值含平值 · 虚值=价外";
}
function fmtPxSz(px, sz, estimated) {
@@ -286,11 +303,9 @@
return String(e.exp_time) === String(expMs);
});
if (!exp) return;
const list = (exp.contracts || []).filter(function (c) {
return c.opt_type === state.optType;
});
const list = filterChainContracts(exp.contracts);
if (!list.length) {
tbody.innerHTML = '<tr><td colspan="8" class="muted">该到期日暂无报价</td></tr>';
tbody.innerHTML = '<tr><td colspan="8" class="muted">该到期日暂无' + moneyFilterLabel() + "合约</td></tr>";
state.selectedInst = null;
return;
}
@@ -805,6 +820,17 @@
document.querySelectorAll(".opt-type-btn").forEach(function (b) { b.classList.remove("active"); });
btn.classList.add("active");
state.optType = btn.getAttribute("data-type");
renderExpiries();
renderStrikes();
});
});
document.querySelectorAll(".opt-money-btn").forEach(function (btn) {
btn.addEventListener("click", function () {
document.querySelectorAll(".opt-money-btn").forEach(function (b) { b.classList.remove("active"); });
btn.classList.add("active");
state.moneyFilter = btn.getAttribute("data-money") || "itm";
renderExpiries();
renderStrikes();
});
});
+3 -1
View File
@@ -14,6 +14,8 @@
<select id="opt-exp-select"><option value="">选择到期日</option></select>
<button type="button" class="btn-secondary opt-type-btn active" data-type="C">看涨 Call</button>
<button type="button" class="btn-secondary opt-type-btn" data-type="P">看跌 Put</button>
<button type="button" class="btn-secondary opt-money-btn active" data-money="itm">实值</button>
<button type="button" class="btn-secondary opt-money-btn" data-money="otm">虚值</button>
<button type="button" class="btn-secondary" id="opt-load-chain">刷新链</button>
</div>
<div id="opt-index-line" class="muted"></div>
@@ -139,4 +141,4 @@
</div>
</div>
<script src="/static/options_expiry_countdown.js?v=1"></script>
<script src="/static/options_panel.js?v=18"></script>
<script src="/static/options_panel.js?v=19"></script>