macd 수정

This commit is contained in:
Macbook
2026-06-16 01:41:32 +09:00
parent aac0641c86
commit ddd6ecef80
+68 -24
View File
@@ -844,14 +844,59 @@ export class ChartManager {
return this._plotOrderForEntry(entry).map(plotId => {
const idx = entry.seriesMeta.findIndex(m => m.plotId === plotId);
if (idx < 0) return NaN;
const series = entry.seriesList[idx];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const d = params.seriesData.get(series) as any;
if (!d) return NaN;
return typeof d.value === 'number' ? d.value : NaN;
return this._seriesValueAtCrosshairTime(entry.seriesList[idx], params);
});
}
/** 전용 priceScale 시리즈는 params.seriesData 에 없을 수 있어 time 기준 fallback 조회 */
private _seriesValueAtCrosshairTime(
series: ISeriesApi<SeriesType>,
params: MouseEventParams<Time>,
): number {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const d = params.seriesData.get(series) as any;
if (d != null) {
if (typeof d.value === 'number' && Number.isFinite(d.value)) return d.value;
if (typeof d.close === 'number' && Number.isFinite(d.close)) return d.close;
}
if (params.time == null) return NaN;
return this._lookupSeriesValueAtTime(series, params.time as number);
}
private _lookupSeriesValueAtTime(
series: ISeriesApi<SeriesType>,
time: number,
): number {
try {
const data = series.data() as ReadonlyArray<{ time: Time; value?: number; close?: number }>;
if (!data.length) return NaN;
for (let i = data.length - 1; i >= 0; i--) {
const t = data[i].time as number;
if (t <= time) {
const v = data[i].value ?? data[i].close;
return typeof v === 'number' && Number.isFinite(v) ? v : NaN;
}
}
const v = data[0].value ?? data[0].close;
return typeof v === 'number' && Number.isFinite(v) ? v : NaN;
} catch {
return NaN;
}
}
/** 보조지표 전용 sub-pane (볼륨 숨김 시 pane 1 포함) */
private _isIndicatorSubPane(paneIndex: number): boolean {
return paneIndex >= this._minIndicatorSubPane();
}
private _showSeriesTitleOnChart(paneIndex: number): boolean {
return !this._isIndicatorSubPane(paneIndex);
}
private _hlineAxisLabelVisible(): boolean {
return this._indicatorAreaPriceLabelsEnabled;
}
/** OBV — plot0·plot1 항상 쌍으로 생성 (메인 차트와 동일, DUAL_LINE repair 경로 회피) */
private _addObvIndicatorSeries(
seriesList: ISeriesApi<SeriesType>[],
@@ -918,7 +963,7 @@ export class ChartManager {
const isPlotVisible = !indicatorHidden;
const showPriceLabel = this.shouldShowSeriesPriceLabel(enriched, true, pane);
const showSeriesTitle = pane < 2 && showPriceLabel;
const showSeriesTitle = this._showSeriesTitleOnChart(pane) && showPriceLabel;
const regPlot = def?.plots?.find(p => p.id === plotId);
const resolvedColor = resolvePlotLineColor(
@@ -995,13 +1040,14 @@ export class ChartManager {
? 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 showSeriesTitle = this._showSeriesTitleOnChart(pane) && showPriceLabel;
const regPlot = def?.plots?.find(p => p.id === plotDef.id);
const series = this.chart.addSeries(LineSeries, {
color: resolvePlotLineColor(plotDef.color, regPlot?.color ?? plotDef.color ?? '#2962FF'),
lineWidth: Math.max(1, plotDef.lineWidth ?? regPlot?.lineWidth ?? 1) as 1 | 2 | 3 | 4,
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
priceLineVisible: false,
crosshairMarkerVisible: true,
lastValueVisible: showPriceLabel,
title: showSeriesTitle ? this.seriesTitleForPlot(config, plotDef) : '',
visible: isPlotVisible,
@@ -1045,7 +1091,7 @@ export class ChartManager {
? 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 showSeriesTitle = this._showSeriesTitleOnChart(pane) && showPriceLabel;
const regPlot = def?.plots?.find(p => p.id === plotDef.id);
const series = this.chart.addSeries(LineSeries, {
color: resolvePlotLineColor(plotDef.color, regPlot?.color ?? plotDef.color ?? '#2962FF'),
@@ -1225,13 +1271,14 @@ export class ChartManager {
? 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 showSeriesTitle = this._showSeriesTitleOnChart(pane) && showPriceLabel;
const regPlot = def?.plots?.find(p => p.id === plotDef.id);
series = this.chart.addSeries(LineSeries, {
color: resolvePlotLineColor(plotDef.color, regPlot?.color ?? plotDef.color ?? '#2962FF'),
lineWidth: Math.max(1, plotDef.lineWidth ?? regPlot?.lineWidth ?? 1) as 1 | 2 | 3 | 4,
lineStyle: plotSeriesLineStyle(plotDef.lineStyle),
priceLineVisible: false,
crosshairMarkerVisible: true,
lastValueVisible: showPriceLabel,
title: showSeriesTitle ? this.seriesTitleForPlot(config, plotDef) : '',
visible: isPlotVisible,
@@ -1281,7 +1328,7 @@ export class ChartManager {
color: hl.color,
lineWidth: Math.min(4, hl.lineWidth ?? 1) as 1|2|3|4,
lineStyle: toLineStyle(hl.lineStyle),
axisLabelVisible: false,
axisLabelVisible: this._hlineAxisLabelVisible(),
});
hlineRefs.push(pl);
}
@@ -3561,9 +3608,9 @@ export class ChartManager {
plotAllowsLastValue = true,
paneIndex = 0,
): boolean {
const areaEnabled = paneIndex < 2
? this._candleAreaPriceLabelsEnabled
: this._indicatorAreaPriceLabelsEnabled;
const areaEnabled = this._isIndicatorSubPane(paneIndex)
? this._indicatorAreaPriceLabelsEnabled
: this._candleAreaPriceLabelsEnabled;
return areaEnabled
&& plotAllowsLastValue
&& config.lastValueVisible !== false;
@@ -3632,13 +3679,14 @@ export class ChartManager {
: Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1)) as 1 | 2 | 3 | 4)
: Math.max(1, plot.lineWidth ?? regPlot?.lineWidth ?? 1);
opts['lineStyle'] = plotSeriesLineStyle(plot.lineStyle);
opts['crosshairMarkerVisible'] = true;
let plotAllows = true;
if (entry.type === 'IchimokuCloud') {
plotAllows = entry.seriesMeta[i]?.plotId !== 'plot2';
}
const showPriceLabel = this.shouldShowSeriesPriceLabel(config, plotAllows, paneIdx);
opts['lastValueVisible'] = showPriceLabel && visible;
opts['title'] = paneIdx < 2 && showPriceLabel && visible
opts['title'] = this._showSeriesTitleOnChart(paneIdx) && showPriceLabel && visible
? this.seriesTitleForPlot(config, plot, plotAllows, paneIdx)
: '';
} else {
@@ -3678,7 +3726,7 @@ export class ChartManager {
color: hl.color,
lineWidth: Math.min(4, hl.lineWidth ?? 1) as 1|2|3|4,
lineStyle: toLineStyle2(hl.lineStyle),
axisLabelVisible: false,
axisLabelVisible: this._hlineAxisLabelVisible(),
});
entry.hlineRefs.push(pl);
}
@@ -4821,15 +4869,11 @@ export class ChartManager {
getIndicatorValuesFromParams(params: MouseEventParams<Time>): Record<string, number[]> {
const result: Record<string, number[]> = {};
for (const [, entry] of this.indicators) {
const values: number[] = [];
for (const series of entry.seriesList) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const d = params.seriesData.get(series) as any;
const v = d != null
? (typeof d.value === 'number' ? d.value : d.close ?? NaN)
: NaN;
values.push(v);
}
const values = this._plotOrderForEntry(entry).map(plotId => {
const idx = entry.seriesMeta.findIndex(m => m.plotId === plotId);
if (idx < 0) return NaN;
return this._seriesValueAtCrosshairTime(entry.seriesList[idx], params);
});
if (values.some(v => !isNaN(v))) {
result[entry.type] = values;
}