Fix hub market chart live K-line updates without manual reload.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
(function () {
|
||||
const CHART_WATCH_HEARTBEAT_MS = 25000;
|
||||
const CHART_SSE_FALLBACK_MS = 60000;
|
||||
const CHART_SSE_FALLBACK_MS = 15000;
|
||||
const DEFAULT_VISIBLE_BARS = 200;
|
||||
const CHART_LOAD_LEFT_THRESHOLD = 25;
|
||||
const CHART_INITIAL_LIMITS = {
|
||||
@@ -2312,7 +2312,21 @@
|
||||
}
|
||||
|
||||
function viewKey(exKey, sym, tf) {
|
||||
return (exKey || "") + "|" + (sym || "") + "|" + (tf || "");
|
||||
const ex = String(exKey || "").trim().toLowerCase();
|
||||
const s = normalizeMarketSymbol(sym);
|
||||
const t = String(tf || "").trim();
|
||||
return ex + "|" + s + "|" + t;
|
||||
}
|
||||
|
||||
function lookupSeriesMapEntry(map, vKey) {
|
||||
if (!map || !vKey) return null;
|
||||
if (map[vKey]) return map[vKey];
|
||||
const parts = String(vKey).split("|");
|
||||
if (parts.length === 3) {
|
||||
const norm = viewKey(parts[0], parts[1], parts[2]);
|
||||
if (norm !== vKey && map[norm]) return map[norm];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function chartInitialLimit(tf) {
|
||||
@@ -2773,10 +2787,10 @@
|
||||
|
||||
function currentViewSeriesKey() {
|
||||
const exKey = (elExchange && elExchange.value) || "";
|
||||
const sym = (elSymbol && elSymbol.value.trim().toUpperCase()) || "";
|
||||
const sym = (elSymbol && elSymbol.value.trim()) || "";
|
||||
const tf = (elTf && elTf.value) || "1d";
|
||||
if (!exKey || !sym) return "";
|
||||
return exKey + "|" + sym + "|" + tf;
|
||||
return viewKey(exKey, sym, tf);
|
||||
}
|
||||
|
||||
function postChartWatch() {
|
||||
@@ -2812,6 +2826,45 @@
|
||||
}
|
||||
}
|
||||
|
||||
function handleChartStreamEvent(st) {
|
||||
if (!st || st.polling) return;
|
||||
const vKey = currentViewSeriesKey();
|
||||
if (!vKey) return;
|
||||
const tails = st.tails || {};
|
||||
const series = st.series || {};
|
||||
const tailPack = lookupSeriesMapEntry(tails, vKey);
|
||||
if (tailPack && tailPack.candles && tailPack.candles.length) {
|
||||
if (
|
||||
applyIncomingTailCandles(tailPack.candles, {
|
||||
price_tick: tailPack.price_tick,
|
||||
series_version: tailPack.series_version,
|
||||
chart_version: st.chart_version,
|
||||
updated_at: tailPack.updated_at || st.updated_at,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const seriesEntry = lookupSeriesMapEntry(series, vKey);
|
||||
const sVer = seriesEntry ? Number(seriesEntry.series_version) || 0 : 0;
|
||||
const seriesChanged = sVer > 0 && sVer !== localSeriesVersion;
|
||||
if (seriesChanged) {
|
||||
if (lastCandles.length && vKey === lastViewKey) {
|
||||
void refreshChartTail();
|
||||
} else if (!lastCandles.length && !chartDataLoading) {
|
||||
void loadChart(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (tailPack && lastCandles.length && vKey === lastViewKey && !chartDataLoading) {
|
||||
void refreshChartTail();
|
||||
return;
|
||||
}
|
||||
if (posContext) updateLivePosPnl();
|
||||
const ver = Number(st.chart_version) || 0;
|
||||
if (ver && ver !== localChartVersion) localChartVersion = ver;
|
||||
}
|
||||
|
||||
function connectChartStream() {
|
||||
closeChartStream();
|
||||
const page = document.getElementById("page-market");
|
||||
@@ -2819,34 +2872,7 @@
|
||||
chartEventSource = new EventSource("/api/chart/stream");
|
||||
chartEventSource.addEventListener("chart", function (ev) {
|
||||
try {
|
||||
const st = JSON.parse(ev.data || "{}");
|
||||
if (st.polling) return;
|
||||
const ver = Number(st.chart_version) || 0;
|
||||
const series = st.series || {};
|
||||
const vKey = currentViewSeriesKey();
|
||||
const tails = st.tails || {};
|
||||
const tailPack = vKey && tails[vKey] ? tails[vKey] : null;
|
||||
if (tailPack && tailPack.candles && tailPack.candles.length) {
|
||||
if (
|
||||
applyIncomingTailCandles(tailPack.candles, {
|
||||
price_tick: tailPack.price_tick,
|
||||
series_version: tailPack.series_version,
|
||||
chart_version: ver,
|
||||
updated_at: tailPack.updated_at || st.updated_at,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const sVer = vKey && series[vKey] ? Number(series[vKey].series_version) || 0 : 0;
|
||||
const seriesChanged = vKey && sVer > 0 && sVer !== localSeriesVersion;
|
||||
if (seriesChanged) {
|
||||
refreshChartTail();
|
||||
} else if (posContext) {
|
||||
updateLivePosPnl();
|
||||
} else if (ver !== localChartVersion) {
|
||||
localChartVersion = ver;
|
||||
}
|
||||
handleChartStreamEvent(JSON.parse(ev.data || "{}"));
|
||||
} catch (_) {}
|
||||
});
|
||||
chartEventSource.onerror = function () {
|
||||
@@ -2876,11 +2902,17 @@
|
||||
|
||||
function startAutoRefresh() {
|
||||
stopAutoRefresh();
|
||||
refreshTimer = setInterval(function () {
|
||||
const tick = function () {
|
||||
const page = document.getElementById("page-market");
|
||||
if (!page || page.classList.contains("hidden")) return;
|
||||
refreshChartTail();
|
||||
}, CHART_SSE_FALLBACK_MS);
|
||||
if (lastCandles.length) {
|
||||
void refreshChartTail();
|
||||
} else if (!chartDataLoading) {
|
||||
void loadChart(false);
|
||||
}
|
||||
};
|
||||
refreshTimer = setInterval(tick, CHART_SSE_FALLBACK_MS);
|
||||
tick();
|
||||
}
|
||||
|
||||
function stopAutoRefresh() {
|
||||
@@ -3189,6 +3221,9 @@
|
||||
elSymbol.addEventListener("keydown", function (e) {
|
||||
if (e.key === "Enter") loadChart(false);
|
||||
});
|
||||
elSymbol.addEventListener("change", function () {
|
||||
loadChart(false);
|
||||
});
|
||||
}
|
||||
const btnLoad = document.getElementById("market-load");
|
||||
if (btnLoad) {
|
||||
|
||||
Reference in New Issue
Block a user