import type { BacktestSignal } from './backendApi'; import { normalizeEpochSecOptional } from './backtestUiUtils'; export interface BarSignalHighlight { buy: boolean; sell: boolean; } const isBuySignalType = (type: BacktestSignal['type']): boolean => type === 'BUY' || type === 'SHORT_EXIT'; const isSellSignalType = (type: BacktestSignal['type']): boolean => type === 'SELL' || type === 'SHORT_ENTRY' || type === 'PARTIAL_SELL'; function signalMatchesBar( signal: BacktestSignal, barIndex: number, barTimeSec: number, ): boolean { if (signal.barIndex === barIndex) return true; const signalTime = normalizeEpochSecOptional(signal.time); const barTime = normalizeEpochSecOptional(barTimeSec); if (signalTime > 0 && barTime > 0 && signalTime === barTime) return true; return false; } /** 선택 봉에 백테스트 매매 시그널이 있는지 (차트 마커와 동일 기준) */ export function resolveBarSignalHighlight( signals: BacktestSignal[], barTimeSec: number | null | undefined, barIndex?: number | null, ): BarSignalHighlight { if (signals.length === 0) { return { buy: false, sell: false }; } if (barIndex == null || barIndex < 0) { if (barTimeSec == null) return { buy: false, sell: false }; const t = normalizeEpochSecOptional(barTimeSec); const atBar = signals.filter(s => normalizeEpochSecOptional(s.time) === t); return { buy: atBar.some(s => isBuySignalType(s.type)), sell: atBar.some(s => isSellSignalType(s.type)), }; } const barTime = barTimeSec ?? 0; const atBar = signals.filter(s => signalMatchesBar(s, barIndex, barTime)); return { buy: atBar.some(s => isBuySignalType(s.type)), sell: atBar.some(s => isSellSignalType(s.type)), }; }