import type { TrendSearchConditionDto, TrendSearchResultDto } from './trendSearchApi'; import type { ConditionMetric, ConditionStatus } from './virtualSignalMetrics'; import type { VirtualConditionRow } from './virtualStrategyConditions'; export function buildTrendSearchMetrics(conditions: TrendSearchConditionDto[]): ConditionMetric[] { return conditions.map(c => { const status: ConditionStatus = c.status === 'match' ? 'match' : c.status === 'pending' ? 'pending' : 'nomatch'; const row: VirtualConditionRow & { currentValue: number | null } = { id: c.id, indicatorType: c.category, displayName: c.label, conditionType: 'GTE', conditionLabel: c.label, targetValue: null, timeframe: '1d', side: 'buy', plotKey: c.id, satisfied: c.status === 'match' ? true : c.status === 'mismatch' ? false : null, thresholdLabel: c.thresholdLabel, currentValue: c.currentValue ?? null, }; return { row, status, matchRate: c.progress, progress: c.progress, }; }); } export function tfLabelShort(tf: string): string { if (tf === '1M') return '1M'; if (tf.endsWith('m')) return `${tf.replace('m', '')}분`; if (tf.endsWith('h')) return `${tf.replace('h', '')}시간`; if (tf.endsWith('d')) return `${tf.replace('d', '')}일`; if (tf.endsWith('w')) return `${tf.replace('w', '')}주`; return tf; } /** 추세강도(점수) 내림차순 정렬 */ export function sortTrendSearchByStrength( results: TrendSearchResultDto[], ): TrendSearchResultDto[] { return [...results].sort((a, b) => { if (b.matchRate !== a.matchRate) return b.matchRate - a.matchRate; return a.market.localeCompare(b.market); }); }