Files
goldenChart/frontend/src/utils/chartLiveQuote.ts
T
2026-06-12 22:26:31 +09:00

58 lines
1.9 KiB
TypeScript

/**
* 실시간 차트 상단·우측 현재가·등락률 (크로스헤어와 분리, 업비트 티커 우선)
*/
import type { TickerData } from '../hooks/useMarketTicker';
import type { OHLCVBar } from '../types';
import { formatUpbitKrwPrice } from './safeFormat';
export interface ChartLiveQuote {
price: number | null;
/** 전일 대비 등락률 (%) */
changePct: number | null;
isUp: boolean;
}
export function resolveChartLiveQuote(
ticker: TickerData | undefined | null,
lastBar: OHLCVBar | null,
bars: OHLCVBar[],
): ChartLiveQuote {
// 실시간 차트: STOMP/WS로 갱신되는 최신 봉 종가 우선 (티커 REST 초기값에 고정되지 않도록)
const barPrice = lastBar?.close;
const tickerPrice = ticker?.tradePrice;
const price =
barPrice != null && Number.isFinite(barPrice)
? barPrice
: tickerPrice != null && Number.isFinite(tickerPrice)
? tickerPrice
: null;
if (ticker?.changeRate != null && Number.isFinite(ticker.changeRate)) {
const changePct = ticker.changeRate * 100;
return { price, changePct, isUp: ticker.changeRate >= 0 };
}
if (lastBar && bars.length > 1) {
const prevClose = bars[bars.length - 2].close;
if (prevClose > 0) {
const ch = lastBar.close - prevClose;
const changePct = (ch / prevClose) * 100;
return { price, changePct, isUp: ch >= 0 };
}
}
const isUp = lastBar ? lastBar.close >= lastBar.open : true;
return { price, changePct: null, isUp };
}
export function formatChartLivePrice(price: number | null): string {
if (price == null || !Number.isFinite(price)) return '—';
return `${formatUpbitKrwPrice(price)} KRW`;
}
export function formatChartLiveChangePct(changePct: number | null): string {
if (changePct == null || !Number.isFinite(changePct)) return '';
const up = changePct >= 0;
return `${up ? '▲' : '▼'} ${Math.abs(changePct).toFixed(2)}%`;
}