수정1
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user