Park partial hedge plans for manual leg complete instead of auto-close.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1198,6 +1198,51 @@
|
||||
return "上破 " + fmt(p.target_price_up || p.target_price) + " · 下破 " + fmt(p.target_price_down || p.target_price);
|
||||
}
|
||||
|
||||
function activeStatusLabel(p) {
|
||||
if ((p.status || "") === "partial") {
|
||||
return '<span class="hp-plan-partial">半腿待补</span>';
|
||||
}
|
||||
if ((p.status || "") === "opening") {
|
||||
return '<span class="hp-plan-active">开仓中</span>';
|
||||
}
|
||||
return '<span class="hp-plan-active">进行中</span>';
|
||||
}
|
||||
|
||||
function completeLegButtonHtml(p) {
|
||||
if ((p.status || "") !== "partial") return "";
|
||||
const role = p.missing_leg || "";
|
||||
let label = "";
|
||||
if (role === "perp") label = "补开永续";
|
||||
else if (role === "option_b") label = "补开腿B";
|
||||
else if (role === "option_hedge" || role === "option_a") label = "补开期权";
|
||||
else return "";
|
||||
return (
|
||||
'<button type="button" class="primary hp-btn-complete" data-id="' +
|
||||
p.id +
|
||||
'" data-role="' +
|
||||
role +
|
||||
'">' +
|
||||
label +
|
||||
"</button>"
|
||||
);
|
||||
}
|
||||
|
||||
async function completeMissingLeg(planId) {
|
||||
if (!window.confirm("确认补开缺失腿并真实下单?")) return;
|
||||
try {
|
||||
const d = await apiJson("/api/hedge-plan/" + planId + "/complete-leg", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
alert("补开成功 #" + (d.plan_id || planId) + " · 已进入进行中");
|
||||
void loadActivePlans();
|
||||
void loadGates();
|
||||
} catch (e) {
|
||||
alert(e.message || String(e));
|
||||
}
|
||||
}
|
||||
|
||||
async function loadActivePlans() {
|
||||
const tbody = $("hp-active-tbody");
|
||||
if (!tbody) return;
|
||||
@@ -1225,12 +1270,14 @@
|
||||
"\"><code>" +
|
||||
contracts +
|
||||
"</code></td><td>" +
|
||||
'<span class="hp-plan-active">进行中</span>' +
|
||||
activeStatusLabel(p) +
|
||||
"</td><td>" +
|
||||
activeTargetLabel(p) +
|
||||
"</td><td>" +
|
||||
(p.opened_at || "—") +
|
||||
'</td><td class="hp-hist-actions"><button type="button" class="btn-secondary hp-btn-detail" data-id="' +
|
||||
'</td><td class="hp-hist-actions">' +
|
||||
completeLegButtonHtml(p) +
|
||||
'<button type="button" class="btn-secondary hp-btn-detail" data-id="' +
|
||||
p.id +
|
||||
'">成交细节</button></td>';
|
||||
tbody.appendChild(tr);
|
||||
@@ -1240,6 +1287,11 @@
|
||||
void showPlanDetail(Number(btn.getAttribute("data-id")));
|
||||
});
|
||||
});
|
||||
tbody.querySelectorAll(".hp-btn-complete").forEach(function (btn) {
|
||||
btn.addEventListener("click", function () {
|
||||
void completeMissingLeg(Number(btn.getAttribute("data-id")));
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
tbody.innerHTML = '<tr><td colspan="8" class="err">' + (e.message || e) + "</td></tr>";
|
||||
}
|
||||
@@ -1532,7 +1584,18 @@
|
||||
});
|
||||
setGateLine(d.gates);
|
||||
closePreviewModal();
|
||||
alert("计划已启动 #" + (d.plan_id || "") + (d.dry_run ? " (dry_run)" : ""));
|
||||
if (d.partial) {
|
||||
alert(
|
||||
(d.msg || "半腿失败,已挂待补") +
|
||||
(d.plan_id ? "\n计划 #" + d.plan_id : "") +
|
||||
"\n请到「进行中的计划」补开缺失腿"
|
||||
);
|
||||
state.tab = "active";
|
||||
syncTabUI();
|
||||
void loadActivePlans();
|
||||
} else {
|
||||
alert("计划已启动 #" + (d.plan_id || "") + (d.dry_run ? " (dry_run)" : ""));
|
||||
}
|
||||
void loadGates();
|
||||
} catch (e) {
|
||||
alert(e.message || String(e));
|
||||
|
||||
@@ -3249,6 +3249,16 @@ html[data-theme="light"] .opt-be-dist-down {
|
||||
color: #7ee787;
|
||||
font-weight: 700;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-plan-partial {
|
||||
color: #ffb454;
|
||||
font-weight: 700;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-hist-actions .hp-btn-complete {
|
||||
margin-right: 6px;
|
||||
padding: 3px 8px;
|
||||
font-size: 0.72rem;
|
||||
min-height: 26px;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-pnl-neg {
|
||||
color: #ff8a8a;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user