fix(hub): load full pre-entry history for archive chart pan/zoom

range=history serves archive seed through close (not now). Default view focuses hold period; user can scroll/zoom left to see global morphology before entry.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-07 23:20:37 +08:00
parent 54c0b169c7
commit 5ceacd8077
6 changed files with 126 additions and 26 deletions
+48 -16
View File
@@ -252,16 +252,18 @@
});
}
function focusHoldRange(candles, tr, tf) {
/** 初始只聚焦持仓段;完整历史已加载,可向左拖动/滚轮缩小查看建仓前全局。 */
function focusInitialTradeView(candles, tr, tf) {
if (!chart || !candles.length || !tr) return;
const mode = (elViewMode && elViewMode.value) || "hold";
const openSec = tradeOpenMs(tr) ? msToBarTime(tradeOpenMs(tr), tf) : null;
const closeSec = tradeCloseMs(tr) ? msToBarTime(tradeCloseMs(tr), tf) : null;
let fromIdx = 0;
let toIdx = candles.length - 1;
let openIdx = 0;
let closeIdx = candles.length - 1;
if (openSec != null) {
for (let i = 0; i < candles.length; i++) {
if (candles[i].time >= openSec) {
fromIdx = Math.max(0, i - 12);
openIdx = i;
break;
}
}
@@ -269,11 +271,21 @@
if (closeSec != null) {
for (let i = candles.length - 1; i >= 0; i--) {
if (candles[i].time <= closeSec) {
toIdx = Math.min(candles.length - 1, i + 12);
closeIdx = i;
break;
}
}
}
const span = Math.max(24, closeIdx - openIdx + 20);
let fromIdx;
let toIdx;
if (mode === "entry") {
fromIdx = Math.max(0, openIdx - Math.floor(span * 0.35));
toIdx = Math.min(candles.length - 1, openIdx + Math.floor(span * 0.65));
} else {
fromIdx = Math.max(0, openIdx - 10);
toIdx = Math.min(candles.length - 1, closeIdx + 14);
}
if (toIdx <= fromIdx) {
toIdx = Math.min(candles.length - 1, fromIdx + 80);
}
@@ -303,9 +315,24 @@
vertLines: { color: isDark ? "#1a2030" : "#e8ecf2" },
horzLines: { color: isDark ? "#1a2030" : "#e8ecf2" },
},
rightPriceScale: { borderColor: isDark ? "#2a3348" : "#d0d7e2" },
timeScale: { borderColor: isDark ? "#2a3348" : "#d0d7e2", timeVisible: true },
rightPriceScale: { borderColor: isDark ? "#2a3348" : "#d0d7e2", autoScale: true },
timeScale: {
borderColor: isDark ? "#2a3348" : "#d0d7e2",
timeVisible: true,
secondsVisible: false,
},
crosshair: { mode: LightweightCharts.CrosshairMode.Normal },
handleScroll: {
mouseWheel: true,
pressedMouseMove: true,
horzTouchDrag: true,
vertTouchDrag: false,
},
handleScale: {
axisPressedMouseMove: true,
mouseWheel: true,
pinch: true,
},
});
candleSeries = chart.addCandlestickSeries({
upColor: "#22c55e",
@@ -335,19 +362,23 @@
const tr = pickAnchorTrade();
const anchor = anchorMsForTrade(tr);
const jump = (elJumpAt && elJumpAt.value || "").trim();
const openMs = tradeOpenMs(tr);
const closeMs = tradeCloseMs(tr);
const params = new URLSearchParams({
exchange_key: selected.exchange_key,
symbol: selected.symbol,
timeframe: timeframe,
mode: (elViewMode && elViewMode.value) || "hold",
bars: "200",
});
if (jump) params.set("at", jump);
else if (anchor) params.set("anchor_ms", String(anchor));
const openMs = tradeOpenMs(tr);
const closeMs = tradeCloseMs(tr);
if (openMs) params.set("opened_ms", String(openMs));
if (closeMs) params.set("closed_ms", String(closeMs));
if (openMs && closeMs) {
params.set("range", "history");
params.set("opened_ms", String(openMs));
params.set("closed_ms", String(closeMs));
} else {
params.set("bars", "200");
if (jump) params.set("at", jump);
else if (anchor) params.set("anchor_ms", String(anchor));
}
setStatus("加载 K 线…");
const r = await apiFetch("/api/archive/ohlcv?" + params.toString());
const j = await r.json();
@@ -375,11 +406,12 @@
candleSeries.setMarkers(buildTradeMarkers(tr, candles, timeframe));
}
if (tr && tradeOpenMs(tr) && tradeCloseMs(tr)) {
focusHoldRange(candles, tr, timeframe);
focusInitialTradeView(candles, tr, timeframe);
} else if (candles.length > 10) {
chart.timeScale().setVisibleLogicalRange({ from: candles.length - 120, to: candles.length + 5 });
}
setStatus("K 线 " + candles.length + " 根 · " + timeframe + (tr ? " · 已标注开/平" : ""));
const histHint = openMs && closeMs ? " · 可拖动/滚轮缩放查看建仓前走势" : "";
setStatus("K 线 " + candles.length + " 根 · " + timeframe + (tr ? " · 已标注开/平" : "") + histHint);
}
function renderTrades() {