/** * 中控资金概况:总资金曲线、分户资金与回撤(资金户+交易户,不含浮盈)。 */ (function () { const page = document.getElementById("page-funds"); if (!page) return; const elStatus = document.getElementById("funds-status"); const elTotal = document.getElementById("funds-total-usdt"); const elDdU = document.getElementById("funds-total-dd-u"); const elDdPct = document.getElementById("funds-total-dd-pct"); const elDelta = document.getElementById("funds-total-delta"); const elMeta = document.getElementById("funds-meta"); const elChartHost = document.getElementById("funds-chart-total"); const elAccounts = document.getElementById("funds-accounts"); const elBtnRefresh = document.getElementById("funds-btn-refresh"); let chart = null; let lineSeries = null; let inited = false; let loading = false; function fmt(n, d) { if (n == null || n === "" || !Number.isFinite(Number(n))) return "—"; return Number(n).toFixed(d == null ? 2 : d); } function fmtDelta(n) { if (n == null || !Number.isFinite(Number(n))) return "—"; const v = Number(n); const sign = v > 0 ? "+" : ""; return sign + v.toFixed(2) + " U"; } function deltaClass(n) { if (!Number.isFinite(Number(n))) return ""; if (Number(n) > 0) return "pos"; if (Number(n) < 0) return "neg"; return ""; } function setStatus(msg, isErr) { if (!elStatus) return; elStatus.textContent = msg || ""; elStatus.className = "funds-status" + (isErr ? " err" : ""); } function seriesToChartData(series) { return (series || []) .filter(function (p) { return p && p.day && Number.isFinite(Number(p.total_usdt)); }) .map(function (p) { return { time: String(p.day), value: Number(p.total_usdt) }; }); } function destroyChart() { if (chart) { chart.remove(); chart = null; lineSeries = null; } if (elChartHost) elChartHost.innerHTML = ""; } function chartPalette() { const light = document.documentElement.getAttribute("data-theme") === "light"; return light ? { bg: "#f0f4f9", text: "#4a6078", border: "#b8c8d8", line: "#006e9a" } : { bg: "#0b0e18", text: "#9aa4b8", border: "#2a3348", line: "#3b82f6" }; } function ensureChart() { if (!elChartHost || !window.LightweightCharts) return; if (chart) return; const p = chartPalette(); chart = LightweightCharts.createChart(elChartHost, { layout: { background: { color: p.bg }, textColor: p.text }, grid: { vertLines: { color: p.border, visible: true }, horzLines: { color: p.border, visible: true }, }, rightPriceScale: { borderColor: p.border }, timeScale: { borderColor: p.border, timeVisible: true }, crosshair: { mode: LightweightCharts.CrosshairMode.Normal }, handleScroll: { mouseWheel: true, pressedMouseMove: true }, handleScale: { axisPressedMouseMove: true, mouseWheel: true, pinch: true }, }); lineSeries = chart.addAreaSeries({ lineColor: p.line, topColor: p.line + "44", bottomColor: p.line + "08", lineWidth: 2, priceFormat: { type: "price", precision: 2, minMove: 0.01 }, }); new ResizeObserver(function () { if (chart && elChartHost) { chart.applyOptions({ width: elChartHost.clientWidth, height: elChartHost.clientHeight }); } }).observe(elChartHost); chart.applyOptions({ width: elChartHost.clientWidth, height: elChartHost.clientHeight }); } function renderMiniChart(host, series) { if (!host || !window.LightweightCharts) return; host.innerHTML = ""; const data = seriesToChartData(series); if (data.length < 2) { host.textContent = "历史不足"; return; } const p = chartPalette(); const mini = LightweightCharts.createChart(host, { layout: { background: { color: "transparent" }, textColor: p.text }, grid: { vertLines: { visible: false }, horzLines: { visible: false } }, rightPriceScale: { visible: false }, timeScale: { visible: false }, crosshair: { mode: LightweightCharts.CrosshairMode.Hidden }, handleScroll: false, handleScale: false, }); const s = mini.addLineSeries({ color: p.line, lineWidth: 1.5 }); s.setData(data); mini.timeScale().fitContent(); const w = host.clientWidth; const h = host.clientHeight; if (w > 0 && h > 0) mini.applyOptions({ width: w, height: h }); } function renderAccounts(accounts) { if (!elAccounts) return; if (!accounts || !accounts.length) { elAccounts.innerHTML = '
暂无账户配置
'; return; } elAccounts.innerHTML = accounts .map(function (ac) { const monitored = !!ac.monitored; const cls = monitored ? "" : " is-off"; const total = monitored && ac.data_ok ? fmt(ac.total_usdt, 2) + " U" : "—"; const funding = monitored && ac.funding_usdt != null ? fmt(ac.funding_usdt, 2) : "—"; const trading = monitored && ac.trading_usdt != null ? fmt(ac.trading_usdt, 2) : "—"; const dd = ac.drawdown || {}; const ddU = dd.max_drawdown_u != null ? fmt(dd.max_drawdown_u, 2) + " U" : "—"; const ddPct = dd.max_drawdown_pct != null ? fmt(dd.max_drawdown_pct, 2) + "%" : "—"; const status = monitored ? (ac.data_ok ? "已监控" : "余额未齐") : "未监控"; return ( '