diff --git a/lib/common/static/options_panel.js b/lib/common/static/options_panel.js index 089a09f..0ae34d1 100644 --- a/lib/common/static/options_panel.js +++ b/lib/common/static/options_panel.js @@ -352,7 +352,7 @@ const typeGroup = document.getElementById("opt-type-btn-group"); if (typeGroup) typeGroup.hidden = isT; const expandWrap = document.getElementById("opt-strike-expand-wrap"); - if (expandWrap) expandWrap.hidden = !isT; + if (expandWrap) expandWrap.hidden = false; const headList = document.getElementById("opt-strike-head-list"); const headT = document.getElementById("opt-strike-head-t"); const headTCols = document.getElementById("opt-strike-head-t-cols"); @@ -472,16 +472,59 @@ }); } + // 默认窗口:平值 + 实值 3 档 + 虚值 3 档(T 型按行权价 ATM±3) + const DEFAULT_ATM_SIDE = 3; + function sliceAtmWindow(rows, indexPx) { if (state.strikeExpandAll || !rows.length) return rows; const atmStrike = findAtmStrike(rows, indexPx); const idx = rows.findIndex(function (r) { return Number(r.strike) === Number(atmStrike); }); - if (idx < 0) return rows.slice(0, Math.min(rows.length, 11)); - const start = Math.max(0, idx - 5); - const end = Math.min(rows.length, idx + 6); + const side = DEFAULT_ATM_SIDE; + if (idx < 0) return rows.slice(0, Math.min(rows.length, side * 2 + 1)); + const start = Math.max(0, idx - side); + const end = Math.min(rows.length, idx + side + 1); return rows.slice(start, end); } + function sliceListByMoneyness(list) { + if (state.strikeExpandAll || !list.length) return list; + const sorted = list.slice().sort(function (a, b) { + return Number(a.strike) - Number(b.strike); + }); + const itm = []; + const atm = []; + const otm = []; + sorted.forEach(function (c) { + const m = String(c.moneyness || "").toLowerCase(); + if (m === "atm") atm.push(c); + else if (m === "itm") itm.push(c); + else if (m === "otm") otm.push(c); + }); + if (!atm.length && !itm.length && !otm.length) { + const indexPx = state.chain && state.chain.index_px; + return sliceAtmWindow( + sorted.map(function (c) { return { strike: c.strike, _c: c }; }), + indexPx + ).map(function (r) { return r._c; }); + } + const n = DEFAULT_ATM_SIDE; + const isPut = String(state.optType || "").toUpperCase() === "P"; + // Call: ITM 在下方取靠近 ATM 的末 N;OTM 取前 N。Put 相反。 + const pickedItm = isPut ? itm.slice(0, n) : itm.slice(-n); + const pickedOtm = isPut ? otm.slice(-n) : otm.slice(0, n); + return pickedItm.concat(atm, pickedOtm).sort(function (a, b) { + return Number(a.strike) - Number(b.strike); + }); + } + + function strikeWindowHintHtml(cols) { + return ( + '默认显示平值 + 实值3档 + 虚值3档 · 勾选「展开全部」查看该到期全部行权价' + ); + } + function straddleAskPerUnit(callAsk, putAsk) { const c = Number(callAsk); const p = Number(putAsk); @@ -950,7 +993,8 @@ state.selectedInst = null; return; } - const list = filterChainContracts(exp.contracts); + let list = filterChainContracts(exp.contracts); + list = sliceListByMoneyness(list); if (!list.length) { const label = moneyFilterLabel(); const suffix = label ? label : optTypeLabel(state.optType); @@ -961,11 +1005,18 @@ } let matchedSelected = false; const indexPx = state.chain && state.chain.index_px; + const atmStrike = findAtmStrike( + list.map(function (c) { return { strike: c.strike }; }), + indexPx + ); list.forEach(function (c) { const tr = document.createElement("tr"); tr.className = "opt-strike-row"; tr.setAttribute("data-inst", c.inst_id); if (c.moneyness) tr.classList.add("opt-row-" + c.moneyness); + if (atmStrike != null && Number(c.strike) === Number(atmStrike)) { + tr.classList.add("opt-strike-row-atm"); + } const chainLev = calcAskLeverage(indexPx, c.ask); tr.innerHTML = "" + c.strike + "" + @@ -982,6 +1033,12 @@ tbody.appendChild(tr); if (c.inst_id === prevSelected) matchedSelected = true; }); + if (!state.strikeExpandAll && list.length >= 1) { + const hint = document.createElement("tr"); + hint.className = "opt-strike-hint-row"; + hint.innerHTML = strikeWindowHintHtml(cols); + tbody.appendChild(hint); + } finishStrikeRender(tbody, prevSelected, matchedSelected); } @@ -1046,7 +1103,7 @@ if (!state.strikeExpandAll && rows.length >= 1) { const hint = document.createElement("tr"); hint.className = "opt-strike-hint-row"; - hint.innerHTML = '默认显示 ATM ±5 档 · 勾选「展开全部」查看该到期全部行权价'; + hint.innerHTML = strikeWindowHintHtml(cols); tbody.appendChild(hint); } finishStrikeRender(tbody, prevSelected, matchedSelected); diff --git a/lib/options/templates/options_panel.html b/lib/options/templates/options_panel.html index 1841879..eb66f31 100644 --- a/lib/options/templates/options_panel.html +++ b/lib/options/templates/options_panel.html @@ -21,7 +21,7 @@
  • 列表含卖一/买一;T 型仅卖一(买方开仓),中间为跨式双买测算。
  • 环境配置「链上仅显示有卖一」开启时,隐藏无真实卖一或深度不足 1 张的合约(估算价 ~ 亦不显示)。
  • 开仓只认真实卖一价且卖一深度≥1;无深度时面板显示参考标记价并禁用买入。
  • -
  • 链展示近 14 日到期;T 型默认 ATM ±5 档,可展开全部。
  • +
  • 链展示近 14 日到期;列表与 T 型默认平值 + 实值3档 + 虚值3档,勾选「展开全部」看全部行权价。
  • 「按可用余额打满」可用额度 = min(交易户可用 USDC, 单笔预算 {{ '%.2f'|format(options_trade_budget|default(10)|float) }}),再 × 预算缓冲 {{ '%.2f'|format(options_budget_buffer|default(0.95)|float) }} 算张数(env 可改)。
  • 平仓仅买一限价,详见说明文档。
  • @@ -43,7 +43,7 @@ -