From 6352fa6be3bf0fbf1c78f0d1262526b5ca82b4c5 Mon Sep 17 00:00:00 2001 From: dekun Date: Fri, 26 Jun 2026 23:16:59 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=BB=9A=E4=BB=93=E6=8B=92=E7=BB=9D?= =?UTF-8?q?=E5=8E=9F=E5=9B=A0=E9=A1=B5=E5=86=85=E5=B1=95=E7=A4=BA=EF=BC=8C?= =?UTF-8?q?=E6=96=90=E6=B3=A2/=E7=AA=81=E7=A0=B4=E9=9A=90=E8=97=8F?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- crypto_monitor_binance/templates/index.html | 2 +- crypto_monitor_gate/templates/index.html | 2 +- crypto_monitor_gate_bot/templates/index.html | 2 +- crypto_monitor_okx/templates/index.html | 2 +- embed_templates/embed_shell.html | 2 +- static/instance_theme.css | 24 +++ static/strategy_roll.js | 193 ++++++++++++++----- strategy_templates/strategy_roll_panel.html | 10 +- 8 files changed, 176 insertions(+), 61 deletions(-) diff --git a/crypto_monitor_binance/templates/index.html b/crypto_monitor_binance/templates/index.html index 3953607..3c1dcb4 100644 --- a/crypto_monitor_binance/templates/index.html +++ b/crypto_monitor_binance/templates/index.html @@ -834,7 +834,7 @@ - + - + - + - + - + {% include 'embed_boot_scripts.html' %} diff --git a/static/instance_theme.css b/static/instance_theme.css index 98f60da..f117fac 100644 --- a/static/instance_theme.css +++ b/static/instance_theme.css @@ -1305,6 +1305,12 @@ html[data-theme="light"] .detail-actions { align-items: center; } +#roll-form[data-add-mode="fib_618"] #roll-preview-btn, +#roll-form[data-add-mode="fib_786"] #roll-preview-btn, +#roll-form[data-add-mode="breakout"] #roll-preview-btn { + display: none !important; +} + #strategy-roll-panel .roll-risk-banner { margin-bottom: 8px; color: #8fc8ff; @@ -1341,12 +1347,30 @@ html[data-theme="light"] #strategy-roll-panel .roll-section-title { color: #dde2ff; } +#roll-preview-box.roll-preview-box.is-error { + border-color: #8a3a4a; + background: #1a1218; + color: #ffb4b4; +} + +#roll-preview-box.roll-preview-box.is-preview { + border-color: #3a5a8a; + background: #141a28; + color: #dde2ff; +} + html[data-theme="light"] #roll-preview-box.roll-preview-box { background: #f6f9fc !important; border-color: #b8c8d8 !important; color: #1a2838 !important; } +html[data-theme="light"] #roll-preview-box.roll-preview-box.is-error { + background: #fff5f5 !important; + border-color: #d8a0a8 !important; + color: #8a2030 !important; +} + #roll-countdown.roll-countdown { margin-top: 6px; color: #ffb347; diff --git a/static/strategy_roll.js b/static/strategy_roll.js index c4c8d02..85779e8 100644 --- a/static/strategy_roll.js +++ b/static/strategy_roll.js @@ -42,10 +42,21 @@ const previewBox = document.getElementById("roll-preview-box"); const previewText = document.getElementById("roll-preview-text"); const countdownEl = document.getElementById("roll-countdown"); + const trendLocked = submitBtn && submitBtn.getAttribute("data-trend-locked") === "1"; let countdownTimer = null; let previewOk = false; let lastPreviewMode = ""; + let allowMonitorSubmit = false; + + function isMarketMode() { + return (modeSel.value || "market") === "market"; + } + + function isMonitorMode() { + const m = modeSel.value || "market"; + return m === "fib_618" || m === "fib_786" || m === "breakout"; + } function selectedOption() { return symbolSel.options[symbolSel.selectedIndex]; @@ -64,6 +75,57 @@ "当前风险:" + rp + "%(来自监控单 #" + (opt.getAttribute("data-monitor-id") || "?") + ")"; } + function syncSubmitButton() { + if (!submitBtn || trendLocked) return; + if (isMonitorMode()) { + submitBtn.disabled = false; + return; + } + submitBtn.disabled = !previewOk || !!countdownTimer; + } + + function clearMessageBox() { + if (!previewBox) return; + previewBox.style.display = "none"; + previewBox.classList.remove("is-error", "is-preview"); + if (previewText) previewText.textContent = ""; + if (countdownEl) countdownEl.style.display = "none"; + } + + function showReject(msg) { + if (!previewBox || !previewText) return; + previewBox.style.display = "block"; + previewBox.classList.remove("is-preview"); + previewBox.classList.add("is-error"); + previewText.textContent = msg || "无法执行"; + if (countdownEl) countdownEl.style.display = "none"; + } + + function showPreviewResult(p) { + if (!previewBox || !previewText) return; + previewBox.style.display = "block"; + previewBox.classList.remove("is-error"); + previewBox.classList.add("is-preview"); + previewText.innerHTML = + "" + + (p.add_mode_label || "") + + " · 约 " + + (p.add_amount_display != null ? p.add_amount_display : p.add_amount_raw) + + "
" + + "加仓参考价 " + + (p.add_price_display != null ? p.add_price_display : p.add_price) + + " · 新止损 " + + (p.new_sl_display != null ? p.new_sl_display : p.new_stop_loss) + + "
" + + "合并均价 " + + p.avg_entry_after + + " · 打到止损约 " + + p.loss_at_sl_usdt + + "U(风险预算 " + + (p.risk_budget_usdt != null ? p.risk_budget_usdt : "—") + + "U)"; + } + function syncFieldVisibility() { syncRollFormMode(form, modeSel.value || "market"); resetPreview(); @@ -71,13 +133,13 @@ function resetPreview() { previewOk = false; - if (submitBtn) submitBtn.disabled = true; - if (previewBox) previewBox.style.display = "none"; - if (countdownEl) countdownEl.style.display = "none"; + allowMonitorSubmit = false; + clearMessageBox(); if (countdownTimer) { clearInterval(countdownTimer); countdownTimer = null; } + syncSubmitButton(); } function formPayload() { @@ -89,78 +151,98 @@ return obj; } - function runPreview() { - resetPreview(); - if (!symbolSel.value) { - alert("请先选择持仓币种"); - return; - } - previewBtn.disabled = true; - fetch("/strategy/roll/preview", { + function requestPreview() { + return fetch("/strategy/roll/preview", { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json" }, body: JSON.stringify(formPayload()), credentials: "same-origin", - }) - .then(function (r) { - return r.json(); - }) + }).then(function (r) { + return r.json(); + }); + } + + function runPreview() { + resetPreview(); + if (!symbolSel.value) { + showReject("请先选择持仓币种"); + return; + } + if (previewBtn) previewBtn.disabled = true; + requestPreview() .then(function (data) { - previewBtn.disabled = false; + if (previewBtn) previewBtn.disabled = false; if (!data.ok) { - alert(data.msg || "预览失败"); + showReject(data.msg || "预览失败"); return; } const p = data.preview || {}; lastPreviewMode = p.add_mode || modeSel.value; - previewText.innerHTML = - "" + - (p.add_mode_label || "") + - " · 约 " + - (p.add_amount_display != null ? p.add_amount_display : p.add_amount_raw) + - "
" + - "加仓参考价 " + - (p.add_price_display != null ? p.add_price_display : p.add_price) + - " · 新止损 " + - (p.new_sl_display != null ? p.new_sl_display : p.new_stop_loss) + - "
" + - "合并均价 " + - p.avg_entry_after + - " · 打到止损约 " + - p.loss_at_sl_usdt + - "U(风险预算 " + - (p.risk_budget_usdt != null ? p.risk_budget_usdt : "—") + - "U)"; - previewBox.style.display = "block"; + showPreviewResult(p); previewOk = true; if (lastPreviewMode === "market") { startCountdown(10); - } else if (submitBtn) { - submitBtn.disabled = false; - countdownEl.style.display = "none"; + } else { + syncSubmitButton(); } }) .catch(function () { - previewBtn.disabled = false; - alert("预览请求失败"); + if (previewBtn) previewBtn.disabled = false; + showReject("预览请求失败,请稍后重试"); + }); + } + + function runMonitorSubmit() { + if (!symbolSel.value) { + showReject("请先选择持仓币种"); + return; + } + if (submitBtn) submitBtn.disabled = true; + requestPreview() + .then(function (data) { + if (submitBtn && !trendLocked) submitBtn.disabled = false; + if (!data.ok) { + showReject(data.msg || "无法提交监控"); + return; + } + const p = data.preview || {}; + const modeLabel = modeSel.options[modeSel.selectedIndex].text; + const summary = + "约 " + + (p.add_amount_display != null ? p.add_amount_display : p.add_amount_raw) + + " 张 · 触发参考价 " + + (p.add_price_display != null ? p.add_price_display : p.add_price) + + " · 新止损 " + + (p.new_sl_display != null ? p.new_sl_display : p.new_stop_loss); + if (!confirm("确认提交「" + modeLabel + "」?\n" + summary)) { + return; + } + allowMonitorSubmit = true; + form.requestSubmit(); + }) + .catch(function () { + if (submitBtn && !trendLocked) submitBtn.disabled = false; + showReject("校验请求失败,请稍后重试"); }); } function startCountdown(sec) { let left = sec; if (submitBtn) submitBtn.disabled = true; - countdownEl.style.display = "block"; - countdownEl.textContent = "市价加仓:" + left + " 秒后可执行(可取消刷新预览)"; + if (countdownEl) { + countdownEl.style.display = "block"; + countdownEl.textContent = "市价加仓:" + left + " 秒后可执行(修改表单将取消预览)"; + } countdownTimer = setInterval(function () { left -= 1; if (left <= 0) { clearInterval(countdownTimer); countdownTimer = null; - countdownEl.textContent = "可以执行市价加仓"; - if (submitBtn) submitBtn.disabled = false; + if (countdownEl) countdownEl.textContent = "可以执行市价加仓"; + syncSubmitButton(); return; } - countdownEl.textContent = "市价加仓:" + left + " 秒后可执行"; + if (countdownEl) countdownEl.textContent = "市价加仓:" + left + " 秒后可执行"; }, 1000); } @@ -173,16 +255,25 @@ form.addEventListener("change", function (e) { if (e.target !== previewBtn) resetPreview(); }); - previewBtn.addEventListener("click", runPreview); + if (previewBtn) previewBtn.addEventListener("click", runPreview); form.addEventListener("submit", function (e) { - if (!previewOk) { + if (isMonitorMode()) { + if (allowMonitorSubmit) { + allowMonitorSubmit = false; + return; + } e.preventDefault(); - alert("请先点击预览"); + runMonitorSubmit(); return; } - if (lastPreviewMode === "market" && submitBtn && submitBtn.disabled) { + if (!previewOk) { e.preventDefault(); - alert("请等待 10 秒确认倒计时结束"); + showReject("请先点击「预览」并通过校验"); + return; + } + if (submitBtn && submitBtn.disabled) { + e.preventDefault(); + showReject("请等待 10 秒确认倒计时结束后再执行市价加仓"); return; } const modeLabel = modeSel.options[modeSel.selectedIndex].text; diff --git a/strategy_templates/strategy_roll_panel.html b/strategy_templates/strategy_roll_panel.html index 3d52d7f..4e02a36 100644 --- a/strategy_templates/strategy_roll_panel.html +++ b/strategy_templates/strategy_roll_panel.html @@ -6,7 +6,7 @@ 仅人工提交;须先在「实盘下单」有同向持仓。仅以损定仓模式可用。
做多/做空各最多滚仓 3 次(仅计已成交腿);止盈锁定首仓不变。
风险比例读取所选监控单,不可手改;打到新止损时合并持仓亏损 ≈ 1 个风险单位(当前基数 × 监控 risk%)。
- 斐波/突破为程序监控(mark 价穿越触发),触价后市价加仓;同时仅允许 1 条监控中腿,提交后不可修改,可删除。
+ 斐波/突破为程序监控(mark 价穿越触发),触价后市价加仓;填写后直接点「执行滚仓」(无需预览)。同时仅允许 1 条监控中腿,提交后不可修改,可删除。
手动平仓后滚仓监控自动结束;已成交腿历史保留供复盘。
→ 顺势加仓完整逻辑说明
{% if roll_trend_active %}当前有运行中的趋势回调计划,请先结束后再滚仓。{% endif %} @@ -44,11 +44,11 @@ - - + + - - +