Enable hedge-plan live opens with path validation, DB, and monitor.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-14 13:15:10 +08:00
parent 5fcf649c79
commit 982497d65a
10 changed files with 1474 additions and 45 deletions
+146 -7
View File
@@ -135,7 +135,12 @@
if (gates.reasons && gates.reasons.length) parts.push(gates.reasons.join("; "));
el.textContent = parts.join(" · ");
const start = $("hp-start-btn");
if (start) start.disabled = !gates.can_start;
const startOo = $("hp-start-btn-oo");
if ((gates.plan_type || state.mode) === "options_options") {
if (startOo) startOo.disabled = !gates.can_start;
} else {
if (start) start.disabled = !gates.can_start;
}
}
function setOptionsBalance(chain) {
@@ -702,14 +707,13 @@
syncTabUI();
if (state.tab === "perp_options" || state.tab === "options_options") {
void loadGates();
} else if (state.tab === "history") {
void loadHistory();
} else if (state.tab === "stats") {
void loadStats();
} else {
const el = $("hp-gate-line");
if (el) {
el.textContent =
state.tab === "history"
? "历史记录:独立对冲表,与普通交易记录分离"
: "统计:止盈=盈利−保费;止损=期权盈利−永续亏损";
}
if (el) el.textContent = "";
}
});
});
@@ -768,6 +772,141 @@
state.mode = "options_options";
void runPreview();
});
if ($("hp-start-btn"))
$("hp-start-btn").addEventListener("click", function () {
void startPlan("perp_options");
});
if ($("hp-start-btn-oo"))
$("hp-start-btn-oo").addEventListener("click", function () {
void startPlan("options_options");
});
}
async function loadHistory() {
const tbody = $("hp-history-tbody");
if (!tbody) return;
try {
const d = await apiJson("/api/hedge-plan/history");
const rows = d.plans || [];
if (!rows.length) {
tbody.innerHTML = '<tr><td colspan="8" class="muted">暂无已结束计划</td></tr>';
return;
}
tbody.innerHTML = "";
rows.forEach(function (p) {
const tr = document.createElement("tr");
tr.innerHTML =
"<td>" +
p.id +
"</td><td>" +
(p.plan_type === "perp_options" ? "永期" : "期期") +
"</td><td>" +
(p.underlying || "") +
"</td><td>" +
(p.status || "") +
"</td><td>" +
fmt(p.realized_pnl_total) +
"</td><td>" +
(p.close_reason || "—") +
"</td><td>" +
(p.opened_at || "—") +
"</td><td>" +
(p.closed_at || "—") +
"</td>";
tbody.appendChild(tr);
});
} catch (e) {
tbody.innerHTML = '<tr><td colspan="8" class="err">' + (e.message || e) + "</td></tr>";
}
}
async function loadStats() {
const box = $("hp-stats-box");
if (!box) return;
try {
const d = await apiJson("/api/hedge-plan/stats");
const parts = [
"活跃计划 <strong>" + (d.active || 0) + "</strong>",
"已结笔数 <strong>" + (d.closed_count || 0) + "</strong>",
"已结合计 <strong>" + fmt(d.closed_pnl_total) + "</strong> ≈U",
];
const by = d.by_reason || [];
if (by.length) {
parts.push(
"<br/>按原因: " +
by
.map(function (r) {
return (
(r.plan_type || "") +
"/" +
(r.close_reason || "") +
" ×" +
r.n +
" pnl=" +
fmt(r.pnl)
);
})
.join(" · ")
);
}
box.innerHTML = parts.join(" · ");
} catch (e) {
box.textContent = e.message || String(e);
}
}
async function startPlan(planType) {
const isOo = planType === "options_options";
try {
let body;
if (isOo) {
if (!state.legA || !state.legB) throw new Error("请选用两条期权腿");
const target = Number(($("hp-target") && $("hp-target").value) || 0);
if (!target) throw new Error("请填写目标价");
body = {
plan_type: "options_options",
underlying: state.underlying,
target_price: target,
leg_a: legPayload(state.legA, ooSheets("hp-oo-sheets-a")),
leg_b: legPayload(state.legB, ooSheets("hp-oo-sheets-b")),
};
} else {
if (!state.selected) throw new Error("请选用期权腿");
const entry = Number(($("hp-entry") && $("hp-entry").value) || 0);
const tp = Number(($("hp-tp") && $("hp-tp").value) || 0);
const sl = Number(($("hp-sl") && $("hp-sl").value) || 0);
const contracts = Number(($("hp-contracts") && $("hp-contracts").value) || 0);
const sheets = Number(($("hp-sheets") && $("hp-sheets").value) || 1);
if (!entry || !tp || !sl || !contracts) throw new Error("请完整填写开仓/止盈/止损/张数");
body = {
plan_type: "perp_options",
underlying: state.underlying,
direction: ($("hp-direction") && $("hp-direction").value) || "long",
entry: entry,
tp: tp,
sl: sl,
contracts: contracts,
sheets: sheets,
opt_inst_id: state.selected.inst_id,
opt_type: state.selected.opt_type,
strike: state.selected.strike,
exchange_symbol: (state.market && state.market.exchange_symbol) || "",
leverage: 10,
margin: state.market && state.market.full_margin_sizing && state.market.full_margin_sizing.margin_capital,
};
}
if (!window.confirm("确认启动对冲计划并真实下单?\n(将按期权账户/合约账户分别下单)")) return;
const d = await apiJson("/api/hedge-plan/start", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
setGateLine(d.gates);
alert("计划已启动 #" + (d.plan_id || "") + (d.dry_run ? " (dry_run)" : ""));
void loadGates();
} catch (e) {
alert(e.message || String(e));
}
}
async function refreshAll() {