단순이동평균선 이름 표시방식 변경

This commit is contained in:
Macbook
2026-06-13 01:36:03 +09:00
parent 207374a08e
commit beeebed8f4
13 changed files with 106 additions and 51 deletions
+6 -3
View File
@@ -1,4 +1,4 @@
import { SMA_MA_COUNT, smaPlotId } from './smaConfig';
import { SMA_MA_COUNT, smaPlotId, formatSmaMaDisplayLabel } from './smaConfig';
/** Custom / Custom1 — 동일 기능, 설정만 분리 (세션만, DB 미저장) */
export type ChartCustomOverlaySlotId = 'custom' | 'custom1';
@@ -70,8 +70,11 @@ export function cloneChartCustomOverlaySelection(
};
}
export function smaMaLabel(plotIndex: number): string {
return `MA${plotIndex + 1}`;
export function smaMaLabel(
plotIndex: number,
params?: Record<string, number | string | boolean>,
): string {
return formatSmaMaDisplayLabel(params, plotIndex + 1);
}
export const ICHIMOKU_CUSTOM_ROWS: Array<{
+1
View File
@@ -231,6 +231,7 @@ export function getParamLabel(key: string, indicatorType?: string): string {
}
export function getPlotLabel(title: string): string {
if (/^MA\d+일$/.test(title) || /^EMA\d+일$/.test(title)) return title;
const pair = PLOT_LABELS[title];
if (pair) return bilingual(pair);
return bilingual({ ko: title, en: title });
+1 -1
View File
@@ -54,7 +54,7 @@ export const MAIN_INDICATOR_LABELS: Record<string, { ko: string; en: string }> =
Psychological: { ko: '심리도', en: 'Psychological Line' },
NewPsychological: { ko: '신심리도', en: 'New Psychological Line' },
InvestPsychological: { ko: '투자심리도', en: 'Invest Psychological Line' },
SMA: { ko: '단순 이동평균 (MA1~MA11)', en: 'Simple Moving Average' },
SMA: { ko: '단순 이동평균', en: 'Simple Moving Average' },
};
export function isMainIndicatorType(type: string): boolean {
+1 -1
View File
@@ -268,7 +268,7 @@ export interface IndicatorDef {
export const INDICATOR_REGISTRY: IndicatorDef[] = [
// ── Moving Averages ──────────────────────────────────────────────────────
{ type:'SMA', name:'Simple Moving Average', koreanName:'단순이동평균', shortName:'SMA', category:'Moving Averages', overlay:true, defaultParams:createDefaultSmaParams(), plots:createDefaultSmaPlots(), description:'단순 이동평균 (MA1~MA11)' },
{ type:'SMA', name:'Simple Moving Average', koreanName:'단순이동평균', shortName:'SMA', category:'Moving Averages', overlay:true, defaultParams:createDefaultSmaParams(), plots:createDefaultSmaPlots(), description:'단순 이동평균 (MA{기간}일 × 11)' },
{ type:'EMA', name:'Exponential Moving Average', koreanName:'지수이동평균', shortName:'EMA', category:'Moving Averages', overlay:true, defaultParams:{length:21, src:'close'}, plots:[{id:'plot0',title:'EMA', color:'#FF6D00',type:'line',lineWidth:2}], description:'지수 이동평균' },
{ type:'WMA', name:'Weighted Moving Average', koreanName:'가중이동평균', shortName:'WMA', category:'Moving Averages', overlay:true, defaultParams:{length:20, src:'close'}, plots:[{id:'plot0',title:'WMA', color:'#00BCD4',type:'line',lineWidth:2}], description:'가중 이동평균' },
{ type:'HMA', name:'Hull Moving Average', koreanName:'헐이동평균', shortName:'HMA', category:'Moving Averages', overlay:true, defaultParams:{length:16, src:'close'}, plots:[{id:'plot0',title:'HMA', color:'#4CAF50',type:'line',lineWidth:2}], description:'헐 이동평균 (래그 최소)' },
+15 -18
View File
@@ -4,7 +4,7 @@
* - MA3 → period3 (예: 20일)
* - MA20 → 레거시: 숫자>11 이면 기간 20일 그대로
*/
import { SMA_DEFAULT_PERIODS, SMA_MA_COUNT } from './smaConfig';
import { SMA_DEFAULT_PERIODS, SMA_MA_COUNT, formatSmaPeriodDisplayLabel } from './smaConfig';
export const MA_DSL_SLOT_MAX = SMA_MA_COUNT;
@@ -45,7 +45,14 @@ export function resolveMaDslFieldPeriod(
return null;
}
/** UI·해석용 라벨 — MA5(60일) */
/** EMA 설정 기간 → EMA5일 */
export function formatEmaPeriodDisplayLabel(period: number | string | boolean | undefined): string {
const raw = typeof period === 'number' ? period : Number(period);
const p = Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 1;
return `EMA${p}`;
}
/** UI·해석용 라벨 — MA20일 */
export function formatMaDslFieldLabel(
field: string | undefined,
smaParams?: Record<string, number | string | boolean>,
@@ -53,18 +60,8 @@ export function formatMaDslFieldLabel(
if (!field) return '';
const period = resolveMaDslFieldPeriod(field, smaParams);
if (period == null) return field;
const ma = /^MA(\d+)$/.exec(field);
if (ma && !field.startsWith('MACD')) {
const n = parseInt(ma[1], 10);
if (n >= 1 && n <= MA_DSL_SLOT_MAX) return `MA${n}(${period}일)`;
return `MA(${period}일)`;
}
const ema = /^EMA(\d+)$/.exec(field);
if (ema) {
const n = parseInt(ema[1], 10);
if (n >= 1 && n <= MA_DSL_SLOT_MAX) return `EMA${n}(${period}일)`;
return `EMA(${period}일)`;
}
if (field.startsWith('EMA')) return formatEmaPeriodDisplayLabel(period);
if (field.startsWith('MA') && !field.startsWith('MACD')) return formatSmaPeriodDisplayLabel(period);
return field;
}
@@ -74,7 +71,7 @@ export function buildMaFieldOptions(
return Array.from({ length: SMA_MA_COUNT }, (_, i) => {
const slot = i + 1;
const p = maLines[i] ?? SMA_DEFAULT_PERIODS[i];
return { value: `MA${slot}`, label: `MA${slot}(${p}일)` };
return { value: `MA${slot}`, label: formatSmaPeriodDisplayLabel(p) };
});
}
@@ -86,7 +83,7 @@ export function buildEmaFieldOptions(
return Array.from({ length: n }, (_, i) => {
const slot = i + 1;
const p = maLines[i] ?? SMA_DEFAULT_PERIODS[i];
return { value: `EMA${slot}`, label: `EMA${slot}(${p}일)` };
return { value: `EMA${slot}`, label: formatEmaPeriodDisplayLabel(p) };
});
}
@@ -102,14 +99,14 @@ export function appendLegacyMaFieldOption(
if (ma && !field.startsWith('MACD')) {
const n = parseInt(ma[1], 10);
if (n > MA_DSL_SLOT_MAX) {
return [...opts, { value: field, label: `MA(${period}일)` }];
return [...opts, { value: field, label: formatSmaPeriodDisplayLabel(period) }];
}
}
const ema = /^EMA(\d+)$/.exec(field);
if (ema) {
const n = parseInt(ema[1], 10);
if (n > MA_DSL_SLOT_MAX) {
return [...opts, { value: field, label: `EMA(${period}일)` }];
return [...opts, { value: field, label: formatEmaPeriodDisplayLabel(period) }];
}
}
return opts;
+42 -3
View File
@@ -40,10 +40,49 @@ export function smaPeriodKey(maIndex: number): string {
return `period${maIndex}`;
}
/** 설정 기간 → 표시명 MA5일 (보조지표·차트·전략 공통) */
export function formatSmaPeriodDisplayLabel(
period: number | string | boolean | undefined,
fallback = SMA_DEFAULT_PERIODS[0],
): string {
const raw = typeof period === 'number' ? period : Number(period);
const p = Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : fallback;
return `MA${p}`;
}
export function resolveSmaMaPeriod(
params: Record<string, number | string | boolean> | undefined,
maIndex: number,
): number {
const slot = Math.max(1, Math.min(SMA_MA_COUNT, Math.floor(maIndex)));
const raw = params?.[smaPeriodKey(slot)];
if (typeof raw === 'number' && raw > 0) return Math.floor(raw);
return SMA_DEFAULT_PERIODS[slot - 1];
}
/** MA 슬롯(1~11) + params → MA5일 */
export function formatSmaMaDisplayLabel(
params: Record<string, number | string | boolean> | undefined,
maIndex: number,
): string {
return formatSmaPeriodDisplayLabel(resolveSmaMaPeriod(params, maIndex));
}
/** params 변경 시 plot.title 을 MA{period}일 로 동기화 */
export function syncSmaPlotTitles(
params: Record<string, number | string | boolean>,
plots: PlotDef[],
): PlotDef[] {
return plots.map((plot, i) => ({
...plot,
title: formatSmaMaDisplayLabel(params, i + 1),
}));
}
export function createDefaultSmaPlots(): PlotDef[] {
return SMA_DEFAULT_PERIODS.map((_, i) => ({
return SMA_DEFAULT_PERIODS.map((period, i) => ({
id: smaPlotId(i),
title: `MA${i + 1}`,
title: formatSmaPeriodDisplayLabel(period),
color: SMA_DEFAULT_COLORS[i],
type: 'line',
lineWidth: 2,
@@ -114,7 +153,7 @@ export function normalizeSmaConfig(config: IndicatorConfig): IndicatorConfig {
const plots: PlotDef[] = defaultPlots.map((def, i) => {
const saved = savedById.get(def.id) ?? config.plots?.[i];
return saved
? { ...def, ...saved, id: def.id, title: `MA${i + 1}`, type: 'line' as const }
? { ...def, ...saved, id: def.id, title: formatSmaMaDisplayLabel(params, i + 1), type: 'line' as const }
: def;
});