macd 추가수정

This commit is contained in:
Macbook
2026-06-16 01:29:42 +09:00
parent ea13347be8
commit 52300379c4
2 changed files with 59 additions and 8 deletions
+3 -3
View File
@@ -43,7 +43,7 @@ import {
} from './chartTimeFormat'; } from './chartTimeFormat';
import { DEFAULT_DISPLAY_TIMEZONE, getTimezoneOffsetSec } from './timezone'; import { DEFAULT_DISPLAY_TIMEZONE, getTimezoneOffsetSec } from './timezone';
import { getPaneHostId, sortIndicatorsForPaneLoad } from './indicatorPaneMerge'; import { getPaneHostId, sortIndicatorsForPaneLoad } from './indicatorPaneMerge';
import { calculateIndicator, enrichIndicatorConfig, getIndicatorDef, getHLineLabel, type PlotData, type MarkerData } from './indicatorRegistry'; import { calculateIndicator, enrichIndicatorConfig, getIndicatorDef, getHLineLabel, resolveHLineDrawPrice, type PlotData, type MarkerData } from './indicatorRegistry';
import { filterObvPlotDataForChart } from './customIndicators'; import { filterObvPlotDataForChart } from './customIndicators';
import { IchimokuCloudPlugin, type IchimokuCloudPoint } from './IchimokuCloudPlugin'; import { IchimokuCloudPlugin, type IchimokuCloudPoint } from './IchimokuCloudPlugin';
@@ -1249,7 +1249,7 @@ export class ChartManager {
for (const hl of hlines) { for (const hl of hlines) {
if (hl.visible === false) continue; if (hl.visible === false) continue;
const pl = hlineHost.createPriceLine({ const pl = hlineHost.createPriceLine({
price: hl.price, price: resolveHLineDrawPrice(config.type, hl, hlines),
color: hl.color, color: hl.color,
lineWidth: Math.min(4, hl.lineWidth ?? 1) as 1|2|3|4, lineWidth: Math.min(4, hl.lineWidth ?? 1) as 1|2|3|4,
lineStyle: toLineStyle(hl.lineStyle), lineStyle: toLineStyle(hl.lineStyle),
@@ -3558,7 +3558,7 @@ export class ChartManager {
for (const hl of hlines) { for (const hl of hlines) {
if (hl.visible === false) continue; if (hl.visible === false) continue;
const pl = hlineHost.createPriceLine({ const pl = hlineHost.createPriceLine({
price: hl.price, price: resolveHLineDrawPrice(config.type, hl, hlines),
color: hl.color, color: hl.color,
lineWidth: Math.min(4, hl.lineWidth ?? 1) as 1|2|3|4, lineWidth: Math.min(4, hl.lineWidth ?? 1) as 1|2|3|4,
lineStyle: toLineStyle2(hl.lineStyle), lineStyle: toLineStyle2(hl.lineStyle),
+56 -5
View File
@@ -157,6 +157,10 @@ export function mergeHlines(
? savedList[0] ? savedList[0]
: undefined; : undefined;
const defRoleLabels = new Set(
defs.map(d => d.label ?? getHLineLabel(d.price, defs.map(x => x.price))),
);
return defs return defs
.map(def => { .map(def => {
const wantLabel = def.label ?? getHLineLabel(def.price, defs.map(d => d.price)); const wantLabel = def.label ?? getHLineLabel(def.price, defs.map(d => d.price));
@@ -172,7 +176,9 @@ export function mergeHlines(
.concat( .concat(
savedList.filter(h => { savedList.filter(h => {
const lbl = labelOf(h); const lbl = labelOf(h);
return !defs.some(d => (d.label ?? getHLineLabel(d.price, defs.map(x => x.price))) === lbl); if (defRoleLabels.has(lbl)) return false;
// registry에 없는 역할(잘못 분류된 과열/침체 orphan)은 제거 — 종가가 과열선으로 저장되는 MACD 버그 방지
return defRoleLabels.size > 1;
}).map(h => ({ ...h, label: labelOf(h) })), }).map(h => ({ ...h, label: labelOf(h) })),
) )
.sort((a, b) => b.price - a.price); .sort((a, b) => b.price - a.price);
@@ -254,19 +260,64 @@ export function normalizeHLines(
/** registry 기본 중앙선이 0인 지표에서 잘못 저장된 중앙선 가격을 0으로 고정 */ /** registry 기본 중앙선이 0인 지표에서 잘못 저장된 중앙선 가격을 0으로 고정 */
function clampZeroCenterHLines(hlines: HLineDef[], defaults?: HLineDef[]): HLineDef[] { function clampZeroCenterHLines(hlines: HLineDef[], defaults?: HLineDef[]): HLineDef[] {
const defPrices = (defaults ?? []).map(d => d.price); const defs = defaults ?? [];
const defCenter = (defaults ?? []).find( const defPrices = defs.map(d => d.price);
const defCenter = defs.find(
d => (d.label ?? getHLineLabel(d.price, defPrices)) === '중앙선', d => (d.label ?? getHLineLabel(d.price, defPrices)) === '중앙선',
); );
if (defCenter?.price !== 0) return hlines; if (defCenter?.price !== 0) return hlines;
const prices = hlines.map(h => h.price); const defPriceSet = new Set(defPrices);
return hlines.map(h => { let list = hlines;
// MACD·AO 등 중앙 0선 단일 def — registry에 없는 가격(종가 orphan) 제거
if (defs.length === 1 && defs[0].price === 0) {
const orphanWasVisible = hlines.some(h => {
const prices = hlines.map(x => x.price);
const lbl = h.label ?? getHLineLabel(h.price, prices);
return lbl !== '중앙선' && h.visible !== false && !defPriceSet.has(h.price);
});
list = hlines.filter(h => {
const prices = hlines.map(x => x.price);
const lbl = h.label ?? getHLineLabel(h.price, prices);
if (lbl === '중앙선') return true;
return defPriceSet.has(h.price);
});
if (orphanWasVisible) {
list = list.map(h => {
const prices = list.map(x => x.price);
const lbl = h.label ?? getHLineLabel(h.price, prices);
return lbl === '중앙선' ? { ...h, visible: true } : h;
});
}
}
const prices = list.map(h => h.price);
return list.map(h => {
const lbl = h.label ?? getHLineLabel(h.price, prices); const lbl = h.label ?? getHLineLabel(h.price, prices);
return lbl === '중앙선' ? { ...h, price: 0 } : h; return lbl === '중앙선' ? { ...h, price: 0 } : h;
}); });
} }
/** 차트 draw 시 hline 실제 가격 — 중앙 0선 지표는 항상 0 */
export function resolveHLineDrawPrice(
indicatorType: string,
hl: HLineDef,
allHlines: HLineDef[],
): number {
const def = getIndicatorDef(indicatorType);
const defaults = def?.hlines ?? [];
const defPrices = defaults.map(d => d.price);
const prices = allHlines.map(h => h.price);
const lbl = hl.label ?? getHLineLabel(hl.price, prices);
const defCenter = defaults.find(
d => (d.label ?? getHLineLabel(d.price, defPrices)) === '중앙선',
);
if (lbl === '중앙선' && defCenter?.price === 0) {
return 0;
}
return hl.price;
}
export interface IndicatorDef { export interface IndicatorDef {
type: string; type: string;
name: string; name: string;