실시간 차트 우측 상단 주가, 등락율 현재가로 반영

This commit is contained in:
Macbook
2026-05-29 15:46:57 +09:00
parent 34d91fdced
commit e497d03925
6 changed files with 252 additions and 119 deletions
+35 -21
View File
@@ -14,6 +14,12 @@ import MainChartSettingsModal from './MainChartSettingsModal';
import { MarketSearchPanel } from './MarketSearchPanel';
import { generateBars, formatPrice } from '../utils/dataGenerator';
import { getKoreanName } from '../utils/marketNameCache';
import type { TickerData } from '../hooks/useMarketTicker';
import {
formatChartLiveChangePct,
formatChartLivePrice,
resolveChartLiveQuote,
} from '../utils/chartLiveQuote';
import { DEFAULT_MAIN_CHART_STYLE } from '../utils/storage';
import { enrichIndicatorConfig, getIndicatorDef } from '../utils/indicatorRegistry';
import { normalizeSmaConfig, createDefaultSmaPlotVisibility } from '../utils/smaConfig';
@@ -180,6 +186,8 @@ export interface ChartSlotProps {
chartVisible?: boolean;
/** pane 구분선 */
chartPaneSeparator?: ChartPaneSeparatorOptions;
/** 업비트 실시간 티커 맵 (슬롯 심볼별 현재가·등락) */
marketTickers?: Map<string, TickerData>;
}
const ChartSlot = forwardRef<ChartSlotHandle, ChartSlotProps>(function ChartSlot({
@@ -204,6 +212,7 @@ const ChartSlot = forwardRef<ChartSlotHandle, ChartSlotProps>(function ChartSlot
chartLiveReceiveHighlight = true,
chartVisible = true,
chartPaneSeparator,
marketTickers,
}, ref) {
// ── 전역 지표 파라미터 + 시각 설정 (DB 동기화) ────────────────────────
const { getParams, saveParams, getVisualConfig, saveVisual } = useIndicatorSettings();
@@ -557,10 +566,11 @@ const ChartSlot = forwardRef<ChartSlotHandle, ChartSlotProps>(function ChartSlot
? (latestBar ?? (bars.length > 0 ? bars[bars.length - 1] : null))
: (bars.length > 0 ? bars[bars.length - 1] : null);
const quoteBar = lastKnownBar;
const isUp = quoteBar ? quoteBar.close >= quoteBar.open : true;
const prevClose = bars.length > 1 ? bars[bars.length - 2].close : quoteBar?.open ?? 0;
const dailyChange = quoteBar ? quoteBar.close - prevClose : 0;
const dailyChangePct = prevClose > 0 ? dailyChange / prevClose * 100 : 0;
const slotTicker = marketTickers?.get(symbol) ?? null;
const liveQuote = useMemo(
() => resolveChartLiveQuote(slotTicker, quoteBar, bars),
[slotTicker, quoteBar, bars],
);
const receiveSignal = useMemo(() => {
if (!useUpbit || wsStatus !== 'connected' || !latestBar) return null;
@@ -671,8 +681,8 @@ const ChartSlot = forwardRef<ChartSlotHandle, ChartSlotProps>(function ChartSlot
}, [compactMode, onActivate, showMarket]);
const displayKoName = compactKoName(symbol);
const trendUp = compactMode && quoteBar != null && dailyChangePct >= 0;
const trendDown = compactMode && quoteBar != null && dailyChangePct < 0;
const trendUp = compactMode && liveQuote.price != null && liveQuote.isUp;
const trendDown = compactMode && liveQuote.price != null && !liveQuote.isUp;
return (
<div
@@ -708,20 +718,22 @@ const ChartSlot = forwardRef<ChartSlotHandle, ChartSlotProps>(function ChartSlot
<span className="slot-compact-name-text">{displayKoName}</span>
</button>
{quoteBar && (
{liveQuote.price != null && (
<div className="slot-compact-quote" aria-label="현재가">
<span
className="slot-compact-price"
style={{ color: isUp ? 'var(--up)' : 'var(--down)' }}
style={{ color: liveQuote.isUp ? 'var(--up)' : 'var(--down)' }}
>
{formatPrice(quoteBar.close)}
</span>
<span
className="slot-compact-change"
style={{ color: isUp ? 'var(--up)' : 'var(--down)' }}
>
{isUp ? '+' : '-'}{Math.abs(dailyChangePct).toFixed(2)}%
{formatChartLivePrice(liveQuote.price).replace(' KRW', '')}
</span>
{liveQuote.changePct != null && (
<span
className="slot-compact-change"
style={{ color: liveQuote.isUp ? 'var(--up)' : 'var(--down)' }}
>
{formatChartLiveChangePct(liveQuote.changePct)}
</span>
)}
</div>
)}
@@ -772,12 +784,14 @@ const ChartSlot = forwardRef<ChartSlotHandle, ChartSlotProps>(function ChartSlot
</button>
))}
</div>
{quoteBar && (
<span className="slot-price" style={{ color: isUp ? 'var(--up)' : 'var(--down)' }}>
{formatPrice(quoteBar.close)}
<span className="slot-change" style={{ color: isUp ? 'var(--up)' : 'var(--down)' }}>
{isUp ? '▲' : '▼'} {Math.abs(dailyChangePct).toFixed(2)}%
</span>
{liveQuote.price != null && (
<span className="slot-price" style={{ color: liveQuote.isUp ? 'var(--up)' : 'var(--down)' }}>
{formatChartLivePrice(liveQuote.price).replace(' KRW', '')}
{liveQuote.changePct != null && (
<span className="slot-change" style={{ color: liveQuote.isUp ? 'var(--up)' : 'var(--down)' }}>
{formatChartLiveChangePct(liveQuote.changePct)}
</span>
)}
</span>
)}
{useUpbit && <WsBadge status={wsStatus} isUpbit={true} />}