가상투자 설정 수정

This commit is contained in:
Macbook
2026-05-25 22:30:54 +09:00
parent cae1c3a624
commit 1e950c7db4
24 changed files with 1015 additions and 362 deletions
@@ -1,12 +1,10 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import VirtualTargetCard, { type VirtualCardDisplayMode } from './VirtualTargetCard';
import VirtualGridUnifiedHeader from './VirtualGridUnifiedHeader';
import VirtualTargetFocusView from './VirtualTargetFocusView';
import type { StrategyDto } from '../../utils/backendApi';
import type { Theme } from '../../types';
import type { ChartRealtimeSource } from '../../hooks/useChartRealtimeData';
import type { VirtualTargetItem, VirtualCardViewMode, VirtualSessionConfig } from '../../utils/virtualTradingStorage';
import { loadVirtualCardViewMode, saveVirtualCardViewMode } from '../../utils/virtualTradingStorage';
import type { VirtualLiveStatus } from '../../hooks/useVirtualTargetLiveStatus';
import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots';
import type { TickerData } from '../../hooks/useMarketTicker';
@@ -16,11 +14,6 @@ interface Props {
strategies: StrategyDto[];
snapshots: Record<string, VirtualIndicatorSnapshot>;
session: Pick<VirtualSessionConfig, 'globalStrategyId' | 'executionType' | 'positionMode' | 'running'>;
onStrategyChange: (strategyId: number | null) => void;
onExecutionTypeChange: (type: VirtualSessionConfig['executionType']) => void;
onPositionModeChange: (mode: VirtualSessionConfig['positionMode']) => void;
onStart: () => void;
onStop: () => void;
onTargetStrategyChange: (market: string, strategyId: number | null) => void;
liveStatusByMarket?: Record<string, VirtualLiveStatus>;
lastTickAtByMarket?: Record<string, number>;
@@ -30,11 +23,13 @@ interface Props {
chartRealtimeSource?: ChartRealtimeSource;
chartSeriesPriceLabels?: boolean;
tickers?: Map<string, TickerData>;
viewMode: VirtualCardViewMode;
globalDisplayMode: VirtualCardDisplayMode;
onFocusMarketChange?: (market: string | null) => void;
}
const VirtualTargetGrid: React.FC<Props> = ({
targets, strategies, snapshots, session,
onStrategyChange, onExecutionTypeChange, onPositionModeChange, onStart, onStop,
onTargetStrategyChange,
liveStatusByMarket = {}, lastTickAtByMarket = {}, selectedMarket,
onSelectMarket,
@@ -42,9 +37,10 @@ const VirtualTargetGrid: React.FC<Props> = ({
chartRealtimeSource = 'BACKEND_STOMP',
chartSeriesPriceLabels = true,
tickers,
viewMode,
globalDisplayMode,
onFocusMarketChange,
}) => {
const [viewMode, setViewMode] = useState<VirtualCardViewMode>(() => loadVirtualCardViewMode());
const [globalDisplayMode, setGlobalDisplayMode] = useState<VirtualCardDisplayMode>('signal');
const [cardDisplayOverrides, setCardDisplayOverrides] = useState<Record<string, VirtualCardDisplayMode>>({});
const [focusMarket, setFocusMarket] = useState<string | null>(null);
@@ -53,14 +49,14 @@ const VirtualTargetGrid: React.FC<Props> = ({
useEffect(() => {
if (focusMarket && !activeMarkets.has(focusMarket)) {
setFocusMarket(null);
onFocusMarketChange?.(null);
}
}, [activeMarkets, focusMarket]);
}, [activeMarkets, focusMarket, onFocusMarketChange]);
useEffect(() => {
saveVirtualCardViewMode(viewMode);
}, [viewMode]);
onFocusMarketChange?.(focusMarket);
}, [focusMarket, onFocusMarketChange]);
/** 제거된 종목 override 정리 */
useEffect(() => {
setCardDisplayOverrides(prev => {
const next: Record<string, VirtualCardDisplayMode> = {};
@@ -73,10 +69,9 @@ const VirtualTargetGrid: React.FC<Props> = ({
});
}, [activeMarkets]);
const handleGlobalDisplayMode = useCallback((mode: VirtualCardDisplayMode) => {
setGlobalDisplayMode(mode);
useEffect(() => {
setCardDisplayOverrides({});
}, []);
}, [globalDisplayMode]);
const handleCardDisplayMode = useCallback((market: string, mode: VirtualCardDisplayMode) => {
setCardDisplayOverrides(prev => ({ ...prev, [market]: mode }));
@@ -92,27 +87,9 @@ const VirtualTargetGrid: React.FC<Props> = ({
[focusMarket, targets],
);
const renderUnifiedHeader = (viewControls: 'full' | 'display-only' | 'hidden') => (
<VirtualGridUnifiedHeader
session={session}
strategies={strategies}
onStrategyChange={onStrategyChange}
onExecutionTypeChange={onExecutionTypeChange}
onPositionModeChange={onPositionModeChange}
onStart={onStart}
onStop={onStop}
viewMode={viewMode}
onViewModeChange={setViewMode}
globalDisplayMode={globalDisplayMode}
onGlobalDisplayModeChange={handleGlobalDisplayMode}
viewControls={viewControls}
/>
);
if (targets.length === 0) {
return (
<div className="vtd-grid-wrap">
{renderUnifiedHeader('hidden')}
<div className="vtd-grid-empty">
<p className="vtd-muted"> .</p>
</div>
@@ -122,7 +99,6 @@ const VirtualTargetGrid: React.FC<Props> = ({
return (
<div className={`vtd-grid-wrap${focusMarket ? ' vtd-grid-wrap--focus' : ''}`}>
{renderUnifiedHeader(focusMarket ? 'display-only' : 'full')}
{focusMarket && focusTarget ? (
<VirtualTargetFocusView
market={focusTarget.market}