/** * 보조지표 설정 편집 — 개별 모달·일괄 설정 팝업 공통 직렬화/초기화 */ import type { IndicatorConfig, HlinesBackground, Timeframe } from '../types'; import type { PlotDef, HLineDef } from './indicatorRegistry'; import { getIndicatorDef, mergePlotDefs, normalizeHLines, normalizeObvParams, enrichIndicatorConfig, } from './indicatorRegistry'; import { normalizeBollingerParams, DEFAULT_BB_BAND_BACKGROUND, resolveBbBandBackground, } from './bollingerConfig'; import { normalizeDmiParams } from './indicatorRegistry'; import { normalizeSmaConfig, createDefaultSmaParams, createDefaultSmaPlots, createDefaultSmaPlotVisibility, } from './smaConfig'; import { normalizeIchimokuConfig, createDefaultIchimokuParams, createDefaultIchimokuPlotVisibility, mergeIchimokuPlots, DEFAULT_ICHIMOKU_CLOUD_COLORS, resolveIchimokuCloudColors, type IchimokuCloudColors, } from './ichimokuConfig'; export const DEFAULT_HLINES_BG: HlinesBackground = { visible: true, color: '#787B8640' }; export interface IndicatorSettingsEditorSnapshot { params: Record; plots: PlotDef[]; plotVis: Record; hlines: HLineDef[]; hlinesBg: HlinesBackground; lastValueVisible: boolean; timeframeVis: Partial>; cloudColors: IchimokuCloudColors; bandBg: HlinesBackground; } /** 차트·DB 값으로 편집기 초기 config (개별 모달·일괄 팝업 동일) */ export function initializeIndicatorConfigForEditor( raw: IndicatorConfig, getParams?: (type: string, defaults: Record) => Record, getVisualConfig?: ( type: string, defaultPlots: PlotDef[], defaultHlines?: HLineDef[], ) => { plots: PlotDef[]; hlines: HLineDef[]; cloudColors?: IchimokuCloudColors; bandBackground?: HlinesBackground }, ): IndicatorConfig { const def = getIndicatorDef(raw.type); if (!def) return enrichIndicatorConfig(raw); const params = getParams ? { ...getParams(raw.type, def.defaultParams), ...raw.params } : { ...raw.params }; const visual = getVisualConfig?.(raw.type, def.plots, def.hlines); return enrichIndicatorConfig({ ...raw, params, plots: raw.plots?.length ? raw.plots : visual?.plots, hlines: raw.hlines?.length ? raw.hlines : visual?.hlines, cloudColors: raw.cloudColors ?? visual?.cloudColors, bandBackground: raw.bandBackground ?? visual?.bandBackground, }); } export function createEditorSnapshot(config: IndicatorConfig): IndicatorSettingsEditorSnapshot { const normalized = config.type === 'SMA' ? normalizeSmaConfig(config) : config.type === 'IchimokuCloud' ? normalizeIchimokuConfig(config) : config; const def = getIndicatorDef(config.type); const baseParams = config.type === 'SMA' || config.type === 'IchimokuCloud' ? { ...normalized.params } : { ...(def?.defaultParams ?? {}), ...normalized.params }; let params = baseParams; if (config.type === 'OBV') params = normalizeObvParams(baseParams); if (config.type === 'BollingerBands') params = normalizeBollingerParams(baseParams); if (config.type === 'DMI') params = normalizeDmiParams(baseParams); const basePlots: PlotDef[] = config.type === 'IchimokuCloud' ? mergeIchimokuPlots(normalized.plots, def?.plots ?? []) : mergePlotDefs(normalized.plots, def?.plots ?? []); const plotVis: Record = { ...normalized.plotVisibility }; const mergedParams = { ...(def?.defaultParams ?? {}), ...normalized.params }; for (const p of basePlots) { if (plotVis[p.id] === undefined) { plotVis[p.id] = normalized.plotVisibility?.[p.id] !== false; } } if ((config.type === 'CCI' || config.type === 'RSI') && mergedParams.maType === 'None') { plotVis.plot1 = false; } const baseHLines: HLineDef[] = config.hlines ?? def?.hlines ?? []; return { params, plots: basePlots.map(p => ({ ...p })), plotVis, hlines: normalizeHLines( baseHLines.map(h => ({ ...h, visible: h.visible !== false })), config.type, def?.hlines, ), hlinesBg: normalized.hlinesBackground ?? { ...DEFAULT_HLINES_BG }, lastValueVisible: normalized.lastValueVisible !== false, timeframeVis: { ...normalized.timeframeVisibility }, cloudColors: resolveIchimokuCloudColors(normalized.cloudColors), bandBg: resolveBbBandBackground(normalized.bandBackground), }; } /** 편집 스냅샷 → IndicatorConfig (저장·일괄 적용·실시간 onChange 공통) */ export function configFromEditorSnapshot( base: IndicatorConfig, snap: IndicatorSettingsEditorSnapshot, ): IndicatorConfig { const def = getIndicatorDef(base.type); const hasHLines = (def?.hlines ?? []).length > 0 || snap.hlines.length > 0; const tfVis = Object.values(snap.timeframeVis).some(v => v === false) ? snap.timeframeVis : undefined; const draft: IndicatorConfig = { ...base, params: snap.params, plots: snap.plots, plotVisibility: snap.plotVis, hlines: snap.hlines, hlinesBackground: hasHLines ? snap.hlinesBg : undefined, lastValueVisible: snap.lastValueVisible, timeframeVisibility: tfVis, ...(base.type === 'IchimokuCloud' ? { cloudColors: snap.cloudColors } : {}), }; if (base.type === 'SMA') return normalizeSmaConfig(draft); if (base.type === 'IchimokuCloud') return normalizeIchimokuConfig(draft); if (base.type === 'BollingerBands') { return enrichIndicatorConfig({ ...draft, params: normalizeBollingerParams(draft.params), bandBackground: snap.bandBg, }); } return enrichIndicatorConfig(draft); } /** 지표별 기본값 (id·hidden 유지) */ export function resetConfigToDefaults(config: IndicatorConfig): IndicatorConfig { const def = getIndicatorDef(config.type); if (!def) return config; if (config.type === 'SMA') { return normalizeSmaConfig({ ...config, params: createDefaultSmaParams(), plots: createDefaultSmaPlots(), plotVisibility: createDefaultSmaPlotVisibility(), hlines: [], hlinesBackground: undefined, lastValueVisible: true, timeframeVisibility: undefined, }); } if (config.type === 'IchimokuCloud') { return normalizeIchimokuConfig({ ...config, params: createDefaultIchimokuParams(), plots: def.plots.map(p => ({ ...p })), plotVisibility: createDefaultIchimokuPlotVisibility(), cloudColors: DEFAULT_ICHIMOKU_CLOUD_COLORS, hlines: [], hlinesBackground: undefined, lastValueVisible: true, timeframeVisibility: undefined, }); } const baseParams = { ...(def.defaultParams as Record) }; const plots = def.plots.map(p => ({ ...p })); const plotVis: Record = {}; for (const p of def.plots) plotVis[p.id] = true; let params = config.type === 'BollingerBands' ? normalizeBollingerParams(baseParams) : baseParams; const draft: IndicatorConfig = { ...config, params, plots, plotVisibility: plotVis, hlines: normalizeHLines( (def.hlines ?? []).map(h => ({ ...h, visible: h.visible !== false })), config.type, def.hlines, ), hlinesBackground: { ...DEFAULT_HLINES_BG }, lastValueVisible: true, timeframeVisibility: undefined, cloudColors: undefined, bandBackground: config.type === 'BollingerBands' ? { ...DEFAULT_BB_BAND_BACKGROUND } : undefined, }; return enrichIndicatorConfig(draft); }