This commit is contained in:
Macbook
2026-06-09 22:46:15 +09:00
parent 47e287c0f6
commit 222c6ecca8
2 changed files with 12 additions and 52 deletions
@@ -103,26 +103,6 @@ const TradeSignalMiniChart: React.FC<Props> = ({
applyNotificationSignalMarkers(mgr, signalMarkerRef.current, false); 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 syncChartLayout = useCallback(() => {
const wrap = canvasWrapRef.current; const wrap = canvasWrapRef.current;
const mgr = managerRef.current; const mgr = managerRef.current;
@@ -144,24 +124,13 @@ const TradeSignalMiniChart: React.FC<Props> = ({
} }
syncChartLayout(); syncChartLayout();
applySignalMarkers(); applySignalMarkers();
if (!mgr) return; }, [syncChartLayout, applySignalMarkers]);
void ensureObvDualLine();
[0, 100, 500, 1200].forEach(delay => {
setTimeout(() => {
void managerRef.current?.repairDualLineSeries();
void ensureObvDualLine();
}, delay);
});
}, [syncChartLayout, applySignalMarkers, ensureObvDualLine]);
const handleManagerReady = useCallback((mgr: ChartManager) => { const handleManagerReady = useCallback((mgr: ChartManager) => {
managerRef.current = mgr; managerRef.current = mgr;
syncToManager(mgr); syncToManager(mgr);
applySignalMarkers(); applySignalMarkers();
if (needsDeepObv) { }, [syncToManager, applySignalMarkers]);
void mgr.repairDualLineSeries().then(() => ensureObvDualLine());
}
}, [syncToManager, applySignalMarkers, needsDeepObv, ensureObvDualLine]);
const applyRealtimeBar = useCallback((bar: OHLCVBar, append: boolean) => { const applyRealtimeBar = useCallback((bar: OHLCVBar, append: boolean) => {
if (barsMarketRef.current !== marketRef.current) return; if (barsMarketRef.current !== marketRef.current) return;
@@ -216,19 +185,6 @@ const TradeSignalMiniChart: React.FC<Props> = ({
const chartDataReady = barsReady && obvBarsReady && settingsLoaded; 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(() => { useLayoutEffect(() => {
chartLiveReadyRef.current = false; chartLiveReadyRef.current = false;
pendingBarRef.current = null; pendingBarRef.current = null;
+10 -6
View File
@@ -753,7 +753,7 @@ export class ChartManager {
config: IndicatorConfig, config: IndicatorConfig,
def: ReturnType<typeof getIndicatorDef> | undefined, def: ReturnType<typeof getIndicatorDef> | undefined,
): string[] { ): string[] {
const plotDefs = config.plots ?? def?.plots ?? []; const plotDefs = def?.plots ?? config.plots ?? [];
return plotDefs return plotDefs
.filter(p => p.type !== 'histogram' && config.plotVisibility?.[p.id] !== false) .filter(p => p.type !== 'histogram' && config.plotVisibility?.[p.id] !== false)
.map(p => p.id); .map(p => p.id);
@@ -783,8 +783,11 @@ export class ChartManager {
indicatorHidden: boolean, indicatorHidden: boolean,
def: ReturnType<typeof getIndicatorDef>, def: ReturnType<typeof getIndicatorDef>,
): void { ): void {
const plotDefs = sortDualLinePlotDefs(config.plots ?? def?.plots ?? []) const regPlots = def?.plots ?? [];
.filter(p => p.type !== 'histogram' && config.plotVisibility?.[p.id] !== false); 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); const indicatorPriceFormat = priceFormatForIndicatorPane(pane);
for (const plotDef of plotDefs) { for (const plotDef of plotDefs) {
@@ -1092,7 +1095,7 @@ export class ChartManager {
this._setIndicatorPlotsFullData(entry, result.plots as Record<string, PlotData>, config); this._setIndicatorPlotsFullData(entry, result.plots as Record<string, PlotData>, config);
} }
} }
this.applyIndicatorStyle(config); this.applyIndicatorStyle(config, { skipDualLineRefresh: true });
if (config.type === 'BollingerBands' && !indicatorHidden) { if (config.type === 'BollingerBands' && !indicatorHidden) {
attachBbBandFill(entry, config, this._shouldShowBbBandFillForConfig(config)); attachBbBandFill(entry, config, this._shouldShowBbBandFillForConfig(config));
entry.bbFillPrimitive?.requestRefresh(); entry.bbFillPrimitive?.requestRefresh();
@@ -1165,7 +1168,7 @@ export class ChartManager {
this._setIndicatorPlotsFullData(entry, result.plots as Record<string, PlotData>, config); this._setIndicatorPlotsFullData(entry, result.plots as Record<string, PlotData>, config);
} catch { /* ok */ } } catch { /* ok */ }
} }
this.applyIndicatorStyle(config); this.applyIndicatorStyle(config, { skipDualLineRefresh: true });
} }
} }
@@ -1282,7 +1285,8 @@ export class ChartManager {
async refreshIndicators(configs: IndicatorConfig[]): Promise<void> { async refreshIndicators(configs: IndicatorConfig[]): Promise<void> {
if (configs.length === 0) return; if (configs.length === 0) return;
this.cancelPendingIndicatorUpdates(); this.cancelPendingIndicatorUpdates();
const loadGen = ++this._dataGeneration; /** setData 와 달리 generation 을 올리지 않음 — 배치 add 중 다른 지표 로드를 끊지 않음 */
const loadGen = this._dataGeneration;
let any = false; let any = false;
for (const c of configs) { for (const c of configs) {