obv 그래프 수정
This commit is contained in:
@@ -217,6 +217,19 @@ function detachBbBandFill(entry: IndicatorEntry): void {
|
||||
/** OBV·CCI·RSI·TRIX — 본선+신호선 이중 plot (누락 시리즈 보정 대상) */
|
||||
const DUAL_LINE_INDICATOR_TYPES = new Set(['OBV', 'CCI', 'RSI', 'TRIX']);
|
||||
|
||||
const DUAL_LINE_PLOT_ORDER = ['plot0', 'plot1', 'plot2', 'plot3'];
|
||||
|
||||
function sortDualLinePlotDefs(plotDefs: PlotDef[]): PlotDef[] {
|
||||
return [...plotDefs].sort(
|
||||
(a, b) => DUAL_LINE_PLOT_ORDER.indexOf(a.id) - DUAL_LINE_PLOT_ORDER.indexOf(b.id),
|
||||
);
|
||||
}
|
||||
|
||||
/** OBV 본선(plot0) — DB plotVisibility·투명색으로 숨김 방지 */
|
||||
function isDualLinePlotForcedVisible(type: string, plotId: string): boolean {
|
||||
return type === 'OBV' && plotId === 'plot0';
|
||||
}
|
||||
|
||||
export class ChartManager {
|
||||
private chart: IChartApi;
|
||||
private container: HTMLElement;
|
||||
@@ -741,7 +754,7 @@ export class ChartManager {
|
||||
|
||||
for (const plotDef of plotDefs) {
|
||||
if (existingIds.has(plotDef.id)) continue;
|
||||
if (config.plotVisibility?.[plotDef.id] === false) continue;
|
||||
if (config.plotVisibility?.[plotDef.id] === false && !isDualLinePlotForcedVisible(config.type, plotDef.id)) continue;
|
||||
if (plotDef.type === 'histogram') continue;
|
||||
|
||||
const plotData = result.plots[plotDef.id] as PlotData | undefined;
|
||||
@@ -750,9 +763,10 @@ export class ChartManager {
|
||||
if (filtered.length === 0) continue;
|
||||
|
||||
const isPlotVisible = !indicatorHidden
|
||||
&& (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud')
|
||||
? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id)
|
||||
: config.plotVisibility?.[plotDef.id] !== false);
|
||||
&& (isDualLinePlotForcedVisible(config.type, plotDef.id)
|
||||
|| (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud')
|
||||
? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id)
|
||||
: config.plotVisibility?.[plotDef.id] !== false));
|
||||
const showPriceLabel = this.shouldShowSeriesPriceLabel(config, true, pane);
|
||||
const showSeriesTitle = pane < 2 && showPriceLabel;
|
||||
const regPlot = def?.plots?.find(p => p.id === plotDef.id);
|
||||
@@ -851,7 +865,10 @@ export class ChartManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const plotDefs = config.plots ?? def?.plots ?? [];
|
||||
const plotDefsRaw = config.plots ?? def?.plots ?? [];
|
||||
const plotDefs = DUAL_LINE_INDICATOR_TYPES.has(config.type)
|
||||
? sortDualLinePlotDefs(plotDefsRaw)
|
||||
: plotDefsRaw;
|
||||
|
||||
for (const plotDef of plotDefs) {
|
||||
const plotData = result.plots[plotDef.id] as PlotData | undefined;
|
||||
@@ -870,15 +887,21 @@ export class ChartManager {
|
||||
seriesMeta.push({ plotId: plotDef.id, isHistogram: true, color: plotDef.color });
|
||||
} else {
|
||||
const isPlotVisible = !indicatorHidden
|
||||
&& (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud')
|
||||
? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id)
|
||||
: config.plotVisibility?.[plotDef.id] !== false);
|
||||
&& (isDualLinePlotForcedVisible(config.type, plotDef.id)
|
||||
|| (this._isCustomOverlayApplied() && (config.type === 'SMA' || config.type === 'BollingerBands' || config.type === 'IchimokuCloud')
|
||||
? isCustomPlotSelected(this._getAppliedCustomOverlaySelection(), config.type, plotDef.id)
|
||||
: config.plotVisibility?.[plotDef.id] !== false));
|
||||
const showPriceLabel = this.shouldShowSeriesPriceLabel(config, true, pane);
|
||||
const showSeriesTitle = pane < 2 && showPriceLabel;
|
||||
const regPlot = def?.plots?.find(p => p.id === plotDef.id);
|
||||
const fallbackColor = config.type === 'OBV' && plotDef.id === 'plot0'
|
||||
? (regPlot?.color ?? '#2196F3')
|
||||
: (regPlot?.color ?? plotDef.color ?? '#2962FF');
|
||||
series = this.chart.addSeries(LineSeries, {
|
||||
color: resolvePlotLineColor(plotDef.color, regPlot?.color ?? plotDef.color ?? '#2962FF'),
|
||||
lineWidth: Math.max(1, plotDef.lineWidth ?? 1) as 1 | 2 | 3 | 4,
|
||||
color: resolvePlotLineColor(plotDef.color, fallbackColor),
|
||||
lineWidth: (config.type === 'OBV' && plotDef.id === 'plot0'
|
||||
? Math.max(2, plotDef.lineWidth ?? regPlot?.lineWidth ?? 2)
|
||||
: Math.max(1, plotDef.lineWidth ?? 1)) as 1 | 2 | 3 | 4,
|
||||
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
|
||||
priceLineVisible: false,
|
||||
lastValueVisible: showPriceLabel,
|
||||
@@ -956,6 +979,9 @@ export class ChartManager {
|
||||
return;
|
||||
}
|
||||
this.indicators.set(config.id, entry);
|
||||
if (DUAL_LINE_INDICATOR_TYPES.has(config.type)) {
|
||||
await this._ensureDualLinePlotSeriesForEntry(entry);
|
||||
}
|
||||
this.applyIndicatorStyle(config);
|
||||
if (config.type === 'BollingerBands' && !indicatorHidden) {
|
||||
attachBbBandFill(entry, config, this._shouldShowBbBandFillForConfig(config));
|
||||
@@ -1011,6 +1037,15 @@ export class ChartManager {
|
||||
this._notifyPaneLayout();
|
||||
}
|
||||
|
||||
/** OBV·RSI 등 본선(plot0) 시리즈 누락 시 재생성 (미니 차트·스타일 갱신 후) */
|
||||
async repairDualLineSeries(): Promise<void> {
|
||||
for (const entry of this.indicators.values()) {
|
||||
if (!DUAL_LINE_INDICATOR_TYPES.has(entry.type)) continue;
|
||||
await this._ensureDualLinePlotSeriesForEntry(entry);
|
||||
if (entry.config) this.applyIndicatorStyle(entry.config);
|
||||
}
|
||||
}
|
||||
|
||||
/** 여러 지표 추가 후 pane 레이아웃을 한 번만 갱신 */
|
||||
async addIndicatorsBatch(configs: IndicatorConfig[]): Promise<void> {
|
||||
for (const config of configs) {
|
||||
@@ -2617,6 +2652,7 @@ export class ChartManager {
|
||||
/** custom 미적용 시 지표 설정 plotVisibility, 적용 시 custom 선택만 반영 */
|
||||
private _resolveSeriesVisible(config: IndicatorConfig, plotId: string | undefined): boolean {
|
||||
if (!plotId || !this._isIndicatorEffectivelyVisible(config)) return false;
|
||||
if (isDualLinePlotForcedVisible(config.type, plotId)) return true;
|
||||
if (!this._isCustomOverlayApplied()) {
|
||||
return config.plotVisibility?.[plotId] !== false;
|
||||
}
|
||||
@@ -2847,8 +2883,13 @@ export class ChartManager {
|
||||
}
|
||||
if (!entry.seriesMeta[i]?.isHistogram) {
|
||||
const regPlot = def?.plots?.find(p => p.id === pid);
|
||||
opts['color'] = resolvePlotLineColor(plot.color, regPlot?.color ?? plot.color ?? '#aaa');
|
||||
opts['lineWidth'] = Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1);
|
||||
const fallbackColor = entry.type === 'OBV' && pid === 'plot0'
|
||||
? (regPlot?.color ?? '#2196F3')
|
||||
: (regPlot?.color ?? plot.color ?? '#aaa');
|
||||
opts['color'] = resolvePlotLineColor(plot.color, fallbackColor);
|
||||
opts['lineWidth'] = entry.type === 'OBV' && pid === 'plot0'
|
||||
? Math.max(2, plot.lineWidth ?? regPlot?.lineWidth ?? 2)
|
||||
: Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1);
|
||||
opts['lineStyle'] = plotSeriesLineStyle(plot.lineStyle);
|
||||
let plotAllows = true;
|
||||
if (entry.type === 'IchimokuCloud') {
|
||||
|
||||
Reference in New Issue
Block a user