가상매매 챠트모드 수정
This commit is contained in:
@@ -2,7 +2,6 @@ import React, { memo, useMemo } from 'react';
|
|||||||
import type { StrategyDto } from '../../utils/backendApi';
|
import type { StrategyDto } from '../../utils/backendApi';
|
||||||
import {
|
import {
|
||||||
resolveVirtualTargetNames,
|
resolveVirtualTargetNames,
|
||||||
resolveVirtualTargetStrategyDisplayName,
|
|
||||||
} from '../../utils/virtualTargetNames';
|
} from '../../utils/virtualTargetNames';
|
||||||
import { resolveVirtualTargetStrategyId } from '../../utils/virtualTargetStrategy';
|
import { resolveVirtualTargetStrategyId } from '../../utils/virtualTargetStrategy';
|
||||||
import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots';
|
import type { VirtualIndicatorSnapshot } from '../../hooks/useVirtualIndicatorSnapshots';
|
||||||
@@ -100,11 +99,6 @@ const VirtualTargetCard: React.FC<Props> = ({
|
|||||||
koreanName ?? ticker?.koreanName,
|
koreanName ?? ticker?.koreanName,
|
||||||
englishName,
|
englishName,
|
||||||
);
|
);
|
||||||
const strategyDisplayName = resolveVirtualTargetStrategyDisplayName(
|
|
||||||
strategy,
|
|
||||||
strategies,
|
|
||||||
readOnlyStrategyLabel,
|
|
||||||
);
|
|
||||||
const rows = snapshot?.rows ?? [];
|
const rows = snapshot?.rows ?? [];
|
||||||
const effectiveStrategyId = resolveVirtualTargetStrategyId(
|
const effectiveStrategyId = resolveVirtualTargetStrategyId(
|
||||||
{ strategyId },
|
{ strategyId },
|
||||||
@@ -160,10 +154,7 @@ const VirtualTargetCard: React.FC<Props> = ({
|
|||||||
<div className="vtd-card-head-main">
|
<div className="vtd-card-head-main">
|
||||||
<div className={`vtd-card-title${isChart ? ' vtd-card-title--chart' : ''}`}>
|
<div className={`vtd-card-title${isChart ? ' vtd-card-title--chart' : ''}`}>
|
||||||
{isChart ? (
|
{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>
|
<span className="vtd-card-ko">{displayKo}</span>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { useHistoryLoader } from '../../hooks/useHistoryLoader';
|
|||||||
import { useIndicatorSettings } from '../../hooks/useIndicatorSettings';
|
import { useIndicatorSettings } from '../../hooks/useIndicatorSettings';
|
||||||
import type { ChartManager } from '../../utils/ChartManager';
|
import type { ChartManager } from '../../utils/ChartManager';
|
||||||
import {
|
import {
|
||||||
buildVirtualTradingCardChartIndicators,
|
buildStrategyChartIndicators,
|
||||||
buildVirtualTradingChartIndicators,
|
buildVirtualTradingChartIndicators,
|
||||||
resolveStrategyPrimaryTimeframe,
|
resolveStrategyPrimaryTimeframe,
|
||||||
resolveStrategyTimeframes,
|
resolveStrategyTimeframes,
|
||||||
@@ -73,7 +73,7 @@ const VirtualTargetCardChart: React.FC<Props> = ({
|
|||||||
const indicators = useMemo(() => (
|
const indicators = useMemo(() => (
|
||||||
fillHeight
|
fillHeight
|
||||||
? buildVirtualTradingChartIndicators(strategy, getParams, getVisualConfig)
|
? buildVirtualTradingChartIndicators(strategy, getParams, getVisualConfig)
|
||||||
: buildVirtualTradingCardChartIndicators(strategy, getParams, getVisualConfig)
|
: buildStrategyChartIndicators(strategy, getParams, getVisualConfig)
|
||||||
), [strategy, getParams, getVisualConfig, fillHeight]);
|
), [strategy, getParams, getVisualConfig, fillHeight]);
|
||||||
|
|
||||||
const effectiveIndicators = useMemo(
|
const effectiveIndicators = useMemo(
|
||||||
@@ -91,6 +91,17 @@ const VirtualTargetCardChart: React.FC<Props> = ({
|
|||||||
const marketRef = useRef(market);
|
const marketRef = useRef(market);
|
||||||
marketRef.current = 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(() => {
|
const handleCandlesReady = useCallback(() => {
|
||||||
chartLiveReadyRef.current = true;
|
chartLiveReadyRef.current = true;
|
||||||
const pending = pendingBarRef.current;
|
const pending = pendingBarRef.current;
|
||||||
@@ -98,11 +109,8 @@ const VirtualTargetCardChart: React.FC<Props> = ({
|
|||||||
if (!pending || !mgr || barsMarketRef.current !== marketRef.current) return;
|
if (!pending || !mgr || barsMarketRef.current !== marketRef.current) return;
|
||||||
pendingBarRef.current = null;
|
pendingBarRef.current = null;
|
||||||
mgr.updateBar(pending);
|
mgr.updateBar(pending);
|
||||||
const wrap = canvasWrapRef.current;
|
syncChartLayout();
|
||||||
if (wrap && wrap.clientHeight > 0) {
|
}, [syncChartLayout]);
|
||||||
mgr.applyCandleOnlyLayout(true, wrap.clientHeight);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const applyRealtimeBar = useCallback((bar: OHLCVBar, append: boolean) => {
|
const applyRealtimeBar = useCallback((bar: OHLCVBar, append: boolean) => {
|
||||||
if (barsMarketRef.current !== marketRef.current) return;
|
if (barsMarketRef.current !== marketRef.current) return;
|
||||||
@@ -147,12 +155,6 @@ const VirtualTargetCardChart: React.FC<Props> = ({
|
|||||||
|
|
||||||
const barsReady = bars.length >= 2 && barsMarket === market;
|
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(() => {
|
const requestChartReload = useCallback(() => {
|
||||||
chartReloadTriggeredRef.current = true;
|
chartReloadTriggeredRef.current = true;
|
||||||
@@ -169,38 +171,36 @@ const VirtualTargetCardChart: React.FC<Props> = ({
|
|||||||
const wrap = canvasWrapRef.current;
|
const wrap = canvasWrapRef.current;
|
||||||
if (!wrap) return;
|
if (!wrap) return;
|
||||||
|
|
||||||
const timers = [100, 300, 800, 1500, 2500].map(delay =>
|
const timers = [200, 600, 1200].map(delay =>
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!canvasWrapRef.current) return;
|
if (!canvasWrapRef.current) return;
|
||||||
const h = canvasWrapRef.current.clientHeight;
|
|
||||||
if (h <= 0) return;
|
|
||||||
if (managerRef.current?.hasMainSeries()) {
|
if (managerRef.current?.hasMainSeries()) {
|
||||||
managerRef.current.applyCandleOnlyLayout(true, h);
|
syncChartLayout();
|
||||||
} else if (!chartReloadTriggeredRef.current && delay >= 800 && barsReady) {
|
} else if (!chartReloadTriggeredRef.current && delay >= 600 && barsReady) {
|
||||||
requestChartReload();
|
requestChartReload();
|
||||||
}
|
}
|
||||||
}, delay),
|
}, delay),
|
||||||
);
|
);
|
||||||
|
|
||||||
const ro = new ResizeObserver(() => applyPaneHeights());
|
const ro = new ResizeObserver(() => syncChartLayout());
|
||||||
ro.observe(wrap);
|
ro.observe(wrap);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
timers.forEach(clearTimeout);
|
timers.forEach(clearTimeout);
|
||||||
ro.disconnect();
|
ro.disconnect();
|
||||||
};
|
};
|
||||||
}, [market, timeframe, barsReady, applyPaneHeights, requestChartReload]);
|
}, [market, timeframe, barsReady, syncChartLayout, requestChartReload]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!barsReady) return;
|
if (!barsReady) return;
|
||||||
if (managerRef.current?.hasMainSeries()) {
|
if (managerRef.current?.hasMainSeries()) {
|
||||||
applyPaneHeights();
|
syncChartLayout();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!chartReloadTriggeredRef.current) {
|
if (!chartReloadTriggeredRef.current) {
|
||||||
requestChartReload();
|
requestChartReload();
|
||||||
}
|
}
|
||||||
}, [barsReady, applyPaneHeights, requestChartReload]);
|
}, [barsReady, syncChartLayout, requestChartReload]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!streamActive) return;
|
if (!streamActive) return;
|
||||||
@@ -265,9 +265,10 @@ const VirtualTargetCardChart: React.FC<Props> = ({
|
|||||||
volumeVisible={false}
|
volumeVisible={false}
|
||||||
paneLayoutClamp
|
paneLayoutClamp
|
||||||
showHoverToolbar={false}
|
showHoverToolbar={false}
|
||||||
showPaneLegend={false}
|
showPaneLegend
|
||||||
|
showChartRightToolbar={false}
|
||||||
showCandlePaneControls={false}
|
showCandlePaneControls={false}
|
||||||
defaultCandleOnly
|
crosshairInfoVisible={false}
|
||||||
candleAreaPriceLabelsEnabled={chartCandleAreaPriceLabels}
|
candleAreaPriceLabelsEnabled={chartCandleAreaPriceLabels}
|
||||||
indicatorAreaPriceLabelsEnabled={chartSeriesPriceLabels}
|
indicatorAreaPriceLabelsEnabled={chartSeriesPriceLabels}
|
||||||
paneSeparatorOptions={chartPaneSeparator}
|
paneSeparatorOptions={chartPaneSeparator}
|
||||||
|
|||||||
@@ -1608,6 +1608,22 @@
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 보조지표 pane 좌측 상단 지표명 */
|
||||||
|
.vtd-card-chart-canvas .pane-legend-item {
|
||||||
|
right: 46px;
|
||||||
|
width: auto;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtd-card-chart-canvas .pane-legend-name {
|
||||||
|
font-size: 10px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
max-width: none;
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: clip;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.vtd-card-chart-canvas > .tv-chart-wrap {
|
.vtd-card-chart-canvas > .tv-chart-wrap {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user