추세검색 설정 수정

This commit is contained in:
Macbook
2026-05-27 02:10:00 +09:00
parent 2e08c6b16f
commit fc06a16184
27 changed files with 1262 additions and 147 deletions
@@ -1,5 +1,7 @@
import React from 'react';
import type { PaperTradeDto } from '../../utils/backendApi';
import type { TickerData } from '../../hooks/useMarketTicker';
import { resolveVirtualTargetNames } from '../../utils/virtualTargetNames';
import { fmtKrw } from '../TradeOrderPanel';
function coinCode(symbol: string): string {
@@ -22,6 +24,7 @@ function sourceLabel(source: string | null | undefined): string {
interface Props {
trades: PaperTradeDto[];
strategyNames?: Record<number, string>;
tickers?: Map<string, TickerData>;
emptyText?: string;
className?: string;
onSelectMarket?: (market: string) => void;
@@ -30,57 +33,102 @@ interface Props {
const PaperTradeHistoryList: React.FC<Props> = ({
trades,
strategyNames = {},
tickers,
emptyText = '거래 내역이 없습니다.',
className = '',
onSelectMarket,
}) => (
<div className={`ptd-trade-history${className ? ` ${className}` : ''}`}>
{trades.length === 0 ? (
<p className="ptd-muted ptd-trade-history-empty">{emptyText}</p>
) : (
<div className="ptd-trade-history-scroll">
<table className="ptd-table ptd-table--compact ptd-table--trades">
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<div className={`ptd-trade-history vtd-trade-history${className ? ` ${className}` : ''}`}>
<section className="vtd-target-section vtd-trade-section">
<div className="vtd-target-list-head">
<span> </span>
<span className="vtd-target-count">{trades.length}</span>
</div>
{trades.length === 0 ? (
<p className="vtd-muted ptd-trade-history-empty">{emptyText}</p>
) : (
<div className="ptd-trade-history-scroll">
<div className="vtd-target-list vtd-trade-list">
{trades.map(t => {
const { koreanName: ko, englishName: en } = resolveVirtualTargetNames(
t.symbol,
tickers?.get(t.symbol)?.koreanName,
);
const strategyName = t.strategyId != null
? (strategyNames[t.strategyId] ?? `#${t.strategyId}`)
: null;
: '—';
const isBuy = t.side === 'BUY';
const clickable = Boolean(onSelectMarket);
const sideCls = isBuy ? 'vtd-trade-item--buy' : 'vtd-trade-item--sell';
const colorCls = isBuy ? 'vtd-target-up' : 'vtd-target-dn';
return (
<tr
<div
key={t.id}
className={onSelectMarket ? 'ptd-row--click' : undefined}
onClick={onSelectMarket ? () => onSelectMarket(t.symbol) : undefined}
title={strategyName ? `전략: ${strategyName}` : undefined}
className={[
'vtd-target-item',
'vtd-trade-item',
sideCls,
clickable ? 'vtd-trade-item--click' : '',
].filter(Boolean).join(' ')}
role={clickable ? 'button' : undefined}
tabIndex={clickable ? 0 : undefined}
onClick={clickable ? () => onSelectMarket!(t.symbol) : undefined}
onKeyDown={clickable ? e => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onSelectMarket!(t.symbol);
}
} : undefined}
>
<td className="ptd-time">{fmtTradeTime(t.createdAt)}</td>
<td>{coinCode(t.symbol)}</td>
<td className={t.side === 'BUY' ? 'up' : 'down'}>
{t.side === 'BUY' ? '매수' : '매도'}
</td>
<td className={t.source === 'STRATEGY' ? 'ptd-source--auto' : 'ptd-source--manual'}>
{sourceLabel(t.source)}
</td>
<td>{fmtKrw(t.price)}</td>
<td>{t.quantity}</td>
<td>{fmtKrw(t.netAmount)}</td>
</tr>
<div className="vtd-target-item-main">
<div className="vtd-target-names">
<span className="vtd-target-ko">{ko}</span>
<span className="vtd-target-en">{fmtTradeTime(t.createdAt)} · {en}</span>
</div>
<div className="vtd-target-item-actions">
<span className={`vtd-trade-side-badge vtd-trade-side-badge--${isBuy ? 'buy' : 'sell'}`}>
{isBuy ? '매수' : '매도'}
</span>
</div>
</div>
<div className="vtd-target-quote vtd-trade-quote" aria-label="체결 정보">
<div className="vtd-target-quote-left">
<span className={`vtd-target-arrow vtd-target-arrow--${isBuy ? 'rise' : 'fall'}`}>
{isBuy ? '▲' : '▼'}
</span>
<span className="vtd-target-quote-pair">{coinCode(t.symbol)}/KRW</span>
</div>
<div className="vtd-target-quote-right">
<span className={`vtd-target-price ${colorCls}`}>{fmtKrw(t.price)}</span>
<span className={`vtd-target-change ${colorCls}`}>{fmtKrw(t.netAmount)}</span>
</div>
</div>
<div className="vtd-target-strategy-field vtd-trade-meta-field">
<span className="vtd-target-strategy-label"></span>
<span
className={`vtd-trade-meta-value${t.source === 'STRATEGY' ? ' vtd-trade-meta-value--auto' : ''}`}
>
{sourceLabel(t.source)}
</span>
</div>
<div className="vtd-target-strategy-field vtd-trade-meta-field">
<span className="vtd-target-strategy-label"></span>
<span className="vtd-trade-meta-value vtd-trade-meta-value--strategy" title={strategyName}>
{strategyName}
</span>
</div>
</div>
);
})}
</tbody>
</table>
</div>
)}
</div>
</div>
)}
</section>
</div>
);