Clear target input after set and show estimated value/profit.
Position委托 row keeps the field empty for new entry and displays target value plus estimated PnL after arming. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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 = '<span class="opt-target-est">';
|
||||
html += '<span class="opt-target-est-item"><span class="k">价值</span><span class="v">' +
|
||||
(value == null ? "—" : fmtUsdc(value) + " USDC") + "</span></span>";
|
||||
html += '<span class="opt-target-est-item"><span class="k">预估盈利</span><span class="v ' + pnlCls(profit) + '">' +
|
||||
(profit == null ? "—" : fmtUsdcSigned(profit)) + "</span></span>";
|
||||
html += "</span>";
|
||||
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)
|
||||
: '<span class="opt-target-est opt-target-est--idle"></span>';
|
||||
return (
|
||||
'<div class="opt-target-row">' +
|
||||
'<div class="opt-target-row" data-inst="' + inst + '"' +
|
||||
' data-opt-type="' + (p.opt_type || "") + '"' +
|
||||
' data-strike="' + (p.strike != null ? p.strike : "") + '"' +
|
||||
' data-eth="' + (ethAmt != null ? ethAmt : "") + '"' +
|
||||
' data-prem="' + (prem != null ? prem : "") + '"' +
|
||||
' data-armed-target="' + (armed ? tgt : "") + '">' +
|
||||
'<span class="opt-target-row-label">委托</span>' +
|
||||
'<input type="number" class="opt-pos-target-input" data-inst="' + inst + '" step="0.1" min="0" placeholder="监控目标指数" value="' + tgt + '">' +
|
||||
'<input type="number" class="opt-pos-target-input" data-inst="' + inst + '" step="0.1" min="0" placeholder="监控目标指数" value="">' +
|
||||
'<button type="button" class="btn-secondary opt-target-set-btn" data-inst="' + inst + '">设定</button>' +
|
||||
'<button type="button" class="btn-secondary opt-target-cancel-btn" data-inst="' + inst + '"' + (armed ? "" : " disabled") + ">取消</button>" +
|
||||
(armed
|
||||
? '<span class="opt-target-armed">目标 ' + fmt(tgt, 1) + "</span>"
|
||||
: "") +
|
||||
estHtml +
|
||||
'<span class="muted opt-target-row-hint">' +
|
||||
(armed ? "监控中 · 到位按买一限价平 · 无止损" : "目标=监控指数 · 到位按买一限价平 · 到期即止损") +
|
||||
(armed ? "监控中 · 到位按买一限价平" : "输入后设定 · 到位按买一限价平 · 到期即止损") +
|
||||
"</span>" +
|
||||
"</div>"
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
'<div class="pos-card opt-pos-card" data-inst="' + (p.inst_id || "") + '">' +
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user