벡테스팅 수정
This commit is contained in:
@@ -812,6 +812,7 @@ const TradingChart: React.FC<TradingChartProps> = ({
|
||||
const mgr = new ChartManager(containerRef.current, theme, {
|
||||
compactPaneLayout: paneLayoutClamp,
|
||||
autoSize: !paneLayoutClamp,
|
||||
volumePaneEnabled: volumeVisibleRef.current,
|
||||
});
|
||||
managerRef.current = mgr;
|
||||
setChartMgr(mgr);
|
||||
|
||||
@@ -58,7 +58,7 @@ import {
|
||||
import { pinStrategyEvaluationTimeframes } from '../utils/strategyTimeframePin';
|
||||
import { persistVirtualTargetPinned } from '../utils/virtualTargetMutations';
|
||||
import {
|
||||
coalesceTargetsToDefaultStrategy,
|
||||
freezeTargetsBeforeGlobalStrategyChange,
|
||||
resolveVirtualTargetStrategyId,
|
||||
} from '../utils/virtualTargetStrategy';
|
||||
import { virtualTargetLimitMessage } from '../utils/virtualTargetLimits';
|
||||
@@ -165,12 +165,6 @@ const VirtualTradingPage: React.FC<Props> = ({
|
||||
useEffect(() => { saveVirtualTargets(targets); }, [targets]);
|
||||
useEffect(() => { saveVirtualSession(session); }, [session]);
|
||||
|
||||
/** 예전 데이터: 종목 strategyId에 전역 ID가 복사된 경우 → 기본 전략 따름(null) */
|
||||
useEffect(() => {
|
||||
if (session.globalStrategyId == null) return;
|
||||
setTargets(prev => coalesceTargetsToDefaultStrategy(prev, session.globalStrategyId));
|
||||
}, [session.globalStrategyId]);
|
||||
|
||||
useEffect(() => { saveVirtualCardViewMode(viewMode); }, [viewMode]);
|
||||
useEffect(() => { saveVirtualGridPreset(gridPreset); }, [gridPreset]);
|
||||
|
||||
@@ -299,13 +293,11 @@ const VirtualTradingPage: React.FC<Props> = ({
|
||||
});
|
||||
}, []);
|
||||
|
||||
/** 상단 기본전략 — 신규 추가 종목 템플릿만 변경, 기존 종목 전략은 유지 */
|
||||
const handleGlobalStrategyChange = useCallback((strategyId: number | null) => {
|
||||
const next = { ...session, globalStrategyId: strategyId };
|
||||
setSession(next);
|
||||
if (session.running && strategyId) {
|
||||
void syncVirtualTargetsToBackend(targets, next, true);
|
||||
}
|
||||
}, [session, targets]);
|
||||
setTargets(prev => freezeTargetsBeforeGlobalStrategyChange(prev, session.globalStrategyId));
|
||||
setSession(prev => ({ ...prev, globalStrategyId: strategyId }));
|
||||
}, [session.globalStrategyId]);
|
||||
|
||||
const handleStart = useCallback(async () => {
|
||||
if (targets.length === 0) {
|
||||
|
||||
@@ -77,7 +77,7 @@ const VirtualLeftTargetPanel: React.FC<Props> = ({
|
||||
...targets,
|
||||
{
|
||||
market,
|
||||
strategyId: null,
|
||||
strategyId: globalStrategyId,
|
||||
koreanName: names.koreanName,
|
||||
englishName: names.englishName,
|
||||
},
|
||||
|
||||
@@ -33,14 +33,13 @@ const VirtualStrategyChartPopup: React.FC<Props> = ({
|
||||
const chartSeriesPriceLabels = chartDefaults.chartSeriesPriceLabels;
|
||||
|
||||
const ko = getKoreanName(market);
|
||||
const sym = market.replace(/^KRW-/, '');
|
||||
const stratName = strategy?.name ?? '전략 미지정';
|
||||
|
||||
return (
|
||||
<AppPopup
|
||||
onClose={onClose}
|
||||
title={sym}
|
||||
titleKo={ko}
|
||||
title={ko}
|
||||
titleKo={stratName}
|
||||
badge="CHART"
|
||||
width={920}
|
||||
maxWidth="96vw"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { getKoreanName } from '../../utils/marketNameCache';
|
||||
import type { StrategyDto } from '../../utils/backendApi';
|
||||
import {
|
||||
resolveVirtualTargetNames,
|
||||
resolveVirtualTargetStrategyDisplayName,
|
||||
} from '../../utils/virtualTargetNames';
|
||||
import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots';
|
||||
import { useLiveReceiveFlash } from '../../hooks/useLiveReceiveFlash';
|
||||
import type { ChartRealtimeSource } from '../../hooks/useChartRealtimeData';
|
||||
@@ -47,6 +50,9 @@ interface Props {
|
||||
chartPaneSeparator?: import('../../types/chartPaneSeparator').ChartPaneSeparatorOptions;
|
||||
chartLiveReceiveHighlight?: boolean;
|
||||
ticker?: TickerData;
|
||||
/** 투자대상 저장 한글명·영문 심볼 (없으면 티커·마켓 캐시) */
|
||||
koreanName?: string;
|
||||
englishName?: string;
|
||||
/** 알림 목록 등 — 푸터 전략 셀렉트 읽기 전용 라벨 */
|
||||
readOnlyStrategyLabel?: string;
|
||||
/** 헤더 우측 레이아웃 (알림 목록 신호 슬롯: inline-quote) */
|
||||
@@ -78,12 +84,22 @@ const VirtualTargetCard: React.FC<Props> = ({
|
||||
chartPaneSeparator,
|
||||
chartLiveReceiveHighlight = true,
|
||||
ticker,
|
||||
koreanName,
|
||||
englishName,
|
||||
readOnlyStrategyLabel,
|
||||
headVariant = 'default',
|
||||
}) => {
|
||||
const inlineHeadQuote = headVariant === 'inline-quote';
|
||||
const ko = getKoreanName(market);
|
||||
const sym = market.replace(/^KRW-/, '');
|
||||
const { koreanName: displayKo, englishName: displayEn } = resolveVirtualTargetNames(
|
||||
market,
|
||||
koreanName ?? ticker?.koreanName,
|
||||
englishName,
|
||||
);
|
||||
const strategyDisplayName = resolveVirtualTargetStrategyDisplayName(
|
||||
strategy,
|
||||
strategies,
|
||||
readOnlyStrategyLabel,
|
||||
);
|
||||
const rows = snapshot?.rows ?? [];
|
||||
|
||||
const metrics = useMemo(() => buildConditionMetrics(rows), [rows]);
|
||||
@@ -129,9 +145,18 @@ const VirtualTargetCard: React.FC<Props> = ({
|
||||
>
|
||||
<div className="vtd-card-head">
|
||||
<div className="vtd-card-head-main">
|
||||
<div className="vtd-card-title">
|
||||
<span className="vtd-card-ko">{ko}</span>
|
||||
<span className="vtd-card-sym">{sym}</span>
|
||||
<div className={`vtd-card-title${isChart ? ' vtd-card-title--chart' : ''}`}>
|
||||
{isChart ? (
|
||||
<>
|
||||
<span className="vtd-card-chart-strategy">{strategyDisplayName}</span>
|
||||
<span className="vtd-card-ko">{displayKo}</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="vtd-card-ko">{displayKo}</span>
|
||||
<span className="vtd-card-sym">{displayEn}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{inlineHeadQuote ? (
|
||||
|
||||
@@ -259,6 +259,7 @@ const VirtualTargetCardChart: React.FC<Props> = ({
|
||||
onCandlesReady={handleCandlesReady}
|
||||
magnifierEnabled={false}
|
||||
volumeVisible={false}
|
||||
paneLayoutClamp
|
||||
showHoverToolbar={false}
|
||||
showPaneLegend={false}
|
||||
showCandlePaneControls={false}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { getKoreanName } from '../../utils/marketNameCache';
|
||||
import type { StrategyDto } from '../../utils/backendApi';
|
||||
import {
|
||||
resolveVirtualTargetNames,
|
||||
resolveVirtualTargetStrategyDisplayName,
|
||||
} from '../../utils/virtualTargetNames';
|
||||
import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots';
|
||||
import { useLiveReceiveFlash } from '../../hooks/useLiveReceiveFlash';
|
||||
import type { ChartRealtimeSource } from '../../hooks/useChartRealtimeData';
|
||||
@@ -37,6 +40,9 @@ interface Props {
|
||||
chartPaneSeparator?: import('../../types/chartPaneSeparator').ChartPaneSeparatorOptions;
|
||||
chartLiveReceiveHighlight?: boolean;
|
||||
ticker?: TickerData;
|
||||
koreanName?: string;
|
||||
englishName?: string;
|
||||
readOnlyStrategyLabel?: string;
|
||||
}
|
||||
|
||||
/** 전체보기 — 좌 차트 · 우 신호 */
|
||||
@@ -61,9 +67,20 @@ const VirtualTargetFocusView: React.FC<Props> = ({
|
||||
chartPaneSeparator,
|
||||
chartLiveReceiveHighlight = true,
|
||||
ticker,
|
||||
koreanName,
|
||||
englishName,
|
||||
readOnlyStrategyLabel,
|
||||
}) => {
|
||||
const ko = getKoreanName(market);
|
||||
const sym = market.replace(/^KRW-/, '');
|
||||
const { koreanName: displayKo } = resolveVirtualTargetNames(
|
||||
market,
|
||||
koreanName ?? ticker?.koreanName,
|
||||
englishName,
|
||||
);
|
||||
const strategyDisplayName = resolveVirtualTargetStrategyDisplayName(
|
||||
strategy,
|
||||
strategies,
|
||||
readOnlyStrategyLabel,
|
||||
);
|
||||
|
||||
const receiveSignal = useMemo(() => {
|
||||
if (!running) return null;
|
||||
@@ -80,9 +97,9 @@ const VirtualTargetFocusView: React.FC<Props> = ({
|
||||
<div className={`vtd-focus-wrap${highlightReceiving ? ' vtd-focus-wrap--receiving' : ''}`}>
|
||||
<div className="vtd-focus-head">
|
||||
<div className="vtd-focus-head-main">
|
||||
<div className="vtd-focus-title">
|
||||
<span className="vtd-card-ko">{ko}</span>
|
||||
<span className="vtd-card-sym">{sym}</span>
|
||||
<div className="vtd-focus-title vtd-card-title--chart">
|
||||
<span className="vtd-card-chart-strategy">{strategyDisplayName}</span>
|
||||
<span className="vtd-card-ko">{displayKo}</span>
|
||||
</div>
|
||||
{running && <VirtualLiveBadge status={liveStatus} receiving={receiving} />}
|
||||
</div>
|
||||
|
||||
@@ -140,6 +140,8 @@ const VirtualTargetGrid: React.FC<Props> = ({
|
||||
chartPaneSeparator={chartPaneSeparator}
|
||||
chartLiveReceiveHighlight={chartLiveReceiveHighlight}
|
||||
ticker={tickers?.get(focusTarget.market)}
|
||||
koreanName={focusTarget.koreanName}
|
||||
englishName={focusTarget.englishName}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
@@ -180,6 +182,8 @@ const VirtualTargetGrid: React.FC<Props> = ({
|
||||
chartPaneSeparator={chartPaneSeparator}
|
||||
chartLiveReceiveHighlight={chartLiveReceiveHighlight}
|
||||
ticker={tickers?.get(t.market)}
|
||||
koreanName={t.koreanName}
|
||||
englishName={t.englishName}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user