From 222c6ecca8e091a1ed3de2cca5c55f7de93ce506 Mon Sep 17 00:00:00 2001 From: Macbook Date: Tue, 9 Jun 2026 22:46:15 +0900 Subject: [PATCH] =?UTF-8?q?=EC=88=98=EC=A0=951?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TradeSignalMiniChart.tsx | 48 +------------------ frontend/src/utils/ChartManager.ts | 16 ++++--- 2 files changed, 12 insertions(+), 52 deletions(-) diff --git a/frontend/src/components/tradeNotification/TradeSignalMiniChart.tsx b/frontend/src/components/tradeNotification/TradeSignalMiniChart.tsx index c8880dd..4e91ecb 100644 --- a/frontend/src/components/tradeNotification/TradeSignalMiniChart.tsx +++ b/frontend/src/components/tradeNotification/TradeSignalMiniChart.tsx @@ -103,26 +103,6 @@ const TradeSignalMiniChart: React.FC = ({ applyNotificationSignalMarkers(mgr, signalMarkerRef.current, false); }, []); - /** OBV plot0(본선) 누락 시 refreshIndicators 로 강제 재생성 */ - const ensureObvDualLine = useCallback(async (attempt = 0) => { - const mgr = managerRef.current; - if (!mgr?.hasMainSeries() || !needsDeepObv) return; - const obvCfg = chartIndicators.find(i => i.type === 'OBV'); - if (!obvCfg) return; - - await mgr.repairDualLineSeries(); - const plotIds = mgr.getIndicatorSeriesPlotIds(obvCfg.id); - const needsBoth = plotIds.length < 2 || !plotIds.includes('plot0'); - if (needsBoth && attempt < 4) { - await mgr.refreshIndicators([obvCfg]); - await mgr.repairDualLineSeries(); - const after = mgr.getIndicatorSeriesPlotIds(obvCfg.id); - if ((after.length < 2 || !after.includes('plot0')) && attempt < 3) { - setTimeout(() => void ensureObvDualLine(attempt + 1), 500 * (attempt + 1)); - } - } - }, [needsDeepObv, chartIndicators]); - const syncChartLayout = useCallback(() => { const wrap = canvasWrapRef.current; const mgr = managerRef.current; @@ -144,24 +124,13 @@ const TradeSignalMiniChart: React.FC = ({ } syncChartLayout(); applySignalMarkers(); - if (!mgr) return; - void ensureObvDualLine(); - [0, 100, 500, 1200].forEach(delay => { - setTimeout(() => { - void managerRef.current?.repairDualLineSeries(); - void ensureObvDualLine(); - }, delay); - }); - }, [syncChartLayout, applySignalMarkers, ensureObvDualLine]); + }, [syncChartLayout, applySignalMarkers]); const handleManagerReady = useCallback((mgr: ChartManager) => { managerRef.current = mgr; syncToManager(mgr); applySignalMarkers(); - if (needsDeepObv) { - void mgr.repairDualLineSeries().then(() => ensureObvDualLine()); - } - }, [syncToManager, applySignalMarkers, needsDeepObv, ensureObvDualLine]); + }, [syncToManager, applySignalMarkers]); const applyRealtimeBar = useCallback((bar: OHLCVBar, append: boolean) => { if (barsMarketRef.current !== marketRef.current) return; @@ -216,19 +185,6 @@ const TradeSignalMiniChart: React.FC = ({ const chartDataReady = barsReady && obvBarsReady && settingsLoaded; - useEffect(() => { - if (!enabled || !chartDataReady) return; - const mgr = managerRef.current; - if (!mgr?.hasMainSeries()) return; - const timers = [200, 800, 1600].map(delay => - setTimeout(() => { - void mgr.repairDualLineSeries(); - void ensureObvDualLine(); - }, delay), - ); - return () => timers.forEach(clearTimeout); - }, [enabled, chartDataReady, chartIndicators, market, timeframe, settingsRevision, ensureObvDualLine]); - useLayoutEffect(() => { chartLiveReadyRef.current = false; pendingBarRef.current = null; diff --git a/frontend/src/utils/ChartManager.ts b/frontend/src/utils/ChartManager.ts index b79fa99..a7eb079 100644 --- a/frontend/src/utils/ChartManager.ts +++ b/frontend/src/utils/ChartManager.ts @@ -753,7 +753,7 @@ export class ChartManager { config: IndicatorConfig, def: ReturnType | undefined, ): string[] { - const plotDefs = config.plots ?? def?.plots ?? []; + const plotDefs = def?.plots ?? config.plots ?? []; return plotDefs .filter(p => p.type !== 'histogram' && config.plotVisibility?.[p.id] !== false) .map(p => p.id); @@ -783,8 +783,11 @@ export class ChartManager { indicatorHidden: boolean, def: ReturnType, ): void { - const plotDefs = sortDualLinePlotDefs(config.plots ?? def?.plots ?? []) - .filter(p => p.type !== 'histogram' && config.plotVisibility?.[p.id] !== false); + const regPlots = def?.plots ?? []; + const styleById = Object.fromEntries((config.plots ?? regPlots).map(p => [p.id, p])); + const plotDefs = sortDualLinePlotDefs(regPlots) + .filter(p => p.type !== 'histogram' && config.plotVisibility?.[p.id] !== false) + .map(p => ({ ...p, ...styleById[p.id], id: p.id, title: p.title })); const indicatorPriceFormat = priceFormatForIndicatorPane(pane); for (const plotDef of plotDefs) { @@ -1092,7 +1095,7 @@ export class ChartManager { this._setIndicatorPlotsFullData(entry, result.plots as Record, config); } } - this.applyIndicatorStyle(config); + this.applyIndicatorStyle(config, { skipDualLineRefresh: true }); if (config.type === 'BollingerBands' && !indicatorHidden) { attachBbBandFill(entry, config, this._shouldShowBbBandFillForConfig(config)); entry.bbFillPrimitive?.requestRefresh(); @@ -1165,7 +1168,7 @@ export class ChartManager { this._setIndicatorPlotsFullData(entry, result.plots as Record, config); } catch { /* ok */ } } - this.applyIndicatorStyle(config); + this.applyIndicatorStyle(config, { skipDualLineRefresh: true }); } } @@ -1282,7 +1285,8 @@ export class ChartManager { async refreshIndicators(configs: IndicatorConfig[]): Promise { if (configs.length === 0) return; this.cancelPendingIndicatorUpdates(); - const loadGen = ++this._dataGeneration; + /** setData 와 달리 generation 을 올리지 않음 — 배치 add 중 다른 지표 로드를 끊지 않음 */ + const loadGen = this._dataGeneration; let any = false; for (const c of configs) {