From 2950442f69e79efdd1a979a09b39324a09274e4d Mon Sep 17 00:00:00 2001 From: Macbook Date: Tue, 2 Jun 2026 23:06:43 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=9D=BC=EB=AA=A9=20=EA=B5=AC=EB=A6=84?= =?UTF-8?q?=EC=9D=84=20rawBars=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=ED=95=B4=20dev/=ED=94=84=EB=A1=9C=EB=8D=95?= =?UTF-8?q?=EC=85=98=20=EB=8F=99=EC=9D=BC=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 서버 프로덕션 번들에서 lightweight-charts-indicators plot3·plot4가 spanA와 spanB에 동일 값을 줄 수 있어 구름이 사라짐. 로컬 vite dev는 정상. plot0~4 의존을 제거하고 OHLCV rawBars만으로 선행스팬·구름을 계산한다. Co-authored-by: Cursor --- frontend/src/utils/ChartManager.ts | 56 +++++++++++++----------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/frontend/src/utils/ChartManager.ts b/frontend/src/utils/ChartManager.ts index c3a8d38..c766514 100644 --- a/frontend/src/utils/ChartManager.ts +++ b/frontend/src/utils/ChartManager.ts @@ -1368,7 +1368,7 @@ export class ChartManager { return out; } - /** 특정 바 인덱스에서 Donchian 중선을 계산 */ + /** 특정 바 인덱스에서 Donchian 중선 (전환선·기준선·선행스팬B 공통) */ private _donchianAt(idx: number, period: number): number | null { const start = idx - period + 1; if (start < 0) return null; @@ -1378,35 +1378,33 @@ export class ChartManager { if (this.rawBars[i].low < lo) lo = this.rawBars[i].low; } return (hi + lo) / 2; - } - - /** 구름 데이터 빌드: 과거(역사 데이터) + 미래 26봉 포함 */ + } + + /** + * 일목 구름: rawBars만으로 계산 (vite dev / 프로덕션 번들 동일 결과). + * lightweight-charts-indicators 의 plot3·plot4는 서버 프로덕션 빌드에서 + * spanA===spanB 로 붕괴할 수 있어 사용하지 않는다. + */ private _buildIchimokuCloudData( - _spanAPlot: PlotData, - _spanBPlot: PlotData, - convPlot: PlotData, - basePlot: PlotData, + conversionPeriods: number, + basePeriods: number, displacement: number, laggingPeriod: number, ): IchimokuCloudPoint[] { - // 라이브러리의 plot3/plot4(SpanA/SpanB)는 프로덕션 빌드에서 - // 동일한 값을 반환하는 버그가 있으므로, convPlot(전환선)/basePlot(기준선)과 - // rawBars 기반 _donchianAt으로 직접 재계산한다. const N = this.rawBars.length; const historical: IchimokuCloudPoint[] = []; - for (let i = displacement - 1; i < N; i++) { - const srcIdx = i - (displacement - 1); - const conv = convPlot[srcIdx]?.value; - const base = basePlot[srcIdx]?.value; - if (conv == null || isNaN(conv) || base == null || isNaN(base)) continue; - const spanA = (conv + base) / 2; + for (let i = displacement; i < N; i++) { + const srcIdx = i - displacement; + const tenkan = this._donchianAt(srcIdx, conversionPeriods); + const kijun = this._donchianAt(srcIdx, basePeriods); + if (tenkan == null || kijun == null) continue; + const spanA = (tenkan + kijun) / 2; const spanB = this._donchianAt(srcIdx, laggingPeriod); - if (spanB === null) continue; + if (spanB == null) continue; historical.push({ time: this.rawBars[i].time, spanA, spanB }); } - // 미래 구름 if (N < 2) return historical; const interval = this.rawBars[N - 1].time - this.rawBars[N - 2].time; const lastTime = this.rawBars[N - 1].time; @@ -1415,12 +1413,12 @@ export class ChartManager { for (let k = 1; k <= displacement; k++) { const srcIdx = N - displacement - 1 + k; if (srcIdx < 0 || srcIdx >= N) continue; - const conv = convPlot[srcIdx]?.value; - const base = basePlot[srcIdx]?.value; - if (conv == null || isNaN(conv) || base == null || isNaN(base)) continue; - const spanA = (conv + base) / 2; + const tenkan = this._donchianAt(srcIdx, conversionPeriods); + const kijun = this._donchianAt(srcIdx, basePeriods); + if (tenkan == null || kijun == null) continue; + const spanA = (tenkan + kijun) / 2; const spanB = this._donchianAt(srcIdx, laggingPeriod); - if (spanB === null) continue; + if (spanB == null) continue; future.push({ time: lastTime + k * interval, spanA, spanB }); } return [...historical, ...future]; @@ -1782,17 +1780,13 @@ export class ChartManager { return; } - const spanAPlot = plots['plot3'] as PlotData | undefined; - const spanBPlot = plots['plot4'] as PlotData | undefined; - const convPlot = plots['plot0'] as PlotData ?? []; - const basePlot = plots['plot1'] as PlotData ?? []; - if (!spanAPlot || !spanBPlot) return; - const { senkou: displacement } = resolveIchimokuDisplacements(config.params); + const conversionPeriods = (config.params?.conversionPeriods as number) ?? 9; + const basePeriods = (config.params?.basePeriods as number) ?? 26; const laggingPeriod = (config.params?.laggingSpan2Periods as number) ?? 52; const cloud = this._buildIchimokuCloudData( - spanAPlot, spanBPlot, convPlot, basePlot, displacement, laggingPeriod, + conversionPeriods, basePeriods, displacement, laggingPeriod, ); plugin.setCloudData(cloud.length >= 2 ? cloud : []); }