diff --git a/frontend/src/hooks/useHistoryLoader.ts b/frontend/src/hooks/useHistoryLoader.ts index 1fa79f9..015c997 100644 --- a/frontend/src/hooks/useHistoryLoader.ts +++ b/frontend/src/hooks/useHistoryLoader.ts @@ -3,9 +3,9 @@ * * 차트를 왼쪽으로 스크롤할 때 과거 캔들 데이터를 추가로 불러오는 훅. * - * 데이터 소스 우선순위: - * 1. 백엔드 GET /api/candles/history (Ta4jStorage + 업비트 REST 프록시 + RSI 포함) - * 2. 백엔드 호출 실패 시 → 업비트 REST 직접 폴백 + * 데이터 소스: + * 백엔드 GET /api/candles/history (Ta4jStorage + 업비트 REST 프록시 + RSI 포함) + * 백엔드 실패 시 → 추가 로드 중단 (Upbit 직접 호출 없음) * * 중복 방지 락(Lock): * loadingRef = true 인 동안에는 동일 타임스탬프 중복 요청을 원천 차단. @@ -20,7 +20,6 @@ import type { RefObject, MutableRefObject } from 'react'; import type { ChartManager } from '../utils/ChartManager'; import { toHistoryApiIso } from '../utils/analysisChartData'; import { timeframeToCandleType } from '../utils/chartCandleType'; -import { fetchUpbitCandlesBeforeCached } from '../utils/requestCache'; import type { OHLCVBar, Timeframe } from '../types'; /** 이 값(바 인덱스)보다 왼쪽에 가시 범위의 시작이 오면 추가 로드 트리거 */ @@ -147,18 +146,15 @@ export function useHistoryLoader({ setIsLoadingMore(true); try { + // 백엔드 /api/candles/history 에서만 로드 — Upbit 직접 호출 없음 let olderBars: OHLCVBar[]; - - // ── 1. 백엔드 /api/candles/history 우선 시도 ────────────────────────── try { olderBars = await fetchHistoryFromBackend(symbol, candleType, beforeIso, LOAD_BATCH); console.debug(`[HistoryLoader] 백엔드에서 ${olderBars.length}개 수신 (${candleType})`); } catch (backendErr) { - // ── 2. 백엔드 실패 시 업비트 REST 직접 폴백 ─────────────────────── - console.warn('[HistoryLoader] 백엔드 실패, 업비트 직접 폴백:', backendErr); - olderBars = await fetchUpbitCandlesBeforeCached( - symbol, timeframe, LOAD_BATCH, beforeIso, - ); + console.warn('[HistoryLoader] 백엔드 실패, 추가 로드 건너뜀:', backendErr); + hasMoreRef.current = false; + return; } if (olderBars.length === 0) { diff --git a/frontend/src/hooks/useStompChartData.ts b/frontend/src/hooks/useStompChartData.ts index 245b86a..578a1c9 100644 --- a/frontend/src/hooks/useStompChartData.ts +++ b/frontend/src/hooks/useStompChartData.ts @@ -10,14 +10,6 @@ import { getCandleStart, TF_SECONDS } from '../utils/upbitApi'; import { DISPLAY_COUNT, WARMUP_COUNT, OBV_DEEP_HISTORY } from './useUpbitData'; import type { WsStatus } from './useUpbitData'; import { API_BASE } from '../utils/backendApi'; -import { fetchUpbitCandlesCached } from '../utils/requestCache'; - -/** 초기 렌더 최소 봉 수 — 미만이면 업비트 REST 폴백 */ -const MIN_INITIAL_BARS = Math.min(50, Math.floor(DISPLAY_COUNT / 4)); - -function barsHaveVolume(bars: OHLCVBar[]): boolean { - return bars.some(b => (Number(b.volume) || 0) > 0); -} /** 백엔드 BarBuilder 는 틱마다 1m 만 STOMP 발행 — 차트 분봉은 클라이언트에서 집계 */ const STOMP_TICK_CANDLE_TYPE = '1m'; @@ -110,50 +102,22 @@ async function fetchInitialBarsWithRetry( throw lastErr ?? new Error('history fetch failed'); } -/** 백엔드 history → 부족·거래량 0·실패 시 업비트 REST 폴백 */ +/** + * 백엔드 /api/candles/history 에서만 초기 캔들을 로드한다. + * Upbit REST 직접 호출을 하지 않음 — 백엔드가 데이터를 아직 쌓지 못한 경우 + * 빈 배열을 반환하고, 호출부에서 STOMP bootstrap 경로로 처리한다. + */ async function loadInitialBars( market: string, timeframe: Timeframe, count: number, - marketChanged: boolean, - preferUpbit = false, ): Promise { const candleType = timeframeToCandleType(timeframe); - const upbitCount = Math.min(count, OBV_DEEP_HISTORY); - - if (preferUpbit) { - try { - const upbit = await fetchUpbitCandlesCached(market, timeframe, upbitCount, marketChanged); - if (upbit.length >= MIN_INITIAL_BARS && barsHaveVolume(upbit)) return upbit; - } catch { - /* Upbit 실패 시 backend 시도 */ - } - } - - let bars: OHLCVBar[] = []; try { - bars = await fetchInitialBarsWithRetry(market, candleType, count); + return await fetchInitialBarsWithRetry(market, candleType, count); } catch { - bars = []; + return []; } - - const needsUpbitFallback = bars.length < MIN_INITIAL_BARS || !barsHaveVolume(bars); - if (needsUpbitFallback) { - try { - const fallback = await fetchUpbitCandlesCached( - market, - timeframe, - upbitCount, - marketChanged, - ); - if (fallback.length > bars.length || (barsHaveVolume(fallback) && !barsHaveVolume(bars))) { - bars = fallback; - } - } catch { - /* 폴백 실패 시 backend 결과 유지 */ - } - } - return bars; } export function useStompChartData( @@ -180,8 +144,6 @@ export function useStompChartData( const historyReadyRef = useRef(false); /** 백엔드 history 비어 있을 때 STOMP 누적 → React bars 동기화 */ const bootstrapFromStompRef = useRef(false); - const prevMarketRef = useRef(''); - useEffect(() => { if (opts.enabled === false) return; let cancelled = false; @@ -196,13 +158,10 @@ export function useStompChartData( last1mTimeRef.current = 0; lastTimeRef.current = 0; - const marketChanged = prevMarketRef.current !== '' && prevMarketRef.current !== market; - prevMarketRef.current = market; - const count = opts.deepObvHistory ? OBV_DEEP_HISTORY : DISPLAY_COUNT + WARMUP_COUNT; - loadInitialBars(market, timeframe, count, marketChanged, opts.deepObvHistory === true) + loadInitialBars(market, timeframe, count) .then(newBars => { if (cancelled) return; barsRef.current = newBars;