import { resolveVirtualTargetNames } from './virtualTargetNames'; import { getUiPreferences, patchUiPreferences } from './uiPreferencesDb'; import { DEFAULT_TRADE_NOTIFICATION_GRID_PRESET, normalizeTradeNotificationGridPreset, type TradeNotificationGridPresetId, } from './tradeNotificationGridPresets'; /** 가상투자 대상 종목·세션 설정 (DB ui_preferences + per-market live settings) */ export interface VirtualTargetItem { market: string; strategyId: number | null; koreanName?: string; englishName?: string; /** 투자대상 고정 — 추세검색 자동삭제 등에서 보호 (수동 삭제는 가능, gc_live_strategy_settings.is_pinned) */ pinned?: boolean; } export interface VirtualSessionConfig { globalStrategyId: number | null; executionType: 'CANDLE_CLOSE' | 'REALTIME_TICK'; /** LONG_ONLY = 보유 자산 기준, SIGNAL_ONLY = 순수 지표 기준 */ positionMode: 'LONG_ONLY' | 'SIGNAL_ONLY'; running: boolean; } /** 카드 표시: summary=이퀄라이저·신호등·푸터만, detail=지표 테이블 포함 전체 */ export type VirtualCardViewMode = 'summary' | 'detail'; function defaultSession(): VirtualSessionConfig { return { globalStrategyId: null, executionType: 'CANDLE_CLOSE', positionMode: 'LONG_ONLY', running: false, }; } /** 레거시 ui_preferences.virtual.targets.candleType 제거 */ function normalizeTargets(items: VirtualTargetItem[]): VirtualTargetItem[] { return items.map(t => { const { koreanName, englishName } = resolveVirtualTargetNames( t.market, t.koreanName, t.englishName, ); return { market: t.market, strategyId: t.strategyId ?? null, koreanName, englishName, pinned: t.pinned, }; }); } export function loadVirtualTargets(): VirtualTargetItem[] { const raw = getUiPreferences().virtual?.targets; if (!raw?.length) return []; return normalizeTargets(raw); } export function saveVirtualTargets(items: VirtualTargetItem[]): void { patchUiPreferences({ virtual: { targets: normalizeTargets(items) } }); notifyVirtualSessionChanged(); } export function loadVirtualSession(): VirtualSessionConfig { const parsed = getUiPreferences().virtual?.session; if (!parsed) return defaultSession(); return { globalStrategyId: parsed.globalStrategyId ?? null, executionType: parsed.executionType === 'REALTIME_TICK' ? 'REALTIME_TICK' : 'CANDLE_CLOSE', positionMode: parsed.positionMode === 'SIGNAL_ONLY' ? 'SIGNAL_ONLY' : 'LONG_ONLY', running: parsed.running === true, }; } export function saveVirtualSession(cfg: VirtualSessionConfig): void { patchUiPreferences({ virtual: { session: cfg } }); notifyVirtualSessionChanged(); } export const VIRTUAL_SESSION_CHANGED_EVENT = 'gc_virtual_session_changed'; export function notifyVirtualSessionChanged(): void { window.dispatchEvent(new CustomEvent(VIRTUAL_SESSION_CHANGED_EVENT)); } export function loadVirtualCardViewMode(): VirtualCardViewMode { const mode = getUiPreferences().virtual?.cardViewMode; return mode === 'detail' ? 'detail' : 'summary'; } export function saveVirtualCardViewMode(mode: VirtualCardViewMode): void { patchUiPreferences({ virtual: { cardViewMode: mode } }); } export function loadVirtualGridPreset(): TradeNotificationGridPresetId { return normalizeTradeNotificationGridPreset( getUiPreferences().virtual?.gridPreset ?? DEFAULT_TRADE_NOTIFICATION_GRID_PRESET, ); } export function saveVirtualGridPreset(preset: TradeNotificationGridPresetId): void { patchUiPreferences({ virtual: { gridPreset: preset } }); }