From e8a55a0f856a75bb94d39cab09371d8754a74918 Mon Sep 17 00:00:00 2001 From: dekun Date: Sat, 11 Jul 2026 08:57:19 +0800 Subject: [PATCH] Polish option close depth display. Co-authored-by: Cursor --- lib/common/static/instance_theme.css | 167 +++++++++++++++++++++++ lib/common/static/options_panel.js | 44 +++++- lib/options/templates/options_panel.html | 14 +- 3 files changed, 218 insertions(+), 7 deletions(-) diff --git a/lib/common/static/instance_theme.css b/lib/common/static/instance_theme.css index 8787d71..fd2d41d 100644 --- a/lib/common/static/instance_theme.css +++ b/lib/common/static/instance_theme.css @@ -3597,6 +3597,173 @@ html[data-theme="light"] .options-estimate-row { .options-page-wrap .opt-pos-card .pos-value { font-size: 0.78rem; } +.options-page-wrap .opt-pos-cell--depth { + grid-column: span 2; +} +.options-page-wrap .opt-bid-depth { + display: flex; + flex-wrap: wrap; + gap: 5px; + align-items: center; +} +.options-page-wrap .opt-bid-level { + display: inline-grid; + grid-template-columns: auto auto auto; + align-items: center; + gap: 4px; + min-height: 24px; + padding: 3px 7px; + border: 1px solid rgba(82, 101, 143, 0.55); + border-radius: 999px; + background: rgba(18, 24, 37, 0.72); + color: #dbe6ff; + line-height: 1; + font-variant-numeric: tabular-nums; +} +.options-page-wrap .opt-bid-level--best { + border-color: rgba(93, 143, 255, 0.9); + background: linear-gradient(135deg, rgba(47, 86, 170, 0.72), rgba(28, 39, 68, 0.84)); + box-shadow: inset 0 0 0 1px rgba(122, 164, 255, 0.1), 0 6px 14px rgba(24, 46, 92, 0.24); +} +.options-page-wrap .opt-bid-rank { + color: #91a4cc; + font-size: 0.64rem; + font-weight: 600; +} +.options-page-wrap .opt-bid-level--best .opt-bid-rank { + color: #c8d8ff; +} +.options-page-wrap .opt-bid-price { + color: #ffffff; + font-weight: 700; +} +.options-page-wrap .opt-bid-size { + color: #93a2bd; + font-size: 0.66rem; +} +.options-page-wrap .opt-close-preview { + display: flex; + flex-direction: column; + gap: 5px; + align-items: flex-start; +} +.options-page-wrap .opt-close-main { + display: inline-flex; + align-items: baseline; + gap: 4px; + color: #ff7b87; + font-size: 0.9rem; + font-weight: 800; + font-variant-numeric: tabular-nums; + line-height: 1.05; +} +.options-page-wrap .opt-close-main span { + color: #9aa8c2; + font-size: 0.62rem; + font-weight: 600; +} +.options-page-wrap .opt-close-sub { + display: flex; + flex-wrap: wrap; + gap: 4px; + align-items: center; +} +.options-page-wrap .opt-close-pill, +.options-page-wrap .opt-close-pnl { + display: inline-flex; + align-items: center; + min-height: 20px; + padding: 2px 6px; + border-radius: 999px; + font-size: 0.64rem; + font-weight: 650; + line-height: 1; + font-variant-numeric: tabular-nums; +} +.options-page-wrap .opt-close-pill--ok { + color: #9fe6c1; + background: rgba(40, 154, 104, 0.16); + border: 1px solid rgba(67, 190, 128, 0.35); +} +.options-page-wrap .opt-close-pill--warn { + color: #ffd0d5; + background: rgba(214, 80, 96, 0.16); + border: 1px solid rgba(233, 104, 118, 0.35); +} +.options-page-wrap .opt-close-pnl { + color: #9aa8c2; + background: rgba(82, 101, 143, 0.18); + border: 1px solid rgba(82, 101, 143, 0.34); +} +.options-page-wrap .opt-close-pnl.is-profit { + color: #8ce9bb; +} +.options-page-wrap .opt-close-pnl.is-loss { + color: #ff97a2; +} +.options-page-wrap .opt-close-rule { + margin-top: 8px; + padding: 0; + border: 1px solid rgba(67, 82, 118, 0.55); + border-radius: 10px; + background: rgba(14, 19, 30, 0.58); + overflow: hidden; +} +.options-page-wrap .opt-close-rule summary { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 8px 10px; + color: #c9d6f2; + font-size: 0.72rem; + font-weight: 650; + cursor: pointer; + user-select: none; + list-style: none; +} +.options-page-wrap .opt-close-rule summary::-webkit-details-marker { + display: none; +} +.options-page-wrap .opt-close-rule summary::after { + content: "展开"; + padding: 2px 7px; + border-radius: 999px; + background: rgba(82, 101, 143, 0.25); + color: #91a4cc; + font-size: 0.62rem; + font-weight: 600; +} +.options-page-wrap .opt-close-rule[open] summary { + border-bottom: 1px solid rgba(67, 82, 118, 0.45); + background: rgba(28, 38, 60, 0.55); +} +.options-page-wrap .opt-close-rule[open] summary::after { + content: "收起"; +} +.options-page-wrap .opt-close-rule-body { + padding: 8px 10px 10px; + color: #96a4bf; + font-size: 0.7rem; + line-height: 1.55; +} +.options-page-wrap .opt-close-rule-body p { + margin: 0 0 6px; + color: #b6c2dc; +} +.options-page-wrap .opt-close-rule-body ul { + margin: 0; + padding-left: 16px; +} +.options-page-wrap .opt-close-rule-body li + li { + margin-top: 3px; +} +.options-page-wrap .opt-close-rule-body code { + color: #dbe6ff; + background: rgba(82, 101, 143, 0.22); + border-radius: 4px; + padding: 1px 4px; +} .options-page-wrap .pos-empty { padding: 10px; font-size: 0.72rem; diff --git a/lib/common/static/options_panel.js b/lib/common/static/options_panel.js index 56aa1a3..196f4ee 100644 --- a/lib/common/static/options_panel.js +++ b/lib/common/static/options_panel.js @@ -188,12 +188,36 @@ function fmtBidDepth(levels) { const bids = (levels || []).slice(0, 5); if (!bids.length) return "—"; - return bids.map(function (x, idx) { - return "买" + (idx + 1) + " " + fmtPxSz(x.px, x.sz); - }).join(" · "); + return '
' + bids.map(function (x, idx) { + const levelCls = idx === 0 ? " opt-bid-level--best" : ""; + return ( + '' + + '买' + (idx + 1) + "" + + '' + fmt(x.px, 4) + "" + + '' + fmt(x.sz, 0) + "张" + + "" + ); + }).join("") + "
"; } function fmtClosePreview(preview) { + if (!preview || preview.total_received == null) return "—"; + const missing = Number(preview.uncovered_sheets || 0); + const covered = Number(preview.covered_sheets || 0); + const pnl = preview.estimated_pnl; + const pnlCls = pnlClsName(pnl); + return ( + '
' + + '
' + fmt(preview.total_received, 4) + 'USDC
' + + '
' + + '覆盖 ' + covered + "张" + + (missing > 0 ? '缺 ' + missing + "张" : "") + + (pnl != null ? '' + (Number(pnl) > 0 ? "+" : "") + fmt(pnl, 4) + "" : "") + + "
" + ); + } + + function fmtClosePreviewText(preview) { if (!preview || preview.total_received == null) return "—"; let text = fmt(preview.total_received, 4) + " USDC"; if (preview.covered_sheets != null) { @@ -221,6 +245,14 @@ return ""; } + function pnlClsName(v) { + if (v === null || v === undefined || Number.isNaN(Number(v))) return ""; + const n = Number(v); + if (n > 0) return "is-profit"; + if (n < 0) return "is-loss"; + return ""; + } + function estimateExpiryProfit(optType, strike, targetIdx, entryPx, ethAmount) { if (strike == null || targetIdx == null || entryPx == null || ethAmount == null) return null; const amt = Number(ethAmount); @@ -506,8 +538,8 @@ '
开仓均价' + fmt(p.avg_px, 4) + "
" + '
标记价' + fmt(p.mark_px, 4) + "
" + '
指数价' + fmt(p.idx_px, 0) + "
" + - '
买盘深度' + fmtBidDepth(p.bid_depth) + "
" + - '
按买盘收回' + fmtClosePreview(closePreview) + "
" + + '
买盘深度' + fmtBidDepth(p.bid_depth) + "
" + + '
按买盘收回' + fmtClosePreview(closePreview) + "
" + '
到期平衡' + fmt(p.expiry_be_px, 0) + "
" + '
平掉回本' + fmt(p.close_be_px, 0) + "
" + '
浮盈亏' + fmt(p.upl, 2) + "
" + @@ -611,7 +643,7 @@ const msg = [ "按最多5档买盘拆分限价卖出?", "合约: " + inst, - "预计收回: " + fmtClosePreview(preview), + "预计收回: " + fmtClosePreviewText(preview), preview.estimated_pnl != null ? "预估盈亏: " + fmt(preview.estimated_pnl, 4) + " USDC" : "", "", fmtPreviewLevels(preview), diff --git a/lib/options/templates/options_panel.html b/lib/options/templates/options_panel.html index d9c311d..987aac3 100644 --- a/lib/options/templates/options_panel.html +++ b/lib/options/templates/options_panel.html @@ -90,6 +90,18 @@
暂无持仓
+
+ 多档平仓规则说明 +
+

系统平仓前会重新读取最新买盘,不使用页面缓存。

+
    +
  • 买一数量足够覆盖持仓时,只按买一价提交一笔限价卖单。
  • +
  • 买一不够时,先卖买一可覆盖数量;成交后刷新持仓和盘口,再继续用新的最优买盘拆分。
  • +
  • 最多尝试 5 次,全程使用限价卖出,并带 reduceOnly,不会主动市价平仓。
  • +
  • 盘口不足或订单未成交时会停止后续拆单,并提示剩余张数。
  • +
+
+
- +