diff --git a/lib/common/static/instance_theme.css b/lib/common/static/instance_theme.css
index f193369..63fcd86 100644
--- a/lib/common/static/instance_theme.css
+++ b/lib/common/static/instance_theme.css
@@ -4122,6 +4122,34 @@ html[data-theme="light"] .options-estimate-row {
.options-page-wrap .opt-target-row-hint {
font-size: 0.7rem;
}
+.options-page-wrap .opt-target-armed {
+ font-size: 0.78rem;
+ color: #9ad0ff;
+ font-variant-numeric: tabular-nums;
+}
+.options-page-wrap .opt-target-est {
+ display: inline-flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 10px;
+ font-size: 0.78rem;
+}
+.options-page-wrap .opt-target-est--idle:empty {
+ display: none;
+}
+.options-page-wrap .opt-target-est-item {
+ display: inline-flex;
+ align-items: baseline;
+ gap: 4px;
+}
+.options-page-wrap .opt-target-est-item .k {
+ color: #9aa8c7;
+ font-size: 0.7rem;
+}
+.options-page-wrap .opt-target-est-item .v {
+ font-variant-numeric: tabular-nums;
+ font-weight: 600;
+}
.opt-target-monitors {
margin: 0 0 10px;
padding: 10px 12px;
diff --git a/lib/common/static/options_panel.js b/lib/common/static/options_panel.js
index 1bdfed0..2e38cc0 100644
--- a/lib/common/static/options_panel.js
+++ b/lib/common/static/options_panel.js
@@ -859,23 +859,90 @@
);
}
+ function posEthAmount(p) {
+ if (p.eth_amount != null && Number(p.eth_amount) > 0) return Number(p.eth_amount);
+ const sheets = Number(p.avail_pos != null ? p.avail_pos : p.pos);
+ const ct = Number(p.ct_mult != null ? p.ct_mult : 0.01);
+ if (Number.isFinite(sheets) && sheets > 0 && Number.isFinite(ct) && ct > 0) return sheets * ct;
+ return null;
+ }
+
+ function formatTargetEstimateHtml(optType, strike, targetIdx, ethAmount, premiumPaid) {
+ const value = estimateExpiryValue(optType, strike, targetIdx, ethAmount);
+ const profit = estimateExpiryProfit(optType, strike, targetIdx, ethAmount, premiumPaid);
+ if (value == null && profit == null) return "";
+ let html = '';
+ html += '价值' +
+ (value == null ? "—" : fmtUsdc(value) + " USDC") + "";
+ html += '预估盈利' +
+ (profit == null ? "—" : fmtUsdcSigned(profit)) + "";
+ html += "";
+ return html;
+ }
+
function renderTargetDelegateRow(p) {
const inst = p.inst_id || "";
- const tgt = p.target_index != null && p.target_index !== "" ? String(p.target_index) : "";
- const armed = tgt !== "";
+ const tgt = p.target_index != null && p.target_index !== "" ? Number(p.target_index) : null;
+ const armed = tgt != null && Number.isFinite(tgt) && tgt > 0;
+ const ethAmt = posEthAmount(p);
+ const prem = p.premium_paid;
+ const estHtml = armed
+ ? formatTargetEstimateHtml(p.opt_type, p.strike, tgt, ethAmt, prem)
+ : '';
return (
- '
' +
+ '
' +
'委托' +
- '' +
+ '' +
'' +
'" +
+ (armed
+ ? '目标 ' + fmt(tgt, 1) + ""
+ : "") +
+ estHtml +
'' +
- (armed ? "监控中 · 到位按买一限价平 · 无止损" : "目标=监控指数 · 到位按买一限价平 · 到期即止损") +
+ (armed ? "监控中 · 到位按买一限价平" : "输入后设定 · 到位按买一限价平 · 到期即止损") +
"" +
"
"
);
}
+ function updatePosTargetEstimate(row) {
+ if (!row) return;
+ const est = row.querySelector(".opt-target-est");
+ if (!est) return;
+ const inp = row.querySelector(".opt-pos-target-input");
+ const typed = inp ? String(inp.value || "").trim() : "";
+ const armed = row.getAttribute("data-armed-target") || "";
+ const targetRaw = typed !== "" ? typed : armed;
+ if (targetRaw === "") {
+ est.className = "opt-target-est opt-target-est--idle";
+ est.innerHTML = "";
+ return;
+ }
+ const html = formatTargetEstimateHtml(
+ row.getAttribute("data-opt-type"),
+ row.getAttribute("data-strike"),
+ targetRaw,
+ row.getAttribute("data-eth"),
+ row.getAttribute("data-prem")
+ );
+ if (!html) {
+ est.className = "opt-target-est opt-target-est--idle";
+ est.innerHTML = "";
+ return;
+ }
+ const tmp = document.createElement("div");
+ tmp.innerHTML = html;
+ const node = tmp.firstChild;
+ est.className = "opt-target-est";
+ est.innerHTML = node ? node.innerHTML : "";
+ }
+
function renderPositionCard(p) {
return (
'
' +
@@ -953,6 +1020,9 @@
});
container.querySelectorAll(".opt-pos-target-input").forEach(function (inp) {
inp.addEventListener("click", function (e) { e.stopPropagation(); });
+ inp.addEventListener("input", function () {
+ updatePosTargetEstimate(inp.closest(".opt-target-row"));
+ });
inp.addEventListener("keydown", function (e) {
if (e.key === "Enter") {
e.preventDefault();
@@ -979,6 +1049,7 @@
if (!inst) return;
const card = document.querySelector('.opt-pos-card[data-inst="' + inst + '"]') ||
document.querySelector('.opt-pos-accordion-item[data-inst="' + inst + '"]');
+ const row = card ? card.querySelector(".opt-target-row") : null;
const inp = card ? card.querySelector(".opt-pos-target-input") : null;
const raw = inp ? String(inp.value || "").trim() : "";
const tgt = parseFloat(raw);
@@ -997,6 +1068,11 @@
alert(d.msg || "设定失败");
return;
}
+ if (inp) inp.value = "";
+ if (row) {
+ row.setAttribute("data-armed-target", String(tgt));
+ updatePosTargetEstimate(row);
+ }
await refreshAllPositions();
} finally {
if (btn) btn.disabled = false;
diff --git a/lib/common/static/options_position_cards.js b/lib/common/static/options_position_cards.js
index cf64c96..5c164a9 100644
--- a/lib/common/static/options_position_cards.js
+++ b/lib/common/static/options_position_cards.js
@@ -115,7 +115,33 @@
'
按买盘回收' + fmtClosePreview(closePreview, p.premium_paid, hub) + "
" +
"
" +
(p.target_index != null
- ? '
委托目标指数 ' + fmt(p.target_index, 1) + "监控中 · 到位按买一限价平
"
+ ? (function () {
+ const eth = p.eth_amount != null ? Number(p.eth_amount)
+ : (Number(p.pos) > 0 ? Number(p.pos) * Number(p.ct_mult || 0.01) : null);
+ const strike = Number(p.strike);
+ const tgt = Number(p.target_index);
+ const prem = Number(p.premium_paid);
+ let profit = null;
+ let value = null;
+ if (Number.isFinite(tgt) && Number.isFinite(strike) && eth > 0) {
+ const o = String(p.opt_type || "").toUpperCase();
+ const intrinsic = o === "C" ? Math.max(0, tgt - strike) : o === "P" ? Math.max(0, strike - tgt) : null;
+ if (intrinsic != null) {
+ value = Math.round(intrinsic * eth * 100) / 100;
+ if (Number.isFinite(prem)) profit = Math.round((value - prem) * 100) / 100;
+ }
+ }
+ const profitTxt = profit == null ? "—" : ((profit > 0 ? "+" : "") + fmtUsdc(profit) + " USDC");
+ const profitCls = profit > 0 ? " pnl-pos" : profit < 0 ? " pnl-neg" : "";
+ return (
+ '
' +
+ '委托' +
+ '目标 ' + fmt(p.target_index, 1) + "" +
+ '价值 ' + (value == null ? "—" : fmtUsdc(value) + " USDC") + "" +
+ '预估盈利 ' + profitTxt + "" +
+ '监控中 · 到位按买一限价平
'
+ );
+ })()
: "")
);
}