Polish option close depth display.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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 '<div class="opt-bid-depth">' + bids.map(function (x, idx) {
|
||||
const levelCls = idx === 0 ? " opt-bid-level--best" : "";
|
||||
return (
|
||||
'<span class="opt-bid-level' + levelCls + '">' +
|
||||
'<span class="opt-bid-rank">买' + (idx + 1) + "</span>" +
|
||||
'<span class="opt-bid-price">' + fmt(x.px, 4) + "</span>" +
|
||||
'<span class="opt-bid-size">' + fmt(x.sz, 0) + "张</span>" +
|
||||
"</span>"
|
||||
);
|
||||
}).join("") + "</div>";
|
||||
}
|
||||
|
||||
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 (
|
||||
'<div class="opt-close-preview">' +
|
||||
'<div class="opt-close-main">' + fmt(preview.total_received, 4) + '<span>USDC</span></div>' +
|
||||
'<div class="opt-close-sub">' +
|
||||
'<span class="opt-close-pill opt-close-pill--ok">覆盖 ' + covered + "张</span>" +
|
||||
(missing > 0 ? '<span class="opt-close-pill opt-close-pill--warn">缺 ' + missing + "张</span>" : "") +
|
||||
(pnl != null ? '<span class="opt-close-pnl ' + pnlCls + '">' + (Number(pnl) > 0 ? "+" : "") + fmt(pnl, 4) + "</span>" : "") +
|
||||
"</div></div>"
|
||||
);
|
||||
}
|
||||
|
||||
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 @@
|
||||
'<div class="pos-cell"><span class="pos-label">开仓均价</span><span class="pos-value">' + fmt(p.avg_px, 4) + "</span></div>" +
|
||||
'<div class="pos-cell"><span class="pos-label">标记价</span><span class="pos-value">' + fmt(p.mark_px, 4) + "</span></div>" +
|
||||
'<div class="pos-cell"><span class="pos-label">指数价</span><span class="pos-value">' + fmt(p.idx_px, 0) + "</span></div>" +
|
||||
'<div class="pos-cell"><span class="pos-label">买盘深度</span><span class="pos-value">' + fmtBidDepth(p.bid_depth) + "</span></div>" +
|
||||
'<div class="pos-cell"><span class="pos-label">按买盘收回</span><span class="pos-value ' + closePreviewCls + '">' + fmtClosePreview(closePreview) + "</span></div>" +
|
||||
'<div class="pos-cell opt-pos-cell--depth"><span class="pos-label">买盘深度</span><span class="pos-value">' + fmtBidDepth(p.bid_depth) + "</span></div>" +
|
||||
'<div class="pos-cell opt-pos-cell--close"><span class="pos-label">按买盘收回</span><span class="pos-value ' + closePreviewCls + '">' + fmtClosePreview(closePreview) + "</span></div>" +
|
||||
'<div class="pos-cell"><span class="pos-label">到期平衡</span><span class="pos-value">' + fmt(p.expiry_be_px, 0) + "</span></div>" +
|
||||
'<div class="pos-cell"><span class="pos-label">平掉回本</span><span class="pos-value">' + fmt(p.close_be_px, 0) + "</span></div>" +
|
||||
'<div class="pos-cell"><span class="pos-label">浮盈亏</span><span class="pos-value ' + uplCls + '">' + fmt(p.upl, 2) + "</span></div>" +
|
||||
@@ -611,7 +643,7 @@
|
||||
const msg = [
|
||||
"按最多5档买盘拆分限价卖出?",
|
||||
"合约: " + inst,
|
||||
"预计收回: " + fmtClosePreview(preview),
|
||||
"预计收回: " + fmtClosePreviewText(preview),
|
||||
preview.estimated_pnl != null ? "预估盈亏: " + fmt(preview.estimated_pnl, 4) + " USDC" : "",
|
||||
"",
|
||||
fmtPreviewLevels(preview),
|
||||
|
||||
@@ -90,6 +90,18 @@
|
||||
<div id="opt-pos-live" class="panel-scroll pos-list options-pos-live-pane">
|
||||
<div class="pos-empty" id="opt-pos-empty">暂无持仓</div>
|
||||
<div id="opt-pos-cards"></div>
|
||||
<details class="opt-close-rule">
|
||||
<summary>多档平仓规则说明</summary>
|
||||
<div class="opt-close-rule-body">
|
||||
<p>系统平仓前会重新读取最新买盘,不使用页面缓存。</p>
|
||||
<ul>
|
||||
<li>买一数量足够覆盖持仓时,只按买一价提交一笔限价卖单。</li>
|
||||
<li>买一不够时,先卖买一可覆盖数量;成交后刷新持仓和盘口,再继续用新的最优买盘拆分。</li>
|
||||
<li>最多尝试 5 次,全程使用限价卖出,并带 <code>reduceOnly</code>,不会主动市价平仓。</li>
|
||||
<li>盘口不足或订单未成交时会停止后续拆单,并提示剩余张数。</li>
|
||||
</ul>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-pos-pane" data-opt-pos-pane="stats" role="tabpanel" aria-labelledby="opt-pos-tab-stats" hidden>
|
||||
@@ -200,4 +212,4 @@
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/options_expiry_countdown.js?v=1"></script>
|
||||
<script src="/static/options_panel.js?v=21"></script>
|
||||
<script src="/static/options_panel.js?v=22"></script>
|
||||
|
||||
Reference in New Issue
Block a user