전략평가 로직 오류 수정
This commit is contained in:
@@ -87,6 +87,10 @@ interface MarketSearchPanelProps {
|
||||
marketInfos?: HookMarketInfo[];
|
||||
marketLoading?: boolean;
|
||||
refreshAllTickers?: () => Promise<void>;
|
||||
/** 내부 훅 사용 시 전 종목 REST·폴링 (기본 true). 전략평가 검색은 false 권장 */
|
||||
tickerLoadFull?: boolean;
|
||||
/** 내부 훅 우선 종목 (전략평가 차트 종목 등) */
|
||||
tickerPriorityMarkets?: string[];
|
||||
}
|
||||
|
||||
export const MarketSearchPanel: React.FC<MarketSearchPanelProps> = ({
|
||||
@@ -94,7 +98,7 @@ export const MarketSearchPanel: React.FC<MarketSearchPanelProps> = ({
|
||||
variant = 'overlay', query: controlledQuery, onQueryChange,
|
||||
actionMode = 'favorite', onAdd, onRemove, addedMarkets, maxTargetsReached = false,
|
||||
tickers: tickersProp, marketInfos: marketInfosProp, marketLoading: marketLoadingProp,
|
||||
refreshAllTickers: refreshProp,
|
||||
refreshAllTickers: refreshProp, tickerLoadFull = true, tickerPriorityMarkets,
|
||||
}) => {
|
||||
const embedded = variant === 'embedded';
|
||||
const isCompact = useIsCompactDevice();
|
||||
@@ -102,7 +106,8 @@ export const MarketSearchPanel: React.FC<MarketSearchPanelProps> = ({
|
||||
|
||||
const internalFeed = useMarketTicker({
|
||||
enabled: !useExternalFeed,
|
||||
loadFull: true,
|
||||
loadFull: tickerLoadFull,
|
||||
priorityMarkets: tickerPriorityMarkets ?? (currentMarket ? [currentMarket] : undefined),
|
||||
});
|
||||
|
||||
const tickers = tickersProp ?? internalFeed.tickers;
|
||||
|
||||
@@ -31,6 +31,7 @@ import SePanelCollapseHandle from './strategyEditor/SePanelCollapseHandle';
|
||||
import { readStoredSize, readStoredBool, storeBool, storeSize, usePanelResize } from './strategyEditor/usePanelResize';
|
||||
import { getKoreanName } from '../utils/marketNameCache';
|
||||
import { useIndicatorSettings } from '../hooks/useIndicatorSettings';
|
||||
import { useMarketTicker } from '../hooks/useMarketTicker';
|
||||
import {
|
||||
mergeEvalGetParams,
|
||||
buildEvalParamsFromStrategy,
|
||||
@@ -69,6 +70,7 @@ interface Props {
|
||||
export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
const { getParams: baseGetParams, getVisualConfig } = useIndicatorSettings();
|
||||
const [leftTab, setLeftTab] = useState<LeftTab>('strategy');
|
||||
const [marketSearchOpen, setMarketSearchOpen] = useState(false);
|
||||
const [strategies, setStrategies] = useState<StrategyDto[]>([]);
|
||||
const [strategySearch, setStrategySearch] = useState('');
|
||||
const [selectedStrategyId, setSelectedStrategyId] = useState<number | null>(null);
|
||||
@@ -100,6 +102,15 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
[baseGetParams, appliedIndicatorParams],
|
||||
);
|
||||
|
||||
/** 종목 탭·종목검색 전용 ticker — 차트 OHLCV·scan-signals 와 분리 (upbitWsBroker ticker 채널) */
|
||||
const marketTabActive = leftOpen && leftTab === 'market';
|
||||
const marketTickerOpts = useMemo(() => ({
|
||||
enabled: marketTabActive || marketSearchOpen,
|
||||
loadFull: marketTabActive,
|
||||
priorityMarkets: [market],
|
||||
}), [marketTabActive, marketSearchOpen, market]);
|
||||
const marketFeed = useMarketTicker(marketTickerOpts);
|
||||
|
||||
const [leftWidth, setLeftWidth] = useState(() => readMinWidth(LEFT_KEY, LEFT_DEFAULT));
|
||||
const [leftOpen, setLeftOpen] = useState(() => readStoredBool(LEFT_OPEN_KEY, true));
|
||||
const [rightWidth, setRightWidth] = useState(() => readMinWidth(RIGHT_KEY, RIGHT_DEFAULT));
|
||||
@@ -543,7 +554,11 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
<StrategyEvaluationMarketTab
|
||||
activeMarket={market}
|
||||
onSelectMarket={setMarket}
|
||||
enabled={leftOpen && leftTab === 'market'}
|
||||
tickers={marketFeed.tickers}
|
||||
marketInfos={marketFeed.marketInfos}
|
||||
loading={marketFeed.loading}
|
||||
usdRate={marketFeed.usdRate}
|
||||
refreshAllTickers={marketFeed.refreshAllTickers}
|
||||
/>
|
||||
) : (
|
||||
<StrategyEvaluationSettingsTab
|
||||
@@ -602,6 +617,11 @@ export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
|
||||
onOpenReport={() => { void handleOpenReport(); }}
|
||||
reportDisabled={reportDisabled}
|
||||
reportLoading={reportLoading}
|
||||
marketTickers={marketFeed.tickers}
|
||||
marketInfos={marketFeed.marketInfos}
|
||||
marketLoading={marketFeed.loading}
|
||||
refreshMarketTickers={marketFeed.refreshAllTickers}
|
||||
onMarketSearchOpenChange={setMarketSearchOpen}
|
||||
/>
|
||||
<StrategyEvaluationConditionPanel
|
||||
strategy={selectedStrategy}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { DEFAULT_DISPLAY_TIMEZONE } from '../../utils/timezone';
|
||||
import { getKoreanName } from '../../utils/marketNameCache';
|
||||
import type { BacktestSignal, StrategyDto } from '../../utils/backendApi';
|
||||
import { fetchLiveConditionScanSignals } from '../../utils/backendApi';
|
||||
import type { MarketInfo, TickerData } from '../../hooks/useMarketTicker';
|
||||
import {
|
||||
BACKTEST_DISPLAY_BAR_COUNT,
|
||||
fetchBacktestCandleBundle,
|
||||
@@ -73,6 +74,12 @@ interface Props {
|
||||
onOpenReport?: () => void;
|
||||
reportDisabled?: boolean;
|
||||
reportLoading?: boolean;
|
||||
/** StrategyEvaluationPage 공유 ticker (종목 탭·검색과 단일 useMarketTicker) */
|
||||
marketTickers?: Map<string, TickerData>;
|
||||
marketInfos?: MarketInfo[];
|
||||
marketLoading?: boolean;
|
||||
refreshMarketTickers?: () => Promise<void>;
|
||||
onMarketSearchOpenChange?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
const isOverlayType = (type: string) => getIndicatorDef(type)?.overlay === true;
|
||||
@@ -109,6 +116,11 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
||||
onOpenReport,
|
||||
reportDisabled = false,
|
||||
reportLoading = false,
|
||||
marketTickers,
|
||||
marketInfos,
|
||||
marketLoading,
|
||||
refreshMarketTickers,
|
||||
onMarketSearchOpenChange,
|
||||
}) => {
|
||||
const { getParams: baseGetParams, getVisualConfig: baseGetVisual, settingsRevision } = useIndicatorSettings();
|
||||
const getParams = getParamsOverride ?? baseGetParams;
|
||||
@@ -405,6 +417,10 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
||||
return () => window.removeEventListener('keydown', onKeyDown);
|
||||
}, [bars.length, selectedBarIndex, stepBar]);
|
||||
|
||||
useEffect(() => {
|
||||
onMarketSearchOpenChange?.(showMarketSearch);
|
||||
}, [showMarketSearch, onMarketSearchOpenChange]);
|
||||
|
||||
const selectedBar = bars[selectedBarIndex] ?? null;
|
||||
|
||||
return (
|
||||
@@ -611,6 +627,10 @@ const StrategyEvaluationChart: React.FC<Props> = ({
|
||||
currentMarket={market}
|
||||
query={marketQuery}
|
||||
onQueryChange={setMarketQuery}
|
||||
tickers={marketTickers}
|
||||
marketInfos={marketInfos}
|
||||
marketLoading={marketLoading}
|
||||
refreshAllTickers={refreshMarketTickers}
|
||||
onSelect={m => {
|
||||
onMarketChange(m);
|
||||
setShowMarketSearch(false);
|
||||
|
||||
@@ -1,34 +1,28 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React from 'react';
|
||||
import MarketPanel from '../MarketPanel';
|
||||
import { useMarketTicker } from '../../hooks/useMarketTicker';
|
||||
import type { MarketInfo, TickerData } from '../../hooks/useMarketTicker';
|
||||
|
||||
interface Props {
|
||||
activeMarket: string;
|
||||
onSelectMarket: (market: string) => void;
|
||||
/** 종목 탭 표시 중 — 전 종목 시세 로드 */
|
||||
enabled: boolean;
|
||||
/** StrategyEvaluationPage 공유 useMarketTicker — 차트·시그널과 분리된 ticker 전용 */
|
||||
tickers: Map<string, TickerData>;
|
||||
marketInfos: MarketInfo[];
|
||||
loading: boolean;
|
||||
usdRate: number;
|
||||
refreshAllTickers?: () => Promise<void>;
|
||||
}
|
||||
|
||||
/** 전략평가 좌측 — 실시간 차트 MarketPanel 과 동일 종목 목록 */
|
||||
/** 전략평가 좌측 — 실시간 차트 MarketPanel 과 동일 종목 목록 (현재가 WS/REST만, OHLCV·시그널 무관) */
|
||||
const StrategyEvaluationMarketTab: React.FC<Props> = ({
|
||||
activeMarket,
|
||||
onSelectMarket,
|
||||
enabled,
|
||||
tickers,
|
||||
marketInfos,
|
||||
loading,
|
||||
usdRate,
|
||||
refreshAllTickers,
|
||||
}) => {
|
||||
const tickerOpts = useMemo(() => ({
|
||||
enabled,
|
||||
loadFull: enabled,
|
||||
priorityMarkets: [activeMarket],
|
||||
}), [enabled, activeMarket]);
|
||||
|
||||
const {
|
||||
tickers,
|
||||
marketInfos,
|
||||
loading,
|
||||
usdRate,
|
||||
refreshAllTickers,
|
||||
} = useMarketTicker(tickerOpts);
|
||||
|
||||
return (
|
||||
<div className="seval-market-tab">
|
||||
<MarketPanel
|
||||
|
||||
Reference in New Issue
Block a user