diff --git a/frontend/src/components/tradeNotification/TradeSignalMiniChart.tsx b/frontend/src/components/tradeNotification/TradeSignalMiniChart.tsx index 7b5b433..263c14c 100644 --- a/frontend/src/components/tradeNotification/TradeSignalMiniChart.tsx +++ b/frontend/src/components/tradeNotification/TradeSignalMiniChart.tsx @@ -157,7 +157,10 @@ const TradeSignalMiniChart: React.FC = ({ onNewCandle: handleNewCandle, enabled: enabled && useUpbit, source: chartRealtimeSource, - deepObvHistory: needsDeepObv, + deepObvHistory: false, + // OBV 있을 때: 200봉만 가져오면 OBV가 0부터 시작 → 신호선과 시각적 발산 보장 + // WARMUP_COUNT(600) 불필요 — 미니차트 지표(OBV SMA-9, W%R 등)는 짧은 웜업으로 충분 + fetchCount: needsDeepObv ? 200 : undefined, }), [handleTickUpdate, handleNewCandle, enabled, useUpbit, needsDeepObv, chartRealtimeSource]), ); @@ -300,7 +303,6 @@ const TradeSignalMiniChart: React.FC = ({ candleOverlayToggles={candleOverlayToggles} onToggleCandleOverlay={handleToggleCandleOverlay} crosshairInfoVisible={false} - resolveInitialDisplayCount={needsDeepObv ? () => 99999 : undefined} /> )} diff --git a/frontend/src/hooks/useChartRealtimeData.ts b/frontend/src/hooks/useChartRealtimeData.ts index bc3738a..e92eab7 100644 --- a/frontend/src/hooks/useChartRealtimeData.ts +++ b/frontend/src/hooks/useChartRealtimeData.ts @@ -9,6 +9,8 @@ interface Options { onNewCandle: (bar: OHLCVBar) => void; enabled?: boolean; deepObvHistory?: boolean; + /** 직접 지정할 페치 봉 수 — UPBIT_DIRECT 전용 (deepObvHistory·WARMUP_COUNT 무시) */ + fetchCount?: number; source?: ChartRealtimeSource; } @@ -29,6 +31,7 @@ export function useChartRealtimeData( onNewCandle: opts.onNewCandle, enabled: opts.enabled !== false && !useStomp, deepObvHistory: opts.deepObvHistory, + fetchCount: opts.fetchCount, }); return useStomp ? stomp : upbit; } diff --git a/frontend/src/hooks/useUpbitData.ts b/frontend/src/hooks/useUpbitData.ts index 357a98c..db29251 100644 --- a/frontend/src/hooks/useUpbitData.ts +++ b/frontend/src/hooks/useUpbitData.ts @@ -26,6 +26,8 @@ interface UpbitDataOptions { enabled?: boolean; /** OBV 등 누적 지표: 상장 이력에 가깝게 장기 캔들 로드 */ deepObvHistory?: boolean; + /** 직접 지정할 페치 봉 수 (deepObvHistory·WARMUP_COUNT 무시) */ + fetchCount?: number; } interface UseUpbitDataReturn { @@ -88,9 +90,8 @@ export function useUpbitData( const marketChanged = prevMarketRef.current !== '' && prevMarketRef.current !== market; prevMarketRef.current = market; - const fetchCount = opts.deepObvHistory - ? OBV_DEEP_HISTORY - : DISPLAY_COUNT + WARMUP_COUNT; + const fetchCount = opts.fetchCount + ?? (opts.deepObvHistory ? OBV_DEEP_HISTORY : DISPLAY_COUNT + WARMUP_COUNT); fetchUpbitCandlesCached(market, timeframe, fetchCount, marketChanged) .then(newBars => { @@ -108,7 +109,7 @@ export function useUpbitData( }); return () => { cancelled = true; }; - }, [market, timeframe, opts.enabled, opts.deepObvHistory]); + }, [market, timeframe, opts.enabled, opts.deepObvHistory, opts.fetchCount]); // ── 2. WebSocket: 실시간 체결 구독 ──────────────────────────────────── const handleMessage = useCallback((msg: UpbitMessage) => { diff --git a/frontend/src/utils/ChartManager.ts b/frontend/src/utils/ChartManager.ts index 0022566..dc8fa00 100644 --- a/frontend/src/utils/ChartManager.ts +++ b/frontend/src/utils/ChartManager.ts @@ -897,11 +897,8 @@ export class ChartManager { const fallbackColor = config.type === 'OBV' && plotDef.id === 'plot0' ? (regPlot?.color ?? '#2196F3') : (regPlot?.color ?? plotDef.color ?? '#2962FF'); - const resolvedColor = config.type === 'OBV' && plotDef.id === 'plot0' - ? '#FFFF00' - : resolvePlotLineColor(plotDef.color, fallbackColor); series = this.chart.addSeries(LineSeries, { - color: resolvedColor, + color: resolvePlotLineColor(plotDef.color, fallbackColor), lineWidth: (config.type === 'OBV' && plotDef.id === 'plot0' ? Math.max(2, plotDef.lineWidth ?? regPlot?.lineWidth ?? 2) : Math.max(1, plotDef.lineWidth ?? 1)) as 1 | 2 | 3 | 4, @@ -913,19 +910,6 @@ export class ChartManager { ...(indicatorPriceFormat ? { priceFormat: indicatorPriceFormat } : {}), }, pane); series.setData(filtered.map(p => ({ time: p.time as Time, value: p.value }))); - if (config.type === 'OBV') { - const p0 = result.plots['plot0'] as PlotData | undefined; - const p1 = result.plots['plot1'] as PlotData | undefined; - console.error( - `[OBV addIndicator] plotDef.id=${plotDef.id}`, - '| visible:', isPlotVisible, - '| filteredLen:', filtered.length, - '| first val:', filtered[0]?.value, - '| last val:', filtered[filtered.length - 1]?.value, - '| p0.length:', p0?.length, '| p1.length:', p1?.length, - '| pane:', pane, - ); - } seriesMeta.push({ plotId: plotDef.id, isHistogram: false, color: plotDef.color }); } @@ -2903,12 +2887,7 @@ export class ChartManager { const fallbackColor = entry.type === 'OBV' && pid === 'plot0' ? (regPlot?.color ?? '#2196F3') : (regPlot?.color ?? plot.color ?? '#aaa'); - opts['color'] = (entry.type === 'OBV' && pid === 'plot0') - ? '#FFFF00' - : resolvePlotLineColor(plot.color, fallbackColor); - if (entry.type === 'OBV') { - console.error(`[OBV applyStyle] pid=${pid} visible=${visible} color=${opts['color']}`); - } + opts['color'] = resolvePlotLineColor(plot.color, fallbackColor); opts['lineWidth'] = entry.type === 'OBV' && pid === 'plot0' ? Math.max(2, plot.lineWidth ?? regPlot?.lineWidth ?? 2) : Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1);