This commit is contained in:
Macbook
2026-06-09 14:41:14 +09:00
parent a9312285c4
commit a72fd84158
+49 -8
View File
@@ -739,6 +739,41 @@ export class ChartManager {
}
/** 이중 plot 지표 — addIndicator 루프에서 누락된 plot 시리즈 추가 */
/**
* OBV pane y축 스케일을 최근 N봉 실제 값 기준으로 강제 고정.
* 과거에 OBV가 큰 값을 기록했어도 현재 구간이 y축 하단에 압축되지 않도록 방지.
*/
private _applyObvTightScale(
seriesList: ISeriesApi<SeriesType>[],
plots: Record<string, PlotData>,
recentCount = 60,
): void {
const allRecent: number[] = [];
for (const key of ['plot0', 'plot1']) {
const pts = (plots[key] ?? []).filter(p => p.value != null && isFinite(p.value as number));
const slice = pts.slice(-recentCount).map(p => p.value as number);
allRecent.push(...slice);
}
if (allRecent.length === 0) return;
const minV = Math.min(...allRecent);
const maxV = Math.max(...allRecent);
const span = Math.max(1, maxV - minV);
const pad = span * 0.3;
const tMin = minV - pad;
const tMax = maxV + pad;
for (const s of seriesList) {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(s as ISeriesApi<any>).applyOptions({
autoscaleInfoProvider: () => ({
priceRange: { minValue: tMin, maxValue: tMax },
margins: { above: 0, below: 0 },
}),
});
} catch { /* ok */ }
}
}
private _appendMissingPlotSeriesToLists(
seriesList: ISeriesApi<SeriesType>[],
seriesMeta: IndicatorEntry['seriesMeta'],
@@ -812,6 +847,9 @@ export class ChartManager {
indicatorHidden,
def,
);
if (config.type === 'OBV' && !indicatorHidden && entry.seriesList.length > 0) {
this._applyObvTightScale(entry.seriesList, result.plots as Record<string, PlotData>);
}
entry.config = config;
if (entry.seriesList.length > 0) {
const actualPane = this._readSeriesPaneIndex(entry.seriesList[0]);
@@ -911,14 +949,6 @@ export class ChartManager {
}, pane);
series.setData(filtered.map(p => ({ time: p.time as Time, value: p.value })));
seriesMeta.push({ plotId: plotDef.id, isHistogram: false, color: plotDef.color });
// OBV 디버그: 마지막 5개 값 출력
if (config.type === 'OBV') {
const last5 = filtered.slice(-5).map(p => p.value.toFixed(2));
const minV = Math.min(...filtered.map(p => p.value));
const maxV = Math.max(...filtered.map(p => p.value));
console.warn(`[OBV-DATA] ${plotDef.id} | last5=${last5.join(',')} | min=${minV.toFixed(2)} max=${maxV.toFixed(2)} | totalPts=${filtered.length}`);
}
}
seriesList.push(series);
@@ -936,6 +966,10 @@ export class ChartManager {
);
}
// OBV: 최근 50봉 값 기준으로 y축 고정 → 과거 큰 값에 의한 스케일 압축 방지
if (config.type === 'OBV' && !indicatorHidden && seriesList.length > 0) {
this._applyObvTightScale(seriesList, result.plots as Record<string, PlotData>);
}
// hlines(과열선/중앙선/침체선)는 첫 번째 시리즈에만 한 번 생성 (중복 방지)
const hlineRefs: IPriceLine[] = [];
@@ -1052,6 +1086,13 @@ export class ChartManager {
if (!DUAL_LINE_INDICATOR_TYPES.has(entry.type)) continue;
await this._ensureDualLinePlotSeriesForEntry(entry);
if (entry.config) this.applyIndicatorStyle(entry.config);
// OBV: tight scale 재적용 (스타일 갱신 후 autoscaleInfoProvider 덮어써질 수 있음)
if (entry.type === 'OBV' && entry.seriesList.length > 0 && this.rawBars.length > 0) {
try {
const result = await calculateIndicator('OBV', this.rawBars.slice(), entry.config?.params ?? {});
this._applyObvTightScale(entry.seriesList, result.plots as Record<string, PlotData>);
} catch { /* ok */ }
}
}
}