백테스팅 종목 선택란을 MarketSearchPanel 한글 검색 드롭다운으로 교체
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user