전략분봉 저장 에러 문제 수정

This commit is contained in:
Macbook
2026-05-23 21:08:46 +09:00
parent eaf067db1c
commit 70ac67afe7
18 changed files with 2445 additions and 498 deletions
+24 -17
View File
@@ -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}`;
}
/**