전략분봉 저장 에러 문제 수정
This commit is contained in:
@@ -147,6 +147,8 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
const prevBarsKey = useRef<string>('');
|
||||
const prevIndKey = useRef<string>('');
|
||||
const prevSortedPKRef = useRef<string>(''); // 순서 무관 paramKey (reorder 감지용)
|
||||
const prevMarket = useRef<string>(market);
|
||||
const prevMarketTf = useRef<Timeframe>(timeframe);
|
||||
const prevChartType = useRef<ChartType>(chartType);
|
||||
const prevTheme = useRef<Theme>(theme);
|
||||
const prevLogScale = useRef<boolean>(logScale);
|
||||
@@ -252,6 +254,8 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
}, [candleOnlyMode, chartMgr, applyPaneLayout]);
|
||||
|
||||
// ── 전체 재로드 (데이터 + 인디케이터) ─────────────────────────────────────
|
||||
const reloadSafetyTimers = useRef<ReturnType<typeof setTimeout>[]>([]);
|
||||
|
||||
const reloadAll = useCallback(async (
|
||||
mgr: ChartManager,
|
||||
newBars: OHLCVBar[],
|
||||
@@ -262,11 +266,14 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
) => {
|
||||
if (newBars.length === 0) return;
|
||||
|
||||
reloadSafetyTimers.current.forEach(clearTimeout);
|
||||
reloadSafetyTimers.current = [];
|
||||
|
||||
barsRef.current = newBars;
|
||||
prevChartType.current = ct;
|
||||
prevTheme.current = th;
|
||||
prevLogScale.current = ls;
|
||||
prevBarsKey.current = barsKey(newBars);
|
||||
prevBarsKey.current = barsKey(newBars, market);
|
||||
prevIndKey.current = indKey(inds);
|
||||
prevSortedPKRef.current = sortedParamKey(inds);
|
||||
|
||||
@@ -275,15 +282,12 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
mgr.setLogScale(ls);
|
||||
mgr.setDisplayTimezone(displayTimezone, timeframe);
|
||||
|
||||
// 인디케이터를 순차적으로 등록 (async/await 보장)
|
||||
for (const ind of inds) {
|
||||
await mgr.addIndicator(ind);
|
||||
}
|
||||
|
||||
// 인디케이터 추가 완료 후 RAF × 2 대기
|
||||
// → LWC 가 모든 pane 을 DOM 에 확정한 뒤 높이·X축 재설정
|
||||
await new Promise<void>(resolve => requestAnimationFrame(() => requestAnimationFrame(() => {
|
||||
applyPaneLayout(mgr); // ① pane 높이 재배분 (wrapper 높이 기준, 0이면 자동 재시도)
|
||||
applyPaneLayout(mgr);
|
||||
requestAnimationFrame(() => {
|
||||
const futureBars = mgr.hasIchimoku() ? 28 : 0;
|
||||
mgr.setInitialVisibleRange(DISPLAY_COUNT, futureBars);
|
||||
@@ -291,12 +295,9 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
});
|
||||
})));
|
||||
|
||||
// 데이터 로드 완료 알림: 멀티차트 sync range 재적용 등 외부 콜백 처리용
|
||||
onDataLoaded?.();
|
||||
|
||||
// ── 안전망: 멀티레이아웃에서 CSS Grid 높이 확정이 늦어진 경우를 위한 지연 재적용
|
||||
// applyPaneLayout 이 이미 재시도 중이지만, setInitialVisibleRange 도 재실행 필요할 수 있음
|
||||
const safetyTimers = [300, 700, 1400].map(delay =>
|
||||
reloadSafetyTimers.current = [300, 700, 1400].map(delay =>
|
||||
setTimeout(() => {
|
||||
const m = managerRef.current;
|
||||
if (!m || !m.hasMainSeries()) return;
|
||||
@@ -307,10 +308,7 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
m.setInitialVisibleRange(DISPLAY_COUNT, fb);
|
||||
}, delay)
|
||||
);
|
||||
// cleanup 시 타이머 해제 (컴포넌트 언마운트 대응)
|
||||
// 반환값이 없으므로 managerRef 체크로 충분
|
||||
void safetyTimers; // 타이머는 managerRef null 체크로 자동 무효화됨
|
||||
}, [applyPaneLayout, onDataLoaded]);
|
||||
}, [applyPaneLayout, onDataLoaded, displayTimezone, timeframe, market]);
|
||||
|
||||
// ── 차트 초기화 (마운트 시 1회) ──────────────────────────────────────────
|
||||
useEffect(() => {
|
||||
@@ -592,6 +590,8 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
clearTimeout(drawingSingleTimerRef.current);
|
||||
drawingSingleTimerRef.current = null;
|
||||
}
|
||||
reloadSafetyTimers.current.forEach(clearTimeout);
|
||||
reloadSafetyTimers.current = [];
|
||||
ro.disconnect();
|
||||
managerRef.current?.destroy();
|
||||
managerRef.current = null;
|
||||
@@ -604,6 +604,14 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
managerRef.current?.setDisplayTimezone(displayTimezone, timeframe);
|
||||
}, [displayTimezone, timeframe]);
|
||||
|
||||
// 종목·타임프레임 변경 시 barsKey 캐시만 초기화 (reloadAll 은 bars effect 에서 1회만)
|
||||
useEffect(() => {
|
||||
if (prevMarket.current === market && prevMarketTf.current === timeframe) return;
|
||||
prevMarket.current = market;
|
||||
prevMarketTf.current = timeframe;
|
||||
prevBarsKey.current = '';
|
||||
}, [market, timeframe]);
|
||||
|
||||
// ── 데이터/인디케이터 동기화 ─────────────────────────────────────────────
|
||||
useEffect(() => {
|
||||
const mgr = managerRef.current;
|
||||
@@ -615,7 +623,7 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const bk = barsKey(bars);
|
||||
const bk = barsKey(bars, market);
|
||||
const ik = indKey(indicators);
|
||||
const barsChanged = bk !== prevBarsKey.current;
|
||||
const indChanged = ik !== prevIndKey.current;
|
||||
@@ -905,11 +913,10 @@ const PaneLegendPortal: React.FC<
|
||||
};
|
||||
|
||||
// ── 변경 감지용 키 생성 헬퍼 ────────────────────────────────────────────────
|
||||
function barsKey(bars: OHLCVBar[]): string {
|
||||
function barsKey(bars: OHLCVBar[], market = ''): string {
|
||||
if (bars.length === 0) return '';
|
||||
const last = bars[bars.length - 1];
|
||||
// 종목이 달라도 시간 범위·개수가 같을 수 있으므로 마지막 close 가격도 포함
|
||||
return `${bars.length}:${bars[0].time}:${last.time}:${last.close}`;
|
||||
return `${market}:${bars.length}:${bars[0].time}:${last.time}:${last.close}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user