Limit OO T-quote to 3 Call and 3 Put by default with leverage columns.
Drop the scroll box, add a show-all toggle after refresh, and show K/ask leverage on both sides. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
moneyFilter: "itm", // 永期锁定:实值+平值
|
||||
ooMoneyFilter: "atm_otm", // 期期锁定:平值+虚值
|
||||
ooRecommend: null, // atm_straddle | double_otm | null
|
||||
ooStrikeExpandAll: false, // 默认 Call/Put 各 3 档
|
||||
chain: null,
|
||||
selected: null,
|
||||
legA: null,
|
||||
@@ -267,6 +268,87 @@
|
||||
});
|
||||
}
|
||||
|
||||
function syncOoExpandUI() {
|
||||
const btn = $("hp-oo-expand-all");
|
||||
if (!btn) return;
|
||||
const on = !!state.ooStrikeExpandAll;
|
||||
btn.classList.toggle("active", on);
|
||||
btn.classList.toggle("is-selected", on);
|
||||
btn.setAttribute("aria-pressed", on ? "true" : "false");
|
||||
}
|
||||
|
||||
function calcStrikeAskLeverage(strike, ask) {
|
||||
const k = Number(strike);
|
||||
const a = Number(ask);
|
||||
if (!Number.isFinite(k) || k <= 0 || !Number.isFinite(a) || a <= 0) return "—";
|
||||
return (Math.round((k / a) * 10) / 10).toFixed(1) + "×";
|
||||
}
|
||||
|
||||
function findAtmStrikeFromRows(rows, idx) {
|
||||
if (!rows.length) return null;
|
||||
if (idx == null || Number.isNaN(Number(idx))) return rows[0].strike;
|
||||
let best = rows[0].strike;
|
||||
let bestDist = Math.abs(Number(rows[0].strike) - Number(idx));
|
||||
rows.forEach(function (row) {
|
||||
const d = Math.abs(Number(row.strike) - Number(idx));
|
||||
if (d < bestDist || (d === bestDist && Number(row.strike) < Number(best))) {
|
||||
bestDist = d;
|
||||
best = row.strike;
|
||||
}
|
||||
});
|
||||
return best;
|
||||
}
|
||||
|
||||
function sliceOoTRows(prepared, idx) {
|
||||
// prepared: [{strike, call, put, callOk, putOk}]
|
||||
if (state.ooStrikeExpandAll || !prepared.length) return prepared;
|
||||
const n = 3;
|
||||
const anchor = Number(idx) || Number(findAtmStrikeFromRows(prepared, idx)) || 0;
|
||||
function nearest(list, count) {
|
||||
return list
|
||||
.slice()
|
||||
.sort(function (a, b) {
|
||||
return Math.abs(Number(a.strike) - anchor) - Math.abs(Number(b.strike) - anchor);
|
||||
})
|
||||
.slice(0, count);
|
||||
}
|
||||
const byStrike = {};
|
||||
nearest(
|
||||
prepared.filter(function (r) {
|
||||
return r.callOk;
|
||||
}),
|
||||
n
|
||||
).forEach(function (r) {
|
||||
byStrike[String(r.strike)] = r;
|
||||
});
|
||||
nearest(
|
||||
prepared.filter(function (r) {
|
||||
return r.putOk;
|
||||
}),
|
||||
n
|
||||
).forEach(function (r) {
|
||||
byStrike[String(r.strike)] = r;
|
||||
});
|
||||
// 已选用腿始终保留,避免折叠后看不到选中项
|
||||
[state.legA, state.legB].forEach(function (leg) {
|
||||
if (!leg) return;
|
||||
const hit = prepared.find(function (r) {
|
||||
return (
|
||||
(r.call && r.call.inst_id === leg.inst_id) ||
|
||||
(r.put && r.put.inst_id === leg.inst_id)
|
||||
);
|
||||
});
|
||||
if (hit) byStrike[String(hit.strike)] = hit;
|
||||
});
|
||||
return Object.keys(byStrike)
|
||||
.map(function (k) {
|
||||
return byStrike[k];
|
||||
})
|
||||
.sort(function (a, b) {
|
||||
return Number(a.strike) - Number(b.strike);
|
||||
});
|
||||
}
|
||||
|
||||
function syncTabUI() {
|
||||
let tab = state.tab || pickDefaultTab();
|
||||
if (tab === "perp_options" && !showPerp) tab = pickDefaultTab();
|
||||
@@ -945,27 +1027,48 @@
|
||||
const tbody = $("hp-oo-tbody");
|
||||
if (!tbody) return;
|
||||
const exp = currentExp("hp-oo-exp-select");
|
||||
const cols = 9;
|
||||
tbody.innerHTML = "";
|
||||
if (!exp) {
|
||||
tbody.innerHTML = '<tr><td colspan="7" class="muted">请选择到期日</td></tr>';
|
||||
tbody.innerHTML = '<tr><td colspan="' + cols + '" class="muted">请选择到期日</td></tr>';
|
||||
return;
|
||||
}
|
||||
const rows = buildStraddleRows(exp.contracts);
|
||||
const prepared = [];
|
||||
buildStraddleRows(exp.contracts).forEach(function (row) {
|
||||
const callOk = !!(row.call && matchesOoMoneyFilter(row.call));
|
||||
const putOk = !!(row.put && matchesOoMoneyFilter(row.put));
|
||||
if (!callOk && !putOk) return;
|
||||
prepared.push({
|
||||
strike: row.strike,
|
||||
call: row.call,
|
||||
put: row.put,
|
||||
callOk: callOk,
|
||||
putOk: putOk,
|
||||
});
|
||||
});
|
||||
const rows = sliceOoTRows(prepared, indexPx());
|
||||
const selected = selectedOoLegMap();
|
||||
if (!rows.length) {
|
||||
tbody.innerHTML = '<tr><td colspan="' + cols + '" class="muted">该筛选下暂无平值/虚值合约</td></tr>';
|
||||
return;
|
||||
}
|
||||
rows.forEach(function (row) {
|
||||
const tr = document.createElement("tr");
|
||||
const call = row.call;
|
||||
const put = row.put;
|
||||
const callOk = call && matchesOoMoneyFilter(call);
|
||||
const putOk = put && matchesOoMoneyFilter(put);
|
||||
if (!callOk && !putOk) return;
|
||||
const callOk = row.callOk;
|
||||
const putOk = row.putOk;
|
||||
const callAsk = callOk ? fmtPxSz(call.ask, call.ask_sz, call.ask_estimated, call.tick_sz) : "—";
|
||||
const putAsk = putOk ? fmtPxSz(put.ask, put.ask_sz, put.ask_estimated, put.tick_sz) : "—";
|
||||
const callLev = callOk ? calcStrikeAskLeverage(row.strike, call.ask) : "—";
|
||||
const putLev = putOk ? calcStrikeAskLeverage(row.strike, put.ask) : "—";
|
||||
const callLeg = callOk ? selected[String(call.inst_id)] : "";
|
||||
const putLeg = putOk ? selected[String(put.inst_id)] : "";
|
||||
tr.innerHTML =
|
||||
'<td class="opt-t-call opt-px-sz">' +
|
||||
callAsk +
|
||||
'</td><td class="opt-t-call opt-chain-lev" title="K÷卖一">' +
|
||||
callLev +
|
||||
'</td><td class="opt-t-call">' +
|
||||
(callOk ? moneynessBadge(call) : "—") +
|
||||
"</td><td>" +
|
||||
@@ -986,6 +1089,8 @@
|
||||
(putOk ? moneynessBadge(put) : "—") +
|
||||
'</td><td class="opt-t-put opt-px-sz">' +
|
||||
putAsk +
|
||||
'</td><td class="opt-t-put opt-chain-lev" title="K÷卖一">' +
|
||||
putLev +
|
||||
"</td><td>" +
|
||||
(putOk
|
||||
? '<button type="button" class="btn-secondary hp-oo-pick' +
|
||||
@@ -1001,6 +1106,15 @@
|
||||
"</td>";
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
if (!state.ooStrikeExpandAll && prepared.length > rows.length) {
|
||||
const hint = document.createElement("tr");
|
||||
hint.className = "opt-strike-hint-row";
|
||||
hint.innerHTML =
|
||||
'<td colspan="' +
|
||||
cols +
|
||||
'" class="muted opt-strike-hint">默认显示 Call/Put 各最近 3 档 · 勾选「显示全部」查看更多</td>';
|
||||
tbody.appendChild(hint);
|
||||
}
|
||||
tbody.querySelectorAll(".hp-oo-pick").forEach(function (btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
const inst = btn.getAttribute("data-inst");
|
||||
@@ -1411,6 +1525,13 @@
|
||||
$("hp-oo-load-chain").addEventListener("click", function () {
|
||||
void loadChain();
|
||||
});
|
||||
if ($("hp-oo-expand-all")) {
|
||||
$("hp-oo-expand-all").addEventListener("click", function () {
|
||||
state.ooStrikeExpandAll = !state.ooStrikeExpandAll;
|
||||
syncOoExpandUI();
|
||||
renderTStrikes();
|
||||
});
|
||||
}
|
||||
if ($("hp-exp-select")) $("hp-exp-select").addEventListener("change", renderListStrikes);
|
||||
if ($("hp-oo-exp-select")) $("hp-oo-exp-select").addEventListener("change", renderTStrikes);
|
||||
if ($("hp-sheets")) $("hp-sheets").addEventListener("input", updatePremiumLine);
|
||||
@@ -2076,6 +2197,7 @@
|
||||
syncUnderlyingUI();
|
||||
syncMoneyUI();
|
||||
syncOoRecommendUI();
|
||||
syncOoExpandUI();
|
||||
syncPoDirUI();
|
||||
syncOoSizeModeUI();
|
||||
syncOoCloseModeUI();
|
||||
|
||||
@@ -3645,7 +3645,8 @@ html[data-theme="light"] .opt-be-dist-down {
|
||||
.hedge-plan-page-wrap .hp-uly-btn-oo,
|
||||
.hedge-plan-page-wrap .hp-money-btn,
|
||||
.hedge-plan-page-wrap .hp-oo-money-btn,
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn {
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn,
|
||||
.hedge-plan-page-wrap .hp-oo-expand-btn {
|
||||
min-width: 52px;
|
||||
font-weight: 600;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
@@ -3658,7 +3659,9 @@ html[data-theme="light"] .opt-be-dist-down {
|
||||
.hedge-plan-page-wrap .hp-oo-money-btn.is-selected,
|
||||
.hedge-plan-page-wrap .hp-oo-money-btn.active,
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn.is-selected,
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn.active {
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn.active,
|
||||
.hedge-plan-page-wrap .hp-oo-expand-btn.is-selected,
|
||||
.hedge-plan-page-wrap .hp-oo-expand-btn.active {
|
||||
border-color: var(--accent, #00d4ff);
|
||||
color: var(--text, #fff);
|
||||
background: rgba(0, 212, 255, 0.16);
|
||||
@@ -3666,7 +3669,8 @@ html[data-theme="light"] .opt-be-dist-down {
|
||||
font-weight: 700;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-oo-money-btn .hp-oo-check,
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn .hp-oo-check {
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn .hp-oo-check,
|
||||
.hedge-plan-page-wrap .hp-oo-expand-btn .hp-oo-check {
|
||||
display: none;
|
||||
margin-right: 4px;
|
||||
font-weight: 700;
|
||||
@@ -3674,7 +3678,9 @@ html[data-theme="light"] .opt-be-dist-down {
|
||||
.hedge-plan-page-wrap .hp-oo-money-btn.is-selected .hp-oo-check,
|
||||
.hedge-plan-page-wrap .hp-oo-money-btn.active .hp-oo-check,
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn.is-selected .hp-oo-check,
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn.active .hp-oo-check {
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn.active .hp-oo-check,
|
||||
.hedge-plan-page-wrap .hp-oo-expand-btn.is-selected .hp-oo-check,
|
||||
.hedge-plan-page-wrap .hp-oo-expand-btn.active .hp-oo-check {
|
||||
display: inline;
|
||||
color: var(--accent, #00d4ff);
|
||||
}
|
||||
@@ -3698,20 +3704,33 @@ html[data-theme="light"] .opt-be-dist-down {
|
||||
.hedge-plan-page-wrap .hp-opt-toolbar .btn-secondary,
|
||||
.hedge-plan-page-wrap .hp-opt-toolbar .hp-money-btn,
|
||||
.hedge-plan-page-wrap .hp-oo-money-btn,
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn {
|
||||
.hedge-plan-page-wrap .hp-oo-recommend-btn,
|
||||
.hedge-plan-page-wrap .hp-oo-expand-btn {
|
||||
padding: 3px 8px;
|
||||
min-height: 26px;
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
/* 视口约 5 行数据 + 表头;超出表内滚动 */
|
||||
.hedge-plan-page-wrap .hp-strike-table-wrap--5,
|
||||
.hedge-plan-page-wrap .options-strike-table-wrap--t {
|
||||
/* 永期期权列表:视口约 5 行 + 表头,超出滚动 */
|
||||
.hedge-plan-page-wrap .hp-strike-table-wrap--5 {
|
||||
max-height: 248px;
|
||||
min-height: 248px;
|
||||
overflow-y: auto;
|
||||
margin-top: 4px;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
/* 期期 T 型:默认 3+3 一页展示,无下滑框 */
|
||||
.hedge-plan-page-wrap .hp-oo-table-wrap {
|
||||
max-height: none;
|
||||
min-height: 0;
|
||||
overflow: visible;
|
||||
margin-top: 4px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-oo-table-wrap .opt-chain-lev {
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-opt-bal-line {
|
||||
margin-top: 4px;
|
||||
}
|
||||
@@ -3933,7 +3952,9 @@ html[data-theme="light"] .hedge-plan-page-wrap .hp-money-btn.active,
|
||||
html[data-theme="light"] .hedge-plan-page-wrap .hp-oo-money-btn.is-selected,
|
||||
html[data-theme="light"] .hedge-plan-page-wrap .hp-oo-money-btn.active,
|
||||
html[data-theme="light"] .hedge-plan-page-wrap .hp-oo-recommend-btn.is-selected,
|
||||
html[data-theme="light"] .hedge-plan-page-wrap .hp-oo-recommend-btn.active {
|
||||
html[data-theme="light"] .hedge-plan-page-wrap .hp-oo-recommend-btn.active,
|
||||
html[data-theme="light"] .hedge-plan-page-wrap .hp-oo-expand-btn.is-selected,
|
||||
html[data-theme="light"] .hedge-plan-page-wrap .hp-oo-expand-btn.active {
|
||||
color: #0b1220;
|
||||
background: linear-gradient(180deg, #ffffff 0%, #b9d2ff 100%);
|
||||
border-color: #2f6fed;
|
||||
|
||||
@@ -191,23 +191,24 @@
|
||||
<button type="button" class="btn-secondary hp-oo-recommend-btn" id="hp-oo-recommend-atm" data-oo-rec="atm_straddle" title="最近平值 Call+Put" aria-pressed="false"><span class="hp-oo-check" aria-hidden="true">✓</span>推荐跨式</button>
|
||||
<button type="button" class="btn-secondary hp-oo-recommend-btn" id="hp-oo-recommend-otm" data-oo-rec="double_otm" title="最近虚值 Call+Put" aria-pressed="false"><span class="hp-oo-check" aria-hidden="true">✓</span>推荐双虚</button>
|
||||
<button type="button" class="btn-secondary" id="hp-oo-load-chain">刷新链</button>
|
||||
<button type="button" class="btn-secondary hp-oo-expand-btn" id="hp-oo-expand-all" title="默认只显示 Call/Put 各最近 3 档" aria-pressed="false"><span class="hp-oo-check" aria-hidden="true">✓</span>显示全部</button>
|
||||
</div>
|
||||
<div class="options-strike-table-wrap options-strike-table-wrap--t">
|
||||
<div class="options-strike-table-wrap hp-oo-table-wrap" id="hp-oo-table-wrap">
|
||||
<table class="options-strike-table options-strike-table--t" id="hp-oo-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="3" class="opt-t-head-call">Call</th>
|
||||
<th colspan="4" class="opt-t-head-call">Call</th>
|
||||
<th class="opt-t-head-mid">行权</th>
|
||||
<th colspan="3" class="opt-t-head-put">Put</th>
|
||||
<th colspan="4" class="opt-t-head-put">Put</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>卖一/张</th><th>实虚值</th><th>选用</th>
|
||||
<th>卖一/张</th><th title="行权价÷卖一">杠杆</th><th>实虚值</th><th>选用</th>
|
||||
<th>K</th>
|
||||
<th>实虚值</th><th>卖一/张</th><th>选用</th>
|
||||
<th>实虚值</th><th>卖一/张</th><th title="行权价÷卖一">杠杆</th><th>选用</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="hp-oo-tbody">
|
||||
<tr><td colspan="7" class="muted">请刷新期权链</td></tr>
|
||||
<tr><td colspan="9" class="muted">请刷新期权链</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -327,4 +328,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/hedge_plan.js?v=35"></script>
|
||||
<script src="/static/hedge_plan.js?v=36"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
|
||||
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
|
||||
<link rel="stylesheet" href="/static/instance_page.css?v=13">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=113">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=114">
|
||||
<script src="/static/account_risk_badge.js?v=4"></script>
|
||||
<script src="/static/open_submit_gate.js?v=1"></script>
|
||||
<meta name="theme-color" content="#0b0d14">
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<link rel="manifest" href="/static/icons/manifest.webmanifest">
|
||||
<title>{{ pwa_app_name }}</title>
|
||||
<link rel="stylesheet" href="/static/instance_page.css?v=13">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=113">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=114">
|
||||
|
||||
</head>
|
||||
<body
|
||||
|
||||
Reference in New Issue
Block a user