가상매매 챠트모드 수정

This commit is contained in:
Macbook
2026-06-08 21:20:54 +09:00
parent 80c78d75bc
commit 77562e5b8f
3 changed files with 42 additions and 34 deletions
@@ -2,7 +2,6 @@ import React, { memo, useMemo } from 'react';
import type { StrategyDto } from '../../utils/backendApi';
import {
resolveVirtualTargetNames,
resolveVirtualTargetStrategyDisplayName,
} from '../../utils/virtualTargetNames';
import { resolveVirtualTargetStrategyId } from '../../utils/virtualTargetStrategy';
import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots';
@@ -100,11 +99,6 @@ const VirtualTargetCard: React.FC<Props> = ({
koreanName ?? ticker?.koreanName,
englishName,
);
const strategyDisplayName = resolveVirtualTargetStrategyDisplayName(
strategy,
strategies,
readOnlyStrategyLabel,
);
const rows = snapshot?.rows ?? [];
const effectiveStrategyId = resolveVirtualTargetStrategyId(
{ strategyId },
@@ -160,10 +154,7 @@ const VirtualTargetCard: React.FC<Props> = ({
<div className="vtd-card-head-main">
<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-ko">{displayKo}</span>
@@ -16,7 +16,7 @@ import { useHistoryLoader } from '../../hooks/useHistoryLoader';
import { useIndicatorSettings } from '../../hooks/useIndicatorSettings';
import type { ChartManager } from '../../utils/ChartManager';
import {
buildVirtualTradingCardChartIndicators,
buildStrategyChartIndicators,
buildVirtualTradingChartIndicators,
resolveStrategyPrimaryTimeframe,
resolveStrategyTimeframes,
@@ -73,7 +73,7 @@ const VirtualTargetCardChart: React.FC<Props> = ({
const indicators = useMemo(() => (
fillHeight
? buildVirtualTradingChartIndicators(strategy, getParams, getVisualConfig)
: buildVirtualTradingCardChartIndicators(strategy, getParams, getVisualConfig)
: buildStrategyChartIndicators(strategy, getParams, getVisualConfig)
), [strategy, getParams, getVisualConfig, fillHeight]);
const effectiveIndicators = useMemo(
@@ -91,6 +91,17 @@ const VirtualTargetCardChart: React.FC<Props> = ({
const marketRef = useRef(market);
marketRef.current = market;
const syncChartLayout = useCallback(() => {
const wrap = canvasWrapRef.current;
const mgr = managerRef.current;
if (!wrap || !mgr?.hasMainSeries()) return;
const chartWrap = wrap.querySelector<HTMLElement>('.tv-chart-wrap');
const w = chartWrap?.clientWidth ?? wrap.clientWidth;
const h = chartWrap?.clientHeight ?? wrap.clientHeight;
if (w <= 0 || h <= 0) return;
mgr.syncLayout(w, h);
}, []);
const handleCandlesReady = useCallback(() => {
chartLiveReadyRef.current = true;
const pending = pendingBarRef.current;
@@ -98,11 +109,8 @@ const VirtualTargetCardChart: React.FC<Props> = ({
if (!pending || !mgr || barsMarketRef.current !== marketRef.current) return;
pendingBarRef.current = null;
mgr.updateBar(pending);
const wrap = canvasWrapRef.current;
if (wrap && wrap.clientHeight > 0) {
mgr.applyCandleOnlyLayout(true, wrap.clientHeight);
}
}, []);
syncChartLayout();
}, [syncChartLayout]);
const applyRealtimeBar = useCallback((bar: OHLCVBar, append: boolean) => {
if (barsMarketRef.current !== marketRef.current) return;
@@ -147,12 +155,6 @@ const VirtualTargetCardChart: React.FC<Props> = ({
const barsReady = bars.length >= 2 && barsMarket === market;
const applyPaneHeights = useCallback(() => {
const wrap = canvasWrapRef.current;
const mgr = managerRef.current;
if (!wrap || wrap.clientHeight <= 0 || !mgr?.hasMainSeries()) return;
mgr.applyCandleOnlyLayout(true, wrap.clientHeight);
}, []);
const requestChartReload = useCallback(() => {
chartReloadTriggeredRef.current = true;
@@ -169,38 +171,36 @@ const VirtualTargetCardChart: React.FC<Props> = ({
const wrap = canvasWrapRef.current;
if (!wrap) return;
const timers = [100, 300, 800, 1500, 2500].map(delay =>
const timers = [200, 600, 1200].map(delay =>
setTimeout(() => {
if (!canvasWrapRef.current) return;
const h = canvasWrapRef.current.clientHeight;
if (h <= 0) return;
if (managerRef.current?.hasMainSeries()) {
managerRef.current.applyCandleOnlyLayout(true, h);
} else if (!chartReloadTriggeredRef.current && delay >= 800 && barsReady) {
syncChartLayout();
} else if (!chartReloadTriggeredRef.current && delay >= 600 && barsReady) {
requestChartReload();
}
}, delay),
);
const ro = new ResizeObserver(() => applyPaneHeights());
const ro = new ResizeObserver(() => syncChartLayout());
ro.observe(wrap);
return () => {
timers.forEach(clearTimeout);
ro.disconnect();
};
}, [market, timeframe, barsReady, applyPaneHeights, requestChartReload]);
}, [market, timeframe, barsReady, syncChartLayout, requestChartReload]);
useEffect(() => {
if (!barsReady) return;
if (managerRef.current?.hasMainSeries()) {
applyPaneHeights();
syncChartLayout();
return;
}
if (!chartReloadTriggeredRef.current) {
requestChartReload();
}
}, [barsReady, applyPaneHeights, requestChartReload]);
}, [barsReady, syncChartLayout, requestChartReload]);
useEffect(() => {
if (!streamActive) return;
@@ -265,9 +265,10 @@ const VirtualTargetCardChart: React.FC<Props> = ({
volumeVisible={false}
paneLayoutClamp
showHoverToolbar={false}
showPaneLegend={false}
showPaneLegend
showChartRightToolbar={false}
showCandlePaneControls={false}
defaultCandleOnly
crosshairInfoVisible={false}
candleAreaPriceLabelsEnabled={chartCandleAreaPriceLabels}
indicatorAreaPriceLabelsEnabled={chartSeriesPriceLabels}
paneSeparatorOptions={chartPaneSeparator}