obv 수정

This commit is contained in:
Macbook
2026-06-09 22:04:30 +09:00
parent 0a7d547ea9
commit 27c60be1e9
3 changed files with 74 additions and 42 deletions
+54 -40
View File
@@ -748,23 +748,18 @@ export class ChartManager {
return loadGen !== this._dataGeneration;
}
/** OBV — RSI/CCI와 동일한 공유 price scale, 이전 autoscale 오버라이드 제거 */
private _resetObvSharedScale(entry: IndicatorEntry): void {
if (entry.type !== 'OBV') return;
for (const s of entry.seriesList) {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(s as ISeriesApi<any>).applyOptions({ autoscaleInfoProvider: undefined });
} catch { /* ok */ }
}
const anchor = entry.seriesList[0];
if (!anchor) return;
try {
anchor.priceScale().applyOptions({
visible: true,
scaleMargins: { top: 0.1, bottom: 0.1 },
});
} catch { /* ok */ }
/** 이중 plot 지표에서 누락된 plotId 목록 (series 개수만으로는 plot0 누락 감지 불가) */
private _dualLineMissingPlotIds(
entry: IndicatorEntry,
config: IndicatorConfig,
def: ReturnType<typeof getIndicatorDef> | undefined,
): string[] {
const plotDefs = config.plots ?? def?.plots ?? [];
const existing = new Set(entry.seriesMeta.map(m => m.plotId));
return plotDefs
.filter(p => p.type !== 'histogram' && config.plotVisibility?.[p.id] !== false)
.map(p => p.id)
.filter(id => !existing.has(id));
}
private _appendMissingPlotSeriesToLists(
@@ -813,17 +808,13 @@ export class ChartManager {
}
}
/** 스타일 갱신·초기 추가 후 OBV 등 본선(plot0) 시리즈 누락 보정 */
/** 스타일 갱신·초기 추가 후 OBV 등 본선(plot0) 시리즈 누락 보정 + 전체 setData */
private async _ensureDualLinePlotSeriesForEntry(entry: IndicatorEntry): Promise<void> {
if (!DUAL_LINE_INDICATOR_TYPES.has(entry.type)) return;
const config = enrichIndicatorConfig(entry.config!);
const def = getIndicatorDef(config.type);
if (!def) return;
const plotDefs = config.plots ?? def.plots ?? [];
const expectedCount = plotDefs.filter(
p => p.type !== 'histogram' && config.plotVisibility?.[p.id] !== false,
).length;
if (entry.seriesList.length >= expectedCount) return;
if (this._dualLineMissingPlotIds(entry, config, def).length === 0) return;
if (this.rawBars.length === 0) return;
const pane = entry.paneIndex ?? this._readSeriesPaneIndex(entry.seriesList[0]) ?? 2;
@@ -839,8 +830,8 @@ export class ChartManager {
indicatorHidden,
def,
);
if (config.type === 'OBV' && !indicatorHidden && entry.seriesList.length > 0) {
this._resetObvSharedScale(entry);
if (entry.seriesList.length > 0) {
this._setIndicatorPlotsFullData(entry, result.plots as Record<string, PlotData>, config);
}
entry.config = config;
if (entry.seriesList.length > 0) {
@@ -952,12 +943,12 @@ export class ChartManager {
);
}
if (config.type === 'OBV' && !indicatorHidden && seriesList.length > 0) {
const obvEntry: IndicatorEntry = {
if (DUAL_LINE_INDICATOR_TYPES.has(config.type) && !indicatorHidden && seriesList.length > 0) {
const dualEntry: IndicatorEntry = {
id: config.id, type: config.type, seriesList, seriesMeta,
paneIndex: pane, alertLines: [], hlineRefs: [], config,
};
this._resetObvSharedScale(obvEntry);
this._setIndicatorPlotsFullData(dualEntry, result.plots as Record<string, PlotData>, config);
}
// hlines(과열선/중앙선/침체선)는 첫 번째 시리즈에만 한 번 생성 (중복 방지)
@@ -1013,6 +1004,9 @@ export class ChartManager {
this.indicators.set(config.id, entry);
if (DUAL_LINE_INDICATOR_TYPES.has(config.type)) {
await this._ensureDualLinePlotSeriesForEntry(entry);
if (entry.seriesList.length > 0 && !indicatorHidden) {
this._setIndicatorPlotsFullData(entry, result.plots as Record<string, PlotData>, config);
}
}
this.applyIndicatorStyle(config);
if (config.type === 'BollingerBands' && !indicatorHidden) {
@@ -1069,15 +1063,20 @@ export class ChartManager {
this._notifyPaneLayout();
}
/** OBV·RSI 등 본선(plot0) 시리즈 누락 시 재생성 (미니 차트·스타일 갱신 후) */
/** OBV·RSI 등 본선(plot0) 시리즈 누락 시 재생성 + 전체 plot setData */
async repairDualLineSeries(): Promise<void> {
for (const entry of this.indicators.values()) {
if (!DUAL_LINE_INDICATOR_TYPES.has(entry.type)) continue;
if (!DUAL_LINE_INDICATOR_TYPES.has(entry.type) || !entry.config) continue;
await this._ensureDualLinePlotSeriesForEntry(entry);
if (entry.config) this.applyIndicatorStyle(entry.config);
if (entry.type === 'OBV' && entry.seriesList.length > 0) {
this._resetObvSharedScale(entry);
}
if (entry.seriesList.length === 0 || this.rawBars.length === 0) continue;
try {
const config = enrichIndicatorConfig(entry.config);
const result = await calculateIndicator(
config.type, this.rawBars.slice(), config.params ?? {},
);
this._setIndicatorPlotsFullData(entry, result.plots as Record<string, PlotData>, config);
this.applyIndicatorStyle(config);
} catch { /* ok */ }
}
}
@@ -1087,6 +1086,7 @@ export class ChartManager {
await this.addIndicator(config, { skipLayout: true });
}
if (configs.length > 0) {
await this.repairDualLineSeries();
this._finalizeIndicatorPaneLayout();
this._refreshAllIchimokuClouds();
this.syncChartOverlayVisibility();
@@ -1876,8 +1876,17 @@ export class ChartManager {
for (const [, entry] of this.indicators.entries()) {
if (dataGenAtStart !== this._dataGeneration) return;
if (!entry.config || entry.seriesList.length === 0) continue;
if (!entry.config) continue;
try {
if (DUAL_LINE_INDICATOR_TYPES.has(entry.type)) {
const config = enrichIndicatorConfig(entry.config);
const def = getIndicatorDef(entry.type);
if (this._dualLineMissingPlotIds(entry, config, def).length > 0) {
await this._ensureDualLinePlotSeriesForEntry(entry);
}
}
if (entry.seriesList.length === 0) continue;
const { plots } = await calculateIndicator(
entry.config.type, barsSnapshot, entry.config.params ?? {}
);
@@ -2099,8 +2108,17 @@ export class ChartManager {
const barsSnapshot = this.rawBars.slice();
for (const [, entry] of this.indicators.entries()) {
if (dataGenAtStart !== this._dataGeneration) return;
if (!entry.config || entry.seriesList.length === 0) continue;
if (!entry.config) continue;
try {
if (DUAL_LINE_INDICATOR_TYPES.has(entry.type)) {
const config = enrichIndicatorConfig(entry.config);
const def = getIndicatorDef(entry.type);
if (this._dualLineMissingPlotIds(entry, config, def).length > 0) {
await this._ensureDualLinePlotSeriesForEntry(entry);
}
}
if (entry.seriesList.length === 0) continue;
const { plots } = await calculateIndicator(
entry.config.type, barsSnapshot, entry.config.params ?? {}
);
@@ -2984,10 +3002,6 @@ export class ChartManager {
}
}
if (entry.type === 'OBV' && entry.seriesList.length > 0) {
this._resetObvSharedScale(entry);
}
if (entry.type === 'BollingerBands') {
detachBbBandFill(entry);
if (this._shouldShowBbBandFillForConfig(config)) {
+4 -1
View File
@@ -479,7 +479,10 @@ function normalizeSignalLineIndicatorPlots(
const order = ['plot0', 'plot1'];
return order.indexOf(a.id) - order.indexOf(b.id);
});
return { plots: nextPlots, plotVisibility: { ...plotVisibility } };
const nextVis = { ...plotVisibility };
if (nextVis.plot0 !== false) nextVis.plot0 = true;
if (nextVis.plot1 !== false) nextVis.plot1 = true;
return { plots: nextPlots, plotVisibility: nextVis };
}
const regSignal = registryPlots.find(p => p.id === 'plot1');