(function (global) { function escapeHtml(s) { return String(s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function statusLabel(o) { const st = o.status || ""; const reason = o.end_reason || ""; if (st === "done") { const map = { leave_up: "结束·上破", leave_down: "结束·下破", cancel: "已取消", closed: "已完成", }; return map[reason] || "已结束"; } const map2 = { armed: "待命", triggering: "触发中", open: "持仓中" }; return map2[st] || st || "—"; } async function loadCandidates() { const box = document.getElementById("cf-instances"); if (!box) return; const r = await fetch("/api/cond_orders/candidates"); const d = await r.json(); const list = d.instances || []; if (!list.length) { box.innerHTML = '暂无启用实例'; return; } box.innerHTML = list .map(function (it) { const disabled = !it.selectable; const tip = disabled ? it.has_position ? "已有持仓" : it.cond_order_locked ? "条件单占用" : it.online ? "不可选" : "离线" : "可选"; return ( '" ); }) .join(""); } async function loadOrders() { const box = document.getElementById("cond-list"); if (!box) return; const r = await fetch("/api/cond_orders"); const d = await r.json(); const list = d.orders || []; if (!list.length) { box.innerHTML = '暂无条件单'; return; } box.innerHTML = '
' + "" + "" + list .map(function (o) { const side = o.trigger_side === "lte" ? "≤" : "≥"; const exit = (o.profit_exit_enabled ? "翻倍×" + (o.profit_exit_mult || "") : "") + (o.target_index != null ? " 目标" + o.target_index : ""); const canCancel = o.status === "armed" || o.status === "triggering"; const canExit = o.status === "open"; let actions = ""; if (canCancel) { actions += ''; } if (canExit) { actions += ''; } return ( "" + "" + "" + "" + "" + "" + "" + "" + "" + '" + "" ); }) .join("") + "
客户端状态标的触发偏离到期h出场说明操作
" + escapeHtml(o.instance_name || "") + "" + escapeHtml(statusLabel(o)) + "" + escapeHtml((o.underlying || "") + " " + (o.opt_type || "")) + "" + escapeHtml(side + " " + (o.trigger_px != null ? o.trigger_px : "")) + "" + escapeHtml(o.deviation_pct != null ? o.deviation_pct + "%" : "—") + "" + escapeHtml(o.min_expiry_hours != null ? String(o.min_expiry_hours) : "—") + "" + escapeHtml(exit || "—") + "" + escapeHtml(o.message || "") + "
' + actions + "
"; box.querySelectorAll("[data-cancel]").forEach(function (btn) { btn.addEventListener("click", async function () { if (!confirm("确认取消该条件单?")) return; const oid = decodeURIComponent(btn.getAttribute("data-cancel") || ""); const iid = decodeURIComponent(btn.getAttribute("data-iid") || ""); const rr = await fetch("/api/cond_orders/" + encodeURIComponent(oid) + "/cancel", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ instance_id: Number(iid) }), }); const dd = await rr.json(); alert(dd.msg || (dd.ok ? "已取消" : "失败")); refresh(); }); }); box.querySelectorAll("[data-exit]").forEach(function (btn) { btn.addEventListener("click", async function () { const oid = decodeURIComponent(btn.getAttribute("data-exit") || ""); const iid = decodeURIComponent(btn.getAttribute("data-iid") || ""); const curT = decodeURIComponent(btn.getAttribute("data-target") || ""); const curM = decodeURIComponent(btn.getAttribute("data-mult") || "1"); const pe = btn.getAttribute("data-pe") === "1"; const t = prompt("目标指数(留空清除)", curT); if (t === null) return; const peOn = confirm("是否启用翻倍出场?\n当前:" + (pe ? "开" : "关")); let mult = curM; if (peOn) { const m = prompt("翻倍倍数", curM); if (m === null) return; mult = m; } const rr = await fetch("/api/cond_orders/" + encodeURIComponent(oid) + "/exit", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ instance_id: Number(iid), target_index: t === "" ? "" : t, profit_exit_enabled: peOn, profit_exit_mult: mult, }), }); const dd = await rr.json(); alert(dd.msg || (dd.ok ? "已更新" : "失败")); refresh(); }); }); } async function createOrder() { const status = document.getElementById("cf-status"); const ids = Array.prototype.slice .call(document.querySelectorAll('input[name="cf-inst"]:checked')) .map(function (el) { return Number(decodeURIComponent(el.value)); }); if (!ids.length) { alert("请选择至少一台可选客户端"); return; } const body = { instance_ids: ids, underlying: document.getElementById("cf-underlying").value, opt_type: document.getElementById("cf-opt-type").value, trigger_side: document.getElementById("cf-trigger-side").value, trigger_px: document.getElementById("cf-trigger-px").value, deviation_pct: document.getElementById("cf-deviation").value, min_expiry_hours: document.getElementById("cf-expiry-h").value, target_index: document.getElementById("cf-target").value, profit_exit_enabled: document.getElementById("cf-pe").checked, profit_exit_mult: document.getElementById("cf-pe-mult").value, }; if (status) status.textContent = "下发中…"; const r = await fetch("/api/cond_orders", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); const d = await r.json(); if (status) status.textContent = d.msg || ""; alert(d.msg || (d.ok ? "已下发" : "失败")); refresh(); } async function refresh() { await Promise.all([loadCandidates(), loadOrders()]); } function boot() { const btn = document.getElementById("btn-cond-refresh"); if (btn) btn.addEventListener("click", refresh); const create = document.getElementById("btn-cond-create"); if (create) create.addEventListener("click", createOrder); refresh(); setInterval(refresh, 10000); } global.HubCondOrders = { boot: boot, refresh: refresh }; })(window);