분석 레포트 화면 수정
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 백테스팅 · 투자분석 — 거래 시그널 테이블
|
||||
*/
|
||||
import React, { useState } from 'react';
|
||||
import type { BacktestSignal } from '../../utils/backendApi';
|
||||
import { repairUtf8Mojibake } from '../../utils/textEncoding';
|
||||
import { SectionTitle } from '../shared/analysisDashboardUi';
|
||||
|
||||
const SIG_LABEL: Record<string, string> = {
|
||||
BUY: '매수',
|
||||
SELL: '매도',
|
||||
SHORT_ENTRY: '공매도',
|
||||
SHORT_EXIT: '공매도청산',
|
||||
PARTIAL_SELL: '분할매도',
|
||||
};
|
||||
const SIG_COLOR: Record<string, string> = {
|
||||
BUY: 'brd-sig-buy',
|
||||
SELL: 'brd-sig-sell',
|
||||
SHORT_ENTRY: 'brd-neg',
|
||||
SHORT_EXIT: 'brd-pos',
|
||||
PARTIAL_SELL: 'brd-warn',
|
||||
};
|
||||
|
||||
const fmtDate = (ts: number) => {
|
||||
const d = new Date(ts * 1000);
|
||||
return `${d.getFullYear()}.${String(d.getMonth() + 1).padStart(2, '0')}.${String(d.getDate()).padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
signals: BacktestSignal[];
|
||||
/** true — 전체 표시, 접기 버튼 없음 */
|
||||
expanded?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function BacktestSignalTable({ signals, expanded = false, className }: Props) {
|
||||
const [sigExpanded, setSigExpanded] = useState(expanded);
|
||||
const showAll = expanded || sigExpanded;
|
||||
const sigLimit = showAll ? signals.length : 8;
|
||||
|
||||
return (
|
||||
<div className={`brd-card brd-card--full brd-card--sig-panel${className ? ` ${className}` : ''}`}>
|
||||
<SectionTitle
|
||||
icon="📋"
|
||||
title="거래 시그널"
|
||||
right={<span className="brd-section-count">{signals.length}건</span>}
|
||||
/>
|
||||
{signals.length === 0 ? (
|
||||
<div className="brd-empty-msg">시그널이 없습니다.</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="brd-sig-scroll">
|
||||
<table className="brd-sig-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ width: 36 }}>#</th>
|
||||
<th>날짜</th>
|
||||
<th>구분</th>
|
||||
<th style={{ textAlign: 'right' }}>가격</th>
|
||||
<th style={{ textAlign: 'center', width: 50 }}>봉#</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{signals.slice(0, sigLimit).map((s, i) => (
|
||||
<tr key={i} className={i % 2 === 0 ? 'brd-sig-even' : ''}>
|
||||
<td style={{ textAlign: 'center', color: 'var(--text3)' }}>{i + 1}</td>
|
||||
<td style={{ fontVariantNumeric: 'tabular-nums' }}>{fmtDate(s.time)}</td>
|
||||
<td>
|
||||
<span className={`brd-sig-badge ${SIG_COLOR[s.type] ?? ''}`}>
|
||||
{repairUtf8Mojibake(SIG_LABEL[s.type] ?? s.type)}
|
||||
</span>
|
||||
</td>
|
||||
<td style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums', fontWeight: 600 }}>
|
||||
{Math.round(s.price).toLocaleString()}
|
||||
</td>
|
||||
<td style={{ textAlign: 'center', color: 'var(--text3)' }}>{s.barIndex}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{!expanded && signals.length > 8 && (
|
||||
<button type="button" className="brd-expand-btn" onClick={() => setSigExpanded(v => !v)}>
|
||||
{sigExpanded ? '▲ 접기' : `▼ 전체 보기 (${signals.length}건)`}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user