대시보드 실시간 기능 추가
This commit is contained in:
@@ -35,7 +35,7 @@ import {
|
||||
} from "./chart-utils";
|
||||
|
||||
const UP_COLOR = "#ef4444";
|
||||
const MINUTE_SYNC_INTERVAL_MS = 5000;
|
||||
const MINUTE_SYNC_INTERVAL_MS = 30000;
|
||||
const REALTIME_STALE_THRESHOLD_MS = 12000;
|
||||
|
||||
interface ChartPalette {
|
||||
@@ -522,11 +522,11 @@ export function StockLineChart({
|
||||
}
|
||||
}, [isChartReady, renderableBars, setSeriesData]);
|
||||
|
||||
/**
|
||||
* @description WebSocket 체결 틱을 현재 timeframe 캔들에 반영합니다.
|
||||
* @see features/trade/hooks/useKisTradeWebSocket.ts latestTick
|
||||
* @see features/trade/components/chart/chart-utils.ts toRealtimeTickBar
|
||||
*/
|
||||
/**
|
||||
* @description WebSocket 체결 틱을 현재 timeframe 캔들에 반영합니다.
|
||||
* @see features/trade/hooks/useKisTradeWebSocket.ts latestTick
|
||||
* @see features/trade/components/chart/chart-utils.ts toRealtimeTickBar
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!latestTick) return;
|
||||
if (bars.length === 0) return;
|
||||
@@ -567,7 +567,10 @@ export function StockLineChart({
|
||||
const recentBars = latestPageBars.slice(-10);
|
||||
if (recentBars.length === 0) return;
|
||||
|
||||
setBars((prev) => mergeBars(prev, recentBars));
|
||||
setBars((prev) => {
|
||||
const merged = mergeBars(prev, recentBars);
|
||||
return areBarsEqual(prev, merged) ? prev : merged;
|
||||
});
|
||||
} catch {
|
||||
// 폴링 실패는 치명적이지 않으므로 조용히 다음 주기에서 재시도합니다.
|
||||
}
|
||||
@@ -690,3 +693,25 @@ export function StockLineChart({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function areBarsEqual(left: ChartBar[], right: ChartBar[]) {
|
||||
if (left.length !== right.length) return false;
|
||||
|
||||
for (let index = 0; index < left.length; index += 1) {
|
||||
const lhs = left[index];
|
||||
const rhs = right[index];
|
||||
if (!lhs || !rhs) return false;
|
||||
if (
|
||||
lhs.time !== rhs.time ||
|
||||
lhs.open !== rhs.open ||
|
||||
lhs.high !== rhs.high ||
|
||||
lhs.low !== rhs.low ||
|
||||
lhs.close !== rhs.close ||
|
||||
lhs.volume !== rhs.volume
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ function resolveBarTimestamp(
|
||||
|
||||
/**
|
||||
* 타임스탬프를 타임프레임 버킷 경계에 정렬
|
||||
* - 1m: 그대로
|
||||
* - 1m: 초/밀리초를 제거해 분 경계에 정렬
|
||||
* - 30m/1h: 분 단위를 버킷에 정렬
|
||||
* - 1d: 00:00:00
|
||||
* - 1w: 월요일 00:00:00
|
||||
@@ -161,7 +161,9 @@ function alignTimestamp(
|
||||
): UTCTimestamp {
|
||||
const d = new Date(timestamp * 1000);
|
||||
|
||||
if (timeframe === "30m" || timeframe === "1h") {
|
||||
if (timeframe === "1m") {
|
||||
d.setUTCSeconds(0, 0);
|
||||
} else if (timeframe === "30m" || timeframe === "1h") {
|
||||
const bucket = timeframe === "30m" ? 30 : 60;
|
||||
d.setUTCMinutes(Math.floor(d.getUTCMinutes() / bucket) * bucket, 0, 0);
|
||||
} else if (timeframe === "1d") {
|
||||
|
||||
Reference in New Issue
Block a user