import { generateNodeId } from './strategyTypes'; export const START_NODE_ID = '__strategy_start__'; export const DEFAULT_START_CANDLE = '1m'; export const STRATEGY_CANDLE_TYPES = [ '1m', '3m', '5m', '10m', '15m', '30m', '1h', '4h', '1w', '1d', ] as const; /** 그래프 START 노드 — 시간봉 체크박스 2행 배치 */ export const START_TIMEFRAME_GRAPH_ROWS: readonly (readonly StrategyCandleType[])[] = [ ['1m', '3m', '5m', '10m', '15m'], ['30m', '1h', '4h', '1w', '1d'], ] as const; export type StrategyCandleType = (typeof STRATEGY_CANDLE_TYPES)[number]; export type StartNodeMeta = { /** @deprecated 단일 분봉 — candleTypes 우선 */ candleType?: string; /** 선택된 평가 시간봉 (마감봉마다 독립 체크) */ candleTypes?: string[]; }; /** START가 2개 이상일 때 분기 간 결합 연산 */ export type StartCombineOp = 'AND' | 'OR'; export const DEFAULT_START_COMBINE_OP: StartCombineOp = 'AND'; export function isStartNodeId(id: string): boolean { return id === START_NODE_ID || id.startsWith('__strategy_start_'); } export function createStartNodeId(): string { return `__strategy_start_${generateNodeId()}__`; } export function defaultStartMeta(): Record { return { [START_NODE_ID]: { candleTypes: [DEFAULT_START_CANDLE], candleType: DEFAULT_START_CANDLE } }; } /** START 메타에서 정렬된 평가 분봉 목록 (최소 1개) */ export function getStartCandleTypes(meta?: StartNodeMeta | null): string[] { const raw = meta?.candleTypes?.length ? meta.candleTypes : meta?.candleType ? [meta.candleType] : [DEFAULT_START_CANDLE]; const seen = new Set(); const out: string[] = []; for (const ct of STRATEGY_CANDLE_TYPES) { if (raw.some(r => normalizeStartCandleType(r) === ct) && !seen.has(ct)) { seen.add(ct); out.push(ct); } } for (const r of raw) { const n = normalizeStartCandleType(r); if (!seen.has(n)) { seen.add(n); out.push(n); } } return out.length > 0 ? out : [DEFAULT_START_CANDLE]; } export function formatStartCandleTypesLabel(types: string[]): string { const list = getStartCandleTypes({ candleTypes: types }); return list.map(formatStrategyCandleLabel).join(' · '); } export function normalizeStartCandleType(value: string | undefined | null): string { const raw = (value ?? DEFAULT_START_CANDLE).trim().toLowerCase(); if (raw === '1d' || raw === '1w') return raw; return (STRATEGY_CANDLE_TYPES as readonly string[]).includes(raw) ? raw : DEFAULT_START_CANDLE; } export function formatStartCandleLabel(candleType: string): string { return normalizeStartCandleType(candleType); } const CANDLE_TYPE_LABELS: Record = { '1m': '1분봉', '3m': '3분봉', '5m': '5분봉', '10m': '10분봉', '15m': '15분봉', '30m': '30분봉', '1h': '1시간봉', '4h': '4시간봉', '1w': '주간봉', '1d': '일봉', }; export function formatStrategyCandleLabel(candleType: string): string { const ct = normalizeStartCandleType(candleType); return CANDLE_TYPE_LABELS[ct] ?? ct; } export const STRATEGY_CANDLE_TYPE_OPTIONS = STRATEGY_CANDLE_TYPES.map(ct => ({ value: ct, label: CANDLE_TYPE_LABELS[ct] ?? ct, }));