가상투자 화면 추가
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots';
|
||||
import {
|
||||
buildConditionMetrics,
|
||||
computeMatchRate,
|
||||
formatUpdatedTime,
|
||||
getTrafficLightState,
|
||||
} from '../../utils/virtualSignalMetrics';
|
||||
import VirtualSignalEqualizer from './VirtualSignalEqualizer';
|
||||
import VirtualSignalTrafficLight from './VirtualSignalTrafficLight';
|
||||
import VirtualConditionList from './VirtualConditionList';
|
||||
import VirtualIndicatorCompareTable from './VirtualIndicatorCompareTable';
|
||||
import type { VirtualCardViewMode } from '../../utils/virtualTradingStorage';
|
||||
|
||||
interface Props {
|
||||
snapshot: VirtualIndicatorSnapshot | undefined;
|
||||
viewMode?: VirtualCardViewMode;
|
||||
receiving?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const VirtualTargetSignalPanel: React.FC<Props> = ({
|
||||
snapshot,
|
||||
viewMode = 'summary',
|
||||
receiving = false,
|
||||
className = '',
|
||||
}) => {
|
||||
const rows = snapshot?.rows ?? [];
|
||||
const isDetail = viewMode === 'detail';
|
||||
|
||||
const metrics = useMemo(() => buildConditionMetrics(rows), [rows]);
|
||||
const matchRate = useMemo(
|
||||
() => computeMatchRate(metrics, snapshot?.matchRate),
|
||||
[metrics, snapshot?.matchRate],
|
||||
);
|
||||
const trafficState = useMemo(() => getTrafficLightState(matchRate, metrics), [matchRate, metrics]);
|
||||
const metCount = metrics.filter(m => m.status === 'match').length;
|
||||
const evalCount = metrics.filter(m => m.status !== 'unknown').length;
|
||||
|
||||
if (rows.length === 0) {
|
||||
return (
|
||||
<p className={`vtd-muted vtd-card-empty${className ? ` ${className}` : ''}`}>
|
||||
전략 조건·지표 데이터 없음
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
'vtd-sig-panel-wrap',
|
||||
isDetail ? '' : 'vtd-sig-panel-wrap--summary',
|
||||
receiving ? 'vtd-sig-panel-wrap--receiving' : '',
|
||||
className,
|
||||
].filter(Boolean).join(' ')}
|
||||
>
|
||||
{isDetail && evalCount > 0 && (
|
||||
<div className="vtd-focus-sig-meta">
|
||||
<span className="vtd-card-met-count">{metCount}/{evalCount} 조건 충족</span>
|
||||
</div>
|
||||
)}
|
||||
<div className={`vtd-sig-panel${isDetail ? '' : ' vtd-sig-panel--summary'}`}>
|
||||
<div className="vtd-sig-panel-title">SIGNAL INTELLIGENCE & MATCH RATES</div>
|
||||
<div className="vtd-sig-visual">
|
||||
<div className="vtd-sig-visual-eq">
|
||||
<VirtualSignalEqualizer matchRate={matchRate} />
|
||||
</div>
|
||||
<VirtualConditionList metrics={metrics} />
|
||||
<VirtualSignalTrafficLight state={trafficState} matchRate={matchRate} />
|
||||
</div>
|
||||
{isDetail && <VirtualIndicatorCompareTable metrics={metrics} />}
|
||||
</div>
|
||||
<div className="vtd-card-foot">
|
||||
<span className="vtd-card-updated">갱신 {formatUpdatedTime(snapshot?.updatedAt)}</span>
|
||||
<span className="vtd-card-match-summary">매매조건 일치율 {matchRate}%</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VirtualTargetSignalPanel;
|
||||
Reference in New Issue
Block a user