(function () { "use strict"; const root = document.getElementById("options-root"); if (!root) return; if (root.getAttribute("data-options-booted") === "1") return; root.setAttribute("data-options-booted", "1"); const panelCache = (window.__optionsPanelCache = window.__optionsPanelCache || {}); const state = { underlying: root.dataset.defaultUnderly || "ETH", optType: "C", chain: panelCache.chain || null, selectedInst: null, orderQuote: null, expandedPosInst: null, }; function fmt(v, d) { if (v === null || v === undefined || Number.isNaN(Number(v))) return "—"; return Number(v).toFixed(d == null ? 2 : d); } async function apiJson(url, opts) { const r = await fetch(url, Object.assign({ credentials: "same-origin" }, opts || {})); return r.json(); } function orderPanel() { return document.getElementById("opt-order-panel"); } function orderPanelHost() { return document.getElementById("opt-order-panel-host"); } function parkOrderPanel() { const panel = orderPanel(); const host = orderPanelHost(); const inline = document.querySelector(".opt-order-inline-row"); if (inline) inline.remove(); if (panel && host && panel.parentElement !== host) { host.appendChild(panel); host.hidden = true; } if (panel) panel.style.display = "none"; document.querySelectorAll(".opt-strike-row").forEach(function (r) { r.classList.remove("opt-row-selected"); }); document.querySelectorAll(".opt-pick-btn").forEach(function (b) { b.classList.remove("active"); b.disabled = false; if (b.dataset.origText) b.textContent = b.dataset.origText; }); } function placeOrderPanelAfter(instId) { const panel = orderPanel(); if (!panel || !instId) return; const row = document.querySelector('#opt-strike-tbody tr.opt-strike-row[data-inst="' + CSS.escape(instId) + '"]'); if (!row) return; document.querySelectorAll(".opt-strike-row").forEach(function (r) { r.classList.toggle("opt-row-selected", r === row); }); document.querySelectorAll(".opt-pick-btn").forEach(function (btn) { const on = btn.getAttribute("data-inst") === instId; btn.classList.toggle("active", on); if (!btn.dataset.origText) btn.dataset.origText = btn.textContent; if (on) btn.textContent = "已选"; }); const oldInline = document.querySelector(".opt-order-inline-row"); if (oldInline) oldInline.remove(); const tr = document.createElement("tr"); tr.className = "opt-order-inline-row"; const td = document.createElement("td"); td.colSpan = 8; td.appendChild(panel); tr.appendChild(td); row.after(tr); panel.style.display = ""; orderPanelHost().hidden = true; tr.scrollIntoView({ behavior: "smooth", block: "nearest" }); } function currentSizeMode() { const el = document.querySelector('input[name="opt-size-mode"]:checked'); return el ? el.value : "sheets"; } function updateSizeInputs() { const mode = currentSizeMode(); const sheetsEl = document.getElementById("opt-sheets-amount"); const ethEl = document.getElementById("opt-eth-amount"); if (sheetsEl) sheetsEl.style.display = mode === "sheets" ? "" : "none"; if (ethEl) ethEl.style.display = mode === "eth_amount" ? "" : "none"; } function quoteUrl(instId) { const mode = currentSizeMode(); let url = "/api/options/quote?inst_id=" + encodeURIComponent(instId) + "&mode=" + mode; if (mode === "eth_amount") { const eth = document.getElementById("opt-eth-amount").value; if (eth) url += "ð_amount=" + encodeURIComponent(eth); } else if (mode === "sheets") { const sheets = document.getElementById("opt-sheets-amount").value; if (sheets) url += "&sheets=" + encodeURIComponent(sheets); } return url; } function moneynessBadge(c) { const m = (c && c.moneyness) || ""; const label = (c && c.moneyness_label) || "—"; return '' + label + ""; } function optTypeLabel(t) { return (t || "").toUpperCase() === "P" ? "看跌 Put" : "看涨 Call"; } function expLabel(ms) { try { const dt = new Date(Number(ms)); const now = Date.now(); const dte = Math.max(0, Math.ceil((Number(ms) - now) / 86400000)); const base = dt.toLocaleString("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" }); return base + " · " + dte + "D"; } catch (e) { return String(ms); } } function renderExpiries() { const sel = document.getElementById("opt-exp-select"); sel.innerHTML = ''; const exps = (state.chain && state.chain.expiries) || []; exps.forEach(function (e) { const o = document.createElement("option"); o.value = String(e.exp_time); o.textContent = expLabel(e.exp_time) + " (" + e.contracts.length + ")"; sel.appendChild(o); }); const idx = state.chain && state.chain.index_px; const dte = state.chain && state.chain.chain_max_dte_days; if (dte != null) { const el = document.getElementById("opt-chain-dte"); if (el) el.textContent = String(Math.round(dte)); } document.getElementById("opt-index-line").textContent = "指数 " + state.underlying + " ≈ " + fmt(idx, 2) + " · 实值=价内 · 虚值=价外"; } function fmtPxSz(px, sz, estimated) { if (px === null || px === undefined || Number.isNaN(Number(px))) return "—"; let price = Number(px).toFixed(4).replace(/\.?0+$/, ""); if (estimated) price += "~"; 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 pnlCls(v) { if (v === null || v === undefined || Number.isNaN(Number(v))) return ""; const n = Number(v); if (n > 0) return "pos-pnl-profit"; if (n < 0) return "pos-pnl-loss"; return ""; } function estimateExpiryProfit(optType, strike, targetIdx, entryPx, ethAmount) { if (strike == null || targetIdx == null || entryPx == null || ethAmount == null) return null; const amt = Number(ethAmount); const entry = Number(entryPx); const tgt = Number(targetIdx); const k = Number(strike); if (!Number.isFinite(amt) || !Number.isFinite(entry) || !Number.isFinite(tgt) || !Number.isFinite(k) || amt <= 0) { return null; } const o = (optType || "").toUpperCase(); let intrinsic = 0; if (o === "C") intrinsic = Math.max(0, tgt - k); else if (o === "P") intrinsic = Math.max(0, k - tgt); else return null; return Math.round((intrinsic - entry) * amt * 10000) / 10000; } function calcContractLeverage(indexPx, ethAmount, totalPremium) { if (indexPx == null || ethAmount == null || totalPremium == null) return null; const idx = Number(indexPx); const amt = Number(ethAmount); const prem = Number(totalPremium); if (!Number.isFinite(idx) || !Number.isFinite(amt) || !Number.isFinite(prem) || amt <= 0 || prem <= 0) { return null; } return Math.round((idx * amt) / prem * 10) / 10; } function fmtLeverage(v) { if (v === null || v === undefined || Number.isNaN(Number(v))) return "—"; return "约 " + Number(v).toFixed(1) + "×"; } function updateOrderEstimates() { const levEl = document.getElementById("opt-order-leverage"); const profitEl = document.getElementById("opt-est-profit"); const targetLevEl = document.getElementById("opt-est-leverage"); const targetEl = document.getElementById("opt-target-idx"); const q = state.orderQuote; if (!q || !q.ok) { if (levEl) levEl.textContent = "—"; if (profitEl) { profitEl.textContent = "—"; profitEl.className = "v"; } if (targetLevEl) targetLevEl.textContent = "—"; return; } const sz = q.sizing || {}; const ethAmount = sz.eth_amount; const premium = sz.total_premium; const lev = calcContractLeverage(q.index_px, ethAmount, premium); if (levEl) levEl.textContent = fmtLeverage(lev); if (profitEl && targetEl) { const targetRaw = targetEl.value; if (targetRaw === "" || targetRaw == null) { profitEl.textContent = "—"; profitEl.className = "v"; if (targetLevEl) targetLevEl.textContent = "—"; } else { const profit = estimateExpiryProfit(q.opt_type, q.strike, Number(targetRaw), q.ask, ethAmount); if (profit == null || Number.isNaN(profit)) { profitEl.textContent = "—"; profitEl.className = "v"; } else { const sign = profit > 0 ? "+" : ""; profitEl.textContent = sign + profit.toFixed(4) + " USDC"; profitEl.className = "v " + pnlCls(profit); } const targetLev = calcContractLeverage(Number(targetRaw), ethAmount, premium); if (targetLevEl) targetLevEl.textContent = fmtLeverage(targetLev); } } } function updateEstimatedProfit() { updateOrderEstimates(); } 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; const prevSelected = state.selectedInst; parkOrderPanel(); tbody.innerHTML = ""; if (!expMs || !state.chain) { tbody.innerHTML = '请选择到期日'; state.selectedInst = null; return; } const exp = (state.chain.expiries || []).find(function (e) { return String(e.exp_time) === String(expMs); }); if (!exp) return; const list = (exp.contracts || []).filter(function (c) { return c.opt_type === state.optType; }); if (!list.length) { tbody.innerHTML = '该到期日暂无报价'; state.selectedInst = null; return; } let stillVisible = false; 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); tr.innerHTML = "" + c.strike + "" + "" + moneynessBadge(c) + "" + "" + c.inst_id + "" + "" + fmtPxSz(c.ask, c.ask_sz, c.ask_estimated) + "" + "" + fmtPxSz(c.bid, c.bid_sz) + "" + "" + (c.expiry_be_px != null ? fmt(c.expiry_be_px, 0) : "—") + "" + '' + fmtDist(c.dist_expiry_be) + "" + '' + '' + ""; tbody.appendChild(tr); if (c.inst_id === prevSelected) stillVisible = true; }); tbody.querySelectorAll(".opt-pick-btn").forEach(function (btn) { btn.addEventListener("click", function () { selectContract(btn.getAttribute("data-inst"), btn); }); }); if (stillVisible && prevSelected) { selectContract(prevSelected, null, true); } else { state.selectedInst = null; } } function fillOrderPanel(d) { state.orderQuote = d && d.ok ? d : null; const sz = d.sizing || {}; document.getElementById("opt-order-inst").textContent = d.inst_id || state.selectedInst || ""; 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" : "—"; 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 || "报价失败"; msgEl.classList.add("opt-error"); } else if (sz.ok === false) { msgEl.textContent = sz.msg || ""; msgEl.classList.add("opt-error"); } else { msgEl.textContent = ""; msgEl.classList.remove("opt-error"); } updateEstimatedProfit(); } async function selectContract(instId, pickBtn, silent) { state.selectedInst = instId; placeOrderPanelAfter(instId); if (pickBtn) { pickBtn.disabled = true; if (!pickBtn.dataset.origText) pickBtn.dataset.origText = "选择"; pickBtn.textContent = "加载…"; } try { const d = await apiJson(quoteUrl(instId)); fillOrderPanel(d); return d; } finally { if (pickBtn) { pickBtn.disabled = false; pickBtn.textContent = "已选"; pickBtn.classList.add("active"); } if (!silent) placeOrderPanelAfter(instId); } } async function loadChain() { const d = await apiJson("/api/options/chain?underlying=" + encodeURIComponent(state.underlying)); if (!d.ok) { alert(d.msg || "加载失败"); return; } state.chain = d; panelCache.chain = d; panelCache.underlying = state.underlying; panelCache.optType = state.optType; state.selectedInst = null; parkOrderPanel(); renderExpiries(); renderStrikes(); } async function openPosition() { if (!state.selectedInst) { alert("请先选择合约"); return; } const btn = document.getElementById("opt-open-btn"); btn.disabled = true; try { const mode = currentSizeMode(); const body = { inst_id: state.selectedInst, mode: mode, signal_note: document.getElementById("opt-signal-note").value || "", }; if (mode === "eth_amount") { body.eth_amount = parseFloat(document.getElementById("opt-eth-amount").value); } else if (mode === "sheets") { body.sheets = parseInt(document.getElementById("opt-sheets-amount").value, 10); } const d = await apiJson("/api/options/open", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); const msgEl = document.getElementById("opt-order-msg"); msgEl.textContent = d.ok ? "下单已提交,可在 OKX 委托中查看" : (d.msg || "失败"); msgEl.classList.toggle("opt-error", !d.ok); if (d.ok) { refreshAllPositions(); if (typeof refreshAccountSnapshot === "function") refreshAccountSnapshot(); } else { alert(d.msg || "下单失败"); } } finally { btn.disabled = false; } } function renderPositionCardInner(p) { const upl = p.upl; const uplCls = upl > 0 ? "pos-pnl-profit" : upl < 0 ? "pos-pnl-loss" : ""; const sideCls = (p.opt_type || "").toUpperCase() === "P" ? "pos-side-short" : "pos-side-long"; const expMs = p.exp_time_ms != null ? p.exp_time_ms : p.exp_time; const expAttr = expMs != null && expMs !== "" ? String(expMs) : ""; return ( '
' + '
' + (p.inst_id || "") + '' + '' + optTypeLabel(p.opt_type) + "
" + '
' + '' + "
" + '
' + '行权价: ' + fmt(p.strike, 0) + "" + '张数: ' + fmt(p.pos, 0) + " · 币量 " + fmt(p.eth_amount, 4) + "" + (expAttr ? '到期倒计时: ' : "") + "
" + '
' + '
权利金' + fmt(p.premium_paid, 4) + " USDC
" + '
开仓均价' + fmt(p.avg_px, 4) + "
" + '
标记价' + fmt(p.mark_px, 4) + "
" + '
指数价' + fmt(p.idx_px, 0) + "
" + '
到期平衡' + fmt(p.expiry_be_px, 0) + "
" + '
平掉回本' + fmt(p.close_be_px, 0) + "
" + '
浮盈亏' + fmt(p.upl, 2) + "
" + '
收益率' + (p.upl_ratio_pct != null ? fmt(p.upl_ratio_pct, 2) + "%" : "—") + "
" + "
" ); } function renderPositionCard(p) { return ( '
' + renderPositionCardInner(p) + "
" ); } function renderPositionAccordionItem(p, expanded) { const upl = p.upl; const uplCls = upl > 0 ? "pos-pnl-profit" : upl < 0 ? "pos-pnl-loss" : ""; const sideCls = (p.opt_type || "").toUpperCase() === "P" ? "pos-side-short" : "pos-side-long"; const expMs = p.exp_time_ms != null ? p.exp_time_ms : p.exp_time; const expAttr = expMs != null && expMs !== "" ? String(expMs) : ""; const inst = p.inst_id || ""; return ( '
' + '" + '
' + '
' + renderPositionCardInner(p) + "
" ); } function applyAccordionState() { const wrap = document.getElementById("opt-pos-cards"); if (!wrap) return; wrap.querySelectorAll(".opt-pos-accordion-item").forEach(function (el) { const open = el.getAttribute("data-inst") === state.expandedPosInst; el.classList.toggle("is-expanded", open); const btn = el.querySelector(".opt-pos-bar"); const body = el.querySelector(".opt-pos-accordion-body"); if (btn) btn.setAttribute("aria-expanded", open ? "true" : "false"); if (body) body.hidden = !open; }); } function bindPositionActions(container) { if (!container) return; container.querySelectorAll(".opt-close-btn").forEach(function (btn) { btn.addEventListener("click", function (e) { e.stopPropagation(); closePosition(btn.getAttribute("data-inst"), btn); }); }); container.querySelectorAll(".opt-pos-bar").forEach(function (bar) { bar.addEventListener("click", function () { const item = bar.closest(".opt-pos-accordion-item"); if (!item) return; const inst = item.getAttribute("data-inst"); state.expandedPosInst = state.expandedPosInst === inst ? null : inst; applyAccordionState(); if (window.OptionsExpiryCountdown && OptionsExpiryCountdown.ensureTimer) { OptionsExpiryCountdown.ensureTimer(); } }); }); } async function closePosition(inst, btn) { const q = await apiJson("/api/options/quote?inst_id=" + encodeURIComponent(inst) + "&mode=sheets&sheets=1"); if (!q.ok) { alert(q.msg || "获取买一价失败"); return; } const bid = q.bid; if (bid == null || bid <= 0) { alert("暂无买一价,请稍后在 OKX App 平仓或等盘口恢复"); return; } if (!confirm("限价卖出 @ 买一 " + fmt(bid, 4) + "(每 1 ETH/BTC)?\n合约:" + inst)) return; if (btn) btn.disabled = true; try { const r = await apiJson("/api/options/close", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ inst_id: inst }), }); if (r.ok) { alert("平仓单已提交" + (r.bid != null ? " @ " + fmt(r.bid, 4) : "")); } else { alert(r.msg || "平仓失败"); } refreshAllPositions(); if (typeof refreshAccountSnapshot === "function") refreshAccountSnapshot(); } finally { if (btn) btn.disabled = false; } } async function refreshPositions() { const d = await apiJson("/api/options/positions"); const wrap = document.getElementById("opt-pos-cards"); const empty = document.getElementById("opt-pos-empty"); const livePane = document.getElementById("opt-pos-live"); const list = (d.ok && d.positions) || []; wrap.innerHTML = ""; if (!list.length) { empty.style.display = ""; state.expandedPosInst = null; if (livePane) livePane.classList.remove("options-pos-live-pane--accordion"); return; } empty.style.display = "none"; const multi = list.length >= 2; wrap.classList.toggle("opt-pos-cards--accordion", multi); if (livePane) livePane.classList.toggle("options-pos-live-pane--accordion", multi); if (multi) { const ids = list.map(function (p) { return p.inst_id; }); if (state.expandedPosInst && ids.indexOf(state.expandedPosInst) < 0) { state.expandedPosInst = null; } list.forEach(function (p) { const div = document.createElement("div"); div.innerHTML = renderPositionAccordionItem(p, p.inst_id === state.expandedPosInst); wrap.appendChild(div.firstChild); }); } else { state.expandedPosInst = null; list.forEach(function (p) { const div = document.createElement("div"); div.innerHTML = renderPositionCard(p); wrap.appendChild(div.firstChild); }); } bindPositionActions(wrap); if (window.OptionsExpiryCountdown && OptionsExpiryCountdown.ensureTimer) { OptionsExpiryCountdown.ensureTimer(); } } async function refreshStats() { const d = await apiJson("/api/options/stats"); const winEl = document.getElementById("opt-stats-winrate"); const plrEl = document.getElementById("opt-stats-plr"); const closedEl = document.getElementById("opt-stats-closed"); const profitEl = document.getElementById("opt-stats-profit"); const lossEl = document.getElementById("opt-stats-loss"); if (!d.ok) { [winEl, plrEl, closedEl, profitEl, lossEl].forEach(function (el) { if (el) el.textContent = "—"; }); return; } if (winEl) winEl.textContent = d.total_closed ? d.win_rate + "%" : "0%"; if (plrEl) { plrEl.textContent = d.profit_loss_ratio != null ? String(d.profit_loss_ratio) : "—"; } if (closedEl) closedEl.textContent = String(d.total_closed || 0); if (profitEl) { profitEl.textContent = d.total_profit != null && d.total_profit > 0 ? fmt(d.total_profit, 2) + " USDC" : (d.total_closed ? "0 USDC" : "—"); } if (lossEl) { lossEl.textContent = d.total_loss != null && d.total_loss > 0 ? fmt(d.total_loss, 2) + " USDC" : (d.total_closed ? "0 USDC" : "—"); } } async function deleteHistoryRow(id, status) { const warn = status === "open" ? "该记录仍为持仓中,仅删除本地记录,不影响交易所持仓.确认删除?" : "确认删除该条期权历史记录?"; if (!confirm(warn)) return; const r = await apiJson("/api/options/history/" + encodeURIComponent(id), { method: "DELETE" }); if (!r.ok) { alert(r.msg || "删除失败"); return; } refreshAllPositions(); } function optHistoryStatus(h) { if (h.status !== "closed") return "持仓中"; if ((h.signal_note || "").indexOf("到期结算") >= 0) return "到期"; if (h.premium_received === 0 && h.realized_pnl != null && h.realized_pnl < 0 && !h.close_ord_id) { return "到期"; } return "已平"; } function optHistoryStatusHtml(h) { const s = optHistoryStatus(h); let cls = "opt-hist-status"; if (s === "已平") cls += " opt-hist-status--closed"; else if (s === "到期") cls += " opt-hist-status--expired"; else cls += " opt-hist-status--open"; return '' + s + ""; } async function refreshHistory() { const d = await apiJson("/api/options/history"); const tbody = document.getElementById("opt-history-tbody"); tbody.innerHTML = ""; const list = (d.ok && d.history) || []; if (!list.length) { tbody.innerHTML = '暂无历史记录'; return; } list.forEach(function (h) { const tr = document.createElement("tr"); const prem = h.status === "closed" ? h.premium_received : h.premium_paid; const premTxt = prem != null ? fmt(prem, 2) : "—"; const pnl = h.realized_pnl; const pnlTxt = pnl != null ? fmt(pnl, 2) : "—"; const pnlCls = pnl > 0 ? "pos-pnl-profit" : pnl < 0 ? "pos-pnl-loss" : ""; const timeTxt = (h.closed_at || h.created_at || "—").replace("T", " ").slice(0, 19); tr.innerHTML = '' + (h.inst_id || "") + "" + "" + fmt(h.sheets, 0) + "" + "" + premTxt + "" + "" + optHistoryStatusHtml(h) + "" + '' + pnlTxt + "" + "" + timeTxt + "" + ''; tbody.appendChild(tr); }); tbody.querySelectorAll(".opt-history-del").forEach(function (btn) { btn.addEventListener("click", function () { deleteHistoryRow(btn.getAttribute("data-id"), btn.getAttribute("data-status")); }); }); } function refreshAllPositions() { refreshPositions(); refreshStats(); refreshHistory(); } function bootOptionsPanel() { updateSizeInputs(); const hasCache = panelCache.chain && panelCache.underlying === state.underlying && panelCache.optType === state.optType; if (hasCache) { state.chain = panelCache.chain; renderExpiries(); renderStrikes(); refreshAllPositions(); return; } requestAnimationFrame(function () { loadChain(); refreshAllPositions(); }); } document.querySelectorAll(".opt-uly-btn").forEach(function (btn) { btn.addEventListener("click", function () { document.querySelectorAll(".opt-uly-btn").forEach(function (b) { b.classList.remove("active"); }); btn.classList.add("active"); state.underlying = btn.getAttribute("data-uly"); loadChain(); }); }); document.querySelectorAll(".opt-type-btn").forEach(function (btn) { btn.addEventListener("click", function () { document.querySelectorAll(".opt-type-btn").forEach(function (b) { b.classList.remove("active"); }); btn.classList.add("active"); state.optType = btn.getAttribute("data-type"); renderStrikes(); }); }); document.getElementById("opt-exp-select").addEventListener("change", renderStrikes); document.getElementById("opt-load-chain").addEventListener("click", loadChain); document.getElementById("opt-refresh-positions").addEventListener("click", refreshAllPositions); document.getElementById("opt-open-btn").addEventListener("click", openPosition); document.querySelectorAll('input[name="opt-size-mode"]').forEach(function (r) { r.addEventListener("change", function () { updateSizeInputs(); if (state.selectedInst) selectContract(state.selectedInst, null, true); }); }); ["opt-sheets-amount", "opt-eth-amount", "opt-target-idx"].forEach(function (id) { const el = document.getElementById(id); if (!el) return; el.addEventListener("change", function () { if (id === "opt-target-idx") { updateEstimatedProfit(); return; } if (state.selectedInst) selectContract(state.selectedInst, null, true); }); if (id === "opt-target-idx") { el.addEventListener("input", updateEstimatedProfit); } }); bootOptionsPanel(); window.OptionsPanelLive = { refreshSoft: function () { refreshAllPositions(); }, refreshChain: loadChain, }; })();