Show hedge-plan scenario preview in a modal with start/cancel.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -35,6 +35,9 @@
|
||||
fundingUsdc: null,
|
||||
tradeBudgetUsdc: null,
|
||||
budgetBuffer: 0.95,
|
||||
previewOk: false,
|
||||
canStart: false,
|
||||
previewPlanType: null,
|
||||
};
|
||||
|
||||
function $(id) {
|
||||
@@ -169,13 +172,24 @@
|
||||
];
|
||||
if (gates.reasons && gates.reasons.length) parts.push(gates.reasons.join("; "));
|
||||
el.textContent = parts.join(" · ");
|
||||
const start = $("hp-start-btn");
|
||||
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;
|
||||
}
|
||||
state.canStart = !!gates.can_start;
|
||||
syncPreviewStartBtn();
|
||||
}
|
||||
|
||||
function syncPreviewStartBtn() {
|
||||
const start = $("hp-preview-start");
|
||||
if (!start) return;
|
||||
start.disabled = !(state.previewOk && state.canStart);
|
||||
}
|
||||
|
||||
function openPreviewModal() {
|
||||
const modal = $("hp-preview-modal");
|
||||
if (modal) modal.hidden = false;
|
||||
}
|
||||
|
||||
function closePreviewModal() {
|
||||
const modal = $("hp-preview-modal");
|
||||
if (modal) modal.hidden = true;
|
||||
}
|
||||
|
||||
function setOptionsBalance(chain) {
|
||||
@@ -851,8 +865,18 @@
|
||||
|
||||
async function runPreview() {
|
||||
const isOo = state.mode === "options_options";
|
||||
const tbody = $(isOo ? "hp-result-tbody-oo" : "hp-result-tbody");
|
||||
const summary = $(isOo ? "hp-summary-oo" : "hp-summary");
|
||||
const tbody = $("hp-result-tbody");
|
||||
const summary = $("hp-preview-summary");
|
||||
const midTh = $("hp-preview-mid-th");
|
||||
const title = $("hp-preview-title");
|
||||
state.previewOk = false;
|
||||
state.previewPlanType = isOo ? "options_options" : "perp_options";
|
||||
syncPreviewStartBtn();
|
||||
if (midTh) midTh.textContent = isOo ? "腿盈亏" : "永续/腿盈亏";
|
||||
if (title) title.textContent = isOo ? "情景测算 · 期期" : "情景测算 · 永期";
|
||||
if (summary) summary.textContent = "";
|
||||
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="muted">计算中…</td></tr>';
|
||||
openPreviewModal();
|
||||
try {
|
||||
let body;
|
||||
if (isOo) {
|
||||
@@ -949,7 +973,11 @@
|
||||
"</td>";
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
state.previewOk = true;
|
||||
syncPreviewStartBtn();
|
||||
} catch (e) {
|
||||
state.previewOk = false;
|
||||
syncPreviewStartBtn();
|
||||
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="err">' + (e.message || e) + "</td></tr>";
|
||||
if (summary) summary.textContent = "";
|
||||
}
|
||||
@@ -1075,14 +1103,19 @@
|
||||
state.mode = "options_options";
|
||||
void runPreview();
|
||||
});
|
||||
if ($("hp-start-btn"))
|
||||
$("hp-start-btn").addEventListener("click", function () {
|
||||
void startPlan("perp_options");
|
||||
if ($("hp-preview-cancel")) $("hp-preview-cancel").addEventListener("click", closePreviewModal);
|
||||
if ($("hp-preview-cancel-x")) $("hp-preview-cancel-x").addEventListener("click", closePreviewModal);
|
||||
if ($("hp-preview-start"))
|
||||
$("hp-preview-start").addEventListener("click", function () {
|
||||
const planType = state.previewPlanType || state.mode;
|
||||
void startPlan(planType, true);
|
||||
});
|
||||
if ($("hp-start-btn-oo"))
|
||||
$("hp-start-btn-oo").addEventListener("click", function () {
|
||||
void startPlan("options_options");
|
||||
const previewModal = $("hp-preview-modal");
|
||||
if (previewModal) {
|
||||
previewModal.addEventListener("click", function (ev) {
|
||||
if (ev.target === previewModal) closePreviewModal();
|
||||
});
|
||||
}
|
||||
if ($("hp-detail-close")) $("hp-detail-close").addEventListener("click", closeModal);
|
||||
const modal = $("hp-detail-modal");
|
||||
if (modal) {
|
||||
@@ -1442,8 +1475,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function startPlan(planType) {
|
||||
async function startPlan(planType, fromPreviewModal) {
|
||||
const isOo = planType === "options_options";
|
||||
const startBtn = $("hp-preview-start");
|
||||
try {
|
||||
let body;
|
||||
if (isOo) {
|
||||
@@ -1487,17 +1521,22 @@
|
||||
margin: state.market && state.market.full_margin_sizing && state.market.full_margin_sizing.margin_capital,
|
||||
};
|
||||
}
|
||||
if (!window.confirm("确认启动对冲计划并真实下单?\n(将按期权账户/合约账户分别下单)")) return;
|
||||
if (!fromPreviewModal) {
|
||||
if (!window.confirm("确认启动对冲计划并真实下单?\n(将按期权账户/合约账户分别下单)")) return;
|
||||
}
|
||||
if (startBtn) startBtn.disabled = true;
|
||||
const d = await apiJson("/api/hedge-plan/start", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
setGateLine(d.gates);
|
||||
closePreviewModal();
|
||||
alert("计划已启动 #" + (d.plan_id || "") + (d.dry_run ? " (dry_run)" : ""));
|
||||
void loadGates();
|
||||
} catch (e) {
|
||||
alert(e.message || String(e));
|
||||
syncPreviewStartBtn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3536,15 +3536,24 @@ html[data-theme="light"] .opt-be-dist-down {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-preview-card {
|
||||
margin-top: 0;
|
||||
clear: both;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-action-row {
|
||||
margin-top: 10px;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-preview-modal {
|
||||
width: min(96vw, 920px);
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-preview-summary {
|
||||
margin: 0 0 10px;
|
||||
font-size: 0.84rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-preview-actions {
|
||||
margin-top: 14px;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
.hedge-plan-page-wrap .hp-pick.active,
|
||||
.hedge-plan-page-wrap .opt-row-selected td {
|
||||
background: rgba(90, 140, 255, 0.18);
|
||||
|
||||
@@ -97,31 +97,9 @@
|
||||
<div id="hp-opt-bal-line" class="muted hp-quote-line hp-opt-bal-line"></div>
|
||||
<div class="form-row hp-action-row">
|
||||
<button type="button" class="primary" id="hp-preview-btn">计算</button>
|
||||
<button type="button" class="btn-secondary" id="hp-start-btn" disabled title="需开启 HEDGE_PLAN_LIVE_ORDER 等门禁">启动计划</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card hp-preview-card" id="hp-preview-card-po">
|
||||
<h2 style="margin:0 0 8px">情景测算</h2>
|
||||
<div id="hp-summary" class="muted" style="margin:8px 0"></div>
|
||||
<div class="options-strike-table-wrap">
|
||||
<table class="options-strike-table" id="hp-result-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>情景</th>
|
||||
<th>现货价</th>
|
||||
<th>永续/腿盈亏</th>
|
||||
<th>期权盈亏</th>
|
||||
<th>合计≈U</th>
|
||||
<th>说明</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="hp-result-tbody">
|
||||
<tr><td colspan="6" class="muted">填写参数后点计算</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="hp-tab-options_options" class="hp-tab-panel hidden" role="tabpanel" hidden>
|
||||
@@ -215,31 +193,9 @@
|
||||
</div>
|
||||
<div class="form-row hp-action-row">
|
||||
<button type="button" class="primary" id="hp-preview-btn-oo">计算</button>
|
||||
<button type="button" class="btn-secondary" id="hp-start-btn-oo" title="需开启 HEDGE_PLAN_LIVE_ORDER">启动计划</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card hp-preview-card">
|
||||
<h2 style="margin:0 0 8px">情景测算</h2>
|
||||
<div id="hp-summary-oo" class="muted" style="margin:8px 0"></div>
|
||||
<div class="options-strike-table-wrap">
|
||||
<table class="options-strike-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>情景</th>
|
||||
<th>现货价</th>
|
||||
<th>腿盈亏</th>
|
||||
<th>期权</th>
|
||||
<th>合计≈U</th>
|
||||
<th>说明</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="hp-result-tbody-oo">
|
||||
<tr><td colspan="6" class="muted">选用两腿并填上破/下破目标后点计算</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="hp-tab-active" class="hp-tab-panel hidden" role="tabpanel" hidden>
|
||||
@@ -297,5 +253,36 @@
|
||||
<div id="hp-detail-body" class="hp-modal-body muted">加载中…</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="hp-preview-modal" class="hp-modal-backdrop" hidden>
|
||||
<div class="hp-modal hp-preview-modal" role="dialog" aria-modal="true" aria-labelledby="hp-preview-title">
|
||||
<div class="hp-modal-head">
|
||||
<h3 id="hp-preview-title">情景测算</h3>
|
||||
<button type="button" class="btn-secondary" id="hp-preview-cancel-x" aria-label="关闭">关闭</button>
|
||||
</div>
|
||||
<div id="hp-preview-summary" class="muted hp-preview-summary"></div>
|
||||
<div class="options-strike-table-wrap">
|
||||
<table class="options-strike-table" id="hp-result-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>情景</th>
|
||||
<th>现货价</th>
|
||||
<th id="hp-preview-mid-th">永续/腿盈亏</th>
|
||||
<th>期权盈亏</th>
|
||||
<th>合计≈U</th>
|
||||
<th>说明</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="hp-result-tbody">
|
||||
<tr><td colspan="6" class="muted">计算中…</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="form-row hp-preview-actions">
|
||||
<button type="button" class="btn-secondary" id="hp-preview-cancel">取消</button>
|
||||
<button type="button" class="primary" id="hp-preview-start" disabled title="需开启 HEDGE_PLAN_LIVE_ORDER 等门禁">启动计划</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/hedge_plan.js?v=19"></script>
|
||||
<script src="/static/hedge_plan.js?v=20"></script>
|
||||
|
||||
Reference in New Issue
Block a user