import React, { useMemo } from 'react'; import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots'; import { buildConditionMetrics, type ConditionMetric, } from '../../utils/virtualSignalMetrics'; import VirtualSignalMatchVisual from '../virtual/VirtualSignalMatchVisual'; import type { BarSignalHighlight } from '../../utils/strategyEvaluationBarSignals'; interface Props { snapshot: VirtualIndicatorSnapshot | undefined; /** 선택 봉에 백테스트 매수/매도 시그널 존재 여부 */ barSignalHighlight?: BarSignalHighlight; loading?: boolean; loadingMessage?: string; hasStrategy?: boolean; className?: string; } interface SideCardProps { side: 'buy' | 'sell'; metrics: ConditionMetric[]; overallMet?: boolean | null; signalActive?: boolean; } const SideCard: React.FC = ({ side, metrics, overallMet, signalActive = false }) => { const title = side === 'buy' ? '매수 조건' : '매도 조건'; const overallLabel = overallMet === true ? '전체 충족' : overallMet === false ? '전체 미충족' : null; return (
{title} {overallLabel && ( {overallLabel} )}
); }; const StrategyEvaluationSignalPanel: React.FC = ({ snapshot, barSignalHighlight, loading = false, loadingMessage, hasStrategy = true, className = '', }) => { const rows = snapshot?.rows ?? []; const metrics = useMemo(() => buildConditionMetrics(rows), [rows]); const buyMetrics = useMemo(() => metrics.filter(m => m.row.side === 'buy'), [metrics]); const sellMetrics = useMemo(() => metrics.filter(m => m.row.side === 'sell'), [metrics]); if (rows.length === 0) { return (

{loading ? (loadingMessage ?? '지표 데이터 수집 중… (업비트 캔들 · 실시간 연결)') : !hasStrategy ? '투자전략을 선택하세요 (상단 또는 종목별 전략)' : '전략 조건·지표 데이터 없음'}

); } return (
); }; export default StrategyEvaluationSignalPanel;