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,
|
fundingUsdc: null,
|
||||||
tradeBudgetUsdc: null,
|
tradeBudgetUsdc: null,
|
||||||
budgetBuffer: 0.95,
|
budgetBuffer: 0.95,
|
||||||
|
previewOk: false,
|
||||||
|
canStart: false,
|
||||||
|
previewPlanType: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
function $(id) {
|
function $(id) {
|
||||||
@@ -169,13 +172,24 @@
|
|||||||
];
|
];
|
||||||
if (gates.reasons && gates.reasons.length) parts.push(gates.reasons.join("; "));
|
if (gates.reasons && gates.reasons.length) parts.push(gates.reasons.join("; "));
|
||||||
el.textContent = parts.join(" · ");
|
el.textContent = parts.join(" · ");
|
||||||
const start = $("hp-start-btn");
|
state.canStart = !!gates.can_start;
|
||||||
const startOo = $("hp-start-btn-oo");
|
syncPreviewStartBtn();
|
||||||
if ((gates.plan_type || state.mode) === "options_options") {
|
|
||||||
if (startOo) startOo.disabled = !gates.can_start;
|
|
||||||
} else {
|
|
||||||
if (start) start.disabled = !gates.can_start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
function setOptionsBalance(chain) {
|
||||||
@@ -851,8 +865,18 @@
|
|||||||
|
|
||||||
async function runPreview() {
|
async function runPreview() {
|
||||||
const isOo = state.mode === "options_options";
|
const isOo = state.mode === "options_options";
|
||||||
const tbody = $(isOo ? "hp-result-tbody-oo" : "hp-result-tbody");
|
const tbody = $("hp-result-tbody");
|
||||||
const summary = $(isOo ? "hp-summary-oo" : "hp-summary");
|
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 {
|
try {
|
||||||
let body;
|
let body;
|
||||||
if (isOo) {
|
if (isOo) {
|
||||||
@@ -949,7 +973,11 @@
|
|||||||
"</td>";
|
"</td>";
|
||||||
tbody.appendChild(tr);
|
tbody.appendChild(tr);
|
||||||
});
|
});
|
||||||
|
state.previewOk = true;
|
||||||
|
syncPreviewStartBtn();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
state.previewOk = false;
|
||||||
|
syncPreviewStartBtn();
|
||||||
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="err">' + (e.message || e) + "</td></tr>";
|
if (tbody) tbody.innerHTML = '<tr><td colspan="6" class="err">' + (e.message || e) + "</td></tr>";
|
||||||
if (summary) summary.textContent = "";
|
if (summary) summary.textContent = "";
|
||||||
}
|
}
|
||||||
@@ -1075,14 +1103,19 @@
|
|||||||
state.mode = "options_options";
|
state.mode = "options_options";
|
||||||
void runPreview();
|
void runPreview();
|
||||||
});
|
});
|
||||||
if ($("hp-start-btn"))
|
if ($("hp-preview-cancel")) $("hp-preview-cancel").addEventListener("click", closePreviewModal);
|
||||||
$("hp-start-btn").addEventListener("click", function () {
|
if ($("hp-preview-cancel-x")) $("hp-preview-cancel-x").addEventListener("click", closePreviewModal);
|
||||||
void startPlan("perp_options");
|
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"))
|
const previewModal = $("hp-preview-modal");
|
||||||
$("hp-start-btn-oo").addEventListener("click", function () {
|
if (previewModal) {
|
||||||
void startPlan("options_options");
|
previewModal.addEventListener("click", function (ev) {
|
||||||
|
if (ev.target === previewModal) closePreviewModal();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
if ($("hp-detail-close")) $("hp-detail-close").addEventListener("click", closeModal);
|
if ($("hp-detail-close")) $("hp-detail-close").addEventListener("click", closeModal);
|
||||||
const modal = $("hp-detail-modal");
|
const modal = $("hp-detail-modal");
|
||||||
if (modal) {
|
if (modal) {
|
||||||
@@ -1442,8 +1475,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startPlan(planType) {
|
async function startPlan(planType, fromPreviewModal) {
|
||||||
const isOo = planType === "options_options";
|
const isOo = planType === "options_options";
|
||||||
|
const startBtn = $("hp-preview-start");
|
||||||
try {
|
try {
|
||||||
let body;
|
let body;
|
||||||
if (isOo) {
|
if (isOo) {
|
||||||
@@ -1487,17 +1521,22 @@
|
|||||||
margin: state.market && state.market.full_margin_sizing && state.market.full_margin_sizing.margin_capital,
|
margin: state.market && state.market.full_margin_sizing && state.market.full_margin_sizing.margin_capital,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (!fromPreviewModal) {
|
||||||
if (!window.confirm("确认启动对冲计划并真实下单?\n(将按期权账户/合约账户分别下单)")) return;
|
if (!window.confirm("确认启动对冲计划并真实下单?\n(将按期权账户/合约账户分别下单)")) return;
|
||||||
|
}
|
||||||
|
if (startBtn) startBtn.disabled = true;
|
||||||
const d = await apiJson("/api/hedge-plan/start", {
|
const d = await apiJson("/api/hedge-plan/start", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
});
|
});
|
||||||
setGateLine(d.gates);
|
setGateLine(d.gates);
|
||||||
|
closePreviewModal();
|
||||||
alert("计划已启动 #" + (d.plan_id || "") + (d.dry_run ? " (dry_run)" : ""));
|
alert("计划已启动 #" + (d.plan_id || "") + (d.dry_run ? " (dry_run)" : ""));
|
||||||
void loadGates();
|
void loadGates();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert(e.message || String(e));
|
alert(e.message || String(e));
|
||||||
|
syncPreviewStartBtn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3536,15 +3536,24 @@ html[data-theme="light"] .opt-be-dist-down {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.hedge-plan-page-wrap .hp-preview-card {
|
|
||||||
margin-top: 0;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
.hedge-plan-page-wrap .hp-action-row {
|
.hedge-plan-page-wrap .hp-action-row {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
justify-content: flex-end;
|
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 .hp-pick.active,
|
||||||
.hedge-plan-page-wrap .opt-row-selected td {
|
.hedge-plan-page-wrap .opt-row-selected td {
|
||||||
background: rgba(90, 140, 255, 0.18);
|
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 id="hp-opt-bal-line" class="muted hp-quote-line hp-opt-bal-line"></div>
|
||||||
<div class="form-row hp-action-row">
|
<div class="form-row hp-action-row">
|
||||||
<button type="button" class="primary" id="hp-preview-btn">计算</button>
|
<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>
|
||||||
</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>
|
||||||
|
|
||||||
<div id="hp-tab-options_options" class="hp-tab-panel hidden" role="tabpanel" hidden>
|
<div id="hp-tab-options_options" class="hp-tab-panel hidden" role="tabpanel" hidden>
|
||||||
@@ -215,31 +193,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row hp-action-row">
|
<div class="form-row hp-action-row">
|
||||||
<button type="button" class="primary" id="hp-preview-btn-oo">计算</button>
|
<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>
|
||||||
</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>
|
||||||
|
|
||||||
<div id="hp-tab-active" class="hp-tab-panel hidden" role="tabpanel" hidden>
|
<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 id="hp-detail-body" class="hp-modal-body muted">加载中…</div>
|
||||||
</div>
|
</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>
|
||||||
<script src="/static/hedge_plan.js?v=19"></script>
|
<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=20"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user