백테스팅 종목 선택란을 MarketSearchPanel 한글 검색 드롭다운으로 교체

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Macbook
2026-06-11 16:07:06 +09:00
parent b74f305654
commit c747f91792
2 changed files with 84 additions and 10 deletions
+39 -10
View File
@@ -3,6 +3,8 @@
*/
import '../styles/backtestDashboard.css';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import { MarketSearchPanel } from './MarketSearchPanel';
import {
loadBacktestResults,
deleteBacktestResult,
@@ -17,7 +19,6 @@ import {
type BacktestSignal,
type StrategyDto,
} from '../utils/backendApi';
import { UPBIT_MARKETS } from '../utils/upbitApi';
import { timeframeToCandleType } from '../utils/chartCandleType';
import type { Theme, Timeframe } from '../types';
import { buildEquityFromSignals } from '../utils/backtestEquity';
@@ -101,6 +102,9 @@ export function BacktestHistoryPage({ theme = 'dark' }: Props) {
const [runStrategyId, setRunStrategyId] = useState<number | null>(null);
const [runLoading, setRunLoading] = useState(false);
const [runError, setRunError] = useState<string | null>(null);
const [showMarketSearch, setShowMarketSearch] = useState(false);
const [marketQuery, setMarketQuery] = useState('');
const marketBtnRef = useRef<HTMLButtonElement>(null);
const [leftWidth, setLeftWidth] = useState(() => readMinWidth(LEFT_KEY, LEFT_DEFAULT));
const [rightWidth, setRightWidth] = useState(() => readMinWidth(RIGHT_KEY, RIGHT_DEFAULT));
@@ -372,17 +376,42 @@ export function BacktestHistoryPage({ theme = 'dark' }: Props) {
{/* 빠른 실행 툴바 */}
<div className="btd-header-run">
<select
className="btd-run-select"
value={runMarket}
onChange={e => setRunMarket(e.target.value)}
<button
ref={marketBtnRef}
type="button"
className="btd-run-market-btn"
disabled={runLoading}
title="종목"
title="종목 검색"
onClick={() => {
setMarketQuery('');
setShowMarketSearch(v => !v);
}}
>
{UPBIT_MARKETS.map(m => (
<option key={m} value={m}>{m.replace('KRW-', '')}</option>
))}
</select>
<span className="btd-run-market-ko">{getKoreanName(runMarket)}</span>
<span className="btd-run-market-sym">{runMarket.replace('KRW-', '')}</span>
<svg className="btd-run-market-caret" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<polyline points="6 9 12 15 18 9"/>
</svg>
</button>
{showMarketSearch && ReactDOM.createPortal(
<MarketSearchPanel
currentMarket={runMarket}
query={marketQuery}
onQueryChange={setMarketQuery}
onSelect={market => {
setRunMarket(market);
setShowMarketSearch(false);
setMarketQuery('');
}}
onClose={() => {
setShowMarketSearch(false);
setMarketQuery('');
}}
anchorRect={marketBtnRef.current?.getBoundingClientRect() ?? null}
anchorPlacement="dropdown"
/>,
document.body,
)}
<select
className="btd-run-select"
value={runTimeframe}
+45
View File
@@ -848,6 +848,51 @@
min-width: 0;
}
/* 종목 검색 버튼 (MarketSearchPanel 드롭다운 트리거) */
.btd-run-market-btn {
display: flex;
align-items: center;
gap: 4px;
background: var(--se-bg-elevated, var(--bg2));
border: 1px solid var(--se-border);
color: var(--se-text);
border-radius: 7px;
padding: 0 8px;
font-size: 0.76rem;
cursor: pointer;
height: 30px;
outline: none;
transition: border-color 0.15s, background 0.15s;
white-space: nowrap;
min-width: 90px;
max-width: 140px;
}
.btd-run-market-btn:hover:not(:disabled) {
border-color: var(--se-accent, #3d9be9);
background: color-mix(in srgb, var(--se-accent, #3d9be9) 8%, var(--se-bg-elevated, var(--bg2)));
}
.btd-run-market-btn:disabled {
opacity: 0.45;
cursor: not-allowed;
}
.btd-run-market-ko {
font-weight: 600;
font-size: 0.76rem;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.btd-run-market-sym {
font-size: 0.68rem;
color: var(--se-text-muted, #888);
flex-shrink: 0;
}
.btd-run-market-caret {
flex-shrink: 0;
opacity: 0.55;
margin-left: 2px;
}
.btd-run-select {
background: var(--se-bg-elevated, var(--bg2));
border: 1px solid var(--se-border);