From 339e2355eb780d31c649fb2b7018be3abbcda138 Mon Sep 17 00:00:00 2001 From: Macbook Date: Mon, 25 May 2026 13:14:36 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B0=80=EC=83=81=ED=88=AC=EC=9E=90=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/TradingChart.tsx | 30 +- .../src/components/VirtualTradingPage.tsx | 166 ++-- .../virtual/ConditionStatusSignal.tsx | 50 ++ .../virtual/VirtualConditionList.tsx | 28 + .../virtual/VirtualGridUnifiedHeader.tsx | 181 ++++ .../virtual/VirtualIndicatorCompareTable.tsx | 38 +- .../virtual/VirtualLeftTargetPanel.tsx | 33 +- .../components/virtual/VirtualLiveBadge.tsx | 8 +- .../virtual/VirtualSessionToolbar.tsx | 103 +++ .../virtual/VirtualSignalTrafficLight.tsx | 4 +- .../virtual/VirtualStrategyChartPopup.tsx | 177 +--- .../components/virtual/VirtualTargetCard.tsx | 175 ++-- .../virtual/VirtualTargetCardChart.tsx | 221 +++++ .../virtual/VirtualTargetFocusView.tsx | 133 +++ .../components/virtual/VirtualTargetGrid.tsx | 178 ++-- .../components/virtual/VirtualTargetQuote.tsx | 70 ++ .../virtual/VirtualTargetSignalPanel.tsx | 81 ++ frontend/src/hooks/useLiveReceiveFlash.ts | 35 + .../src/hooks/useVirtualTargetLiveStatus.ts | 20 +- frontend/src/styles/builderPageShell.css | 4 +- frontend/src/styles/paperDashboard.css | 154 +++- .../src/styles/virtualTradingDashboard.css | 779 +++++++++++++++++- .../src/utils/strategyToChartIndicators.ts | 19 + 23 files changed, 2230 insertions(+), 457 deletions(-) create mode 100644 frontend/src/components/virtual/ConditionStatusSignal.tsx create mode 100644 frontend/src/components/virtual/VirtualConditionList.tsx create mode 100644 frontend/src/components/virtual/VirtualGridUnifiedHeader.tsx create mode 100644 frontend/src/components/virtual/VirtualSessionToolbar.tsx create mode 100644 frontend/src/components/virtual/VirtualTargetCardChart.tsx create mode 100644 frontend/src/components/virtual/VirtualTargetFocusView.tsx create mode 100644 frontend/src/components/virtual/VirtualTargetQuote.tsx create mode 100644 frontend/src/components/virtual/VirtualTargetSignalPanel.tsx create mode 100644 frontend/src/hooks/useLiveReceiveFlash.ts diff --git a/frontend/src/components/TradingChart.tsx b/frontend/src/components/TradingChart.tsx index 43d74df..707b2fa 100644 --- a/frontend/src/components/TradingChart.tsx +++ b/frontend/src/components/TradingChart.tsx @@ -96,6 +96,12 @@ interface TradingChartProps { onTradeOrderRequest?: (req: { market: string; price: number; side: 'buy' | 'sell' }) => void; /** 표시 시간대 (IANA) */ displayTimezone?: string; + /** 거래량 pane 표시 (기본 true) */ + volumeVisible?: boolean; + /** 하단 호버 줌·스크롤 툴바 (기본 true) */ + showHoverToolbar?: boolean; + /** 보조지표 우측 가격축 라벨·설명 (차트 설정, 기본 true) */ + seriesPriceLabelsEnabled?: boolean; } const TradingChart: React.FC = ({ @@ -122,6 +128,9 @@ const TradingChart: React.FC = ({ onRestoreIndicators, onTradeOrderRequest, displayTimezone = DEFAULT_DISPLAY_TIMEZONE, + volumeVisible = true, + showHoverToolbar = true, + seriesPriceLabelsEnabled = true, }) => { const containerRef = useRef(null); const wrapperRef = useRef(null); // 스크롤 래퍼 @@ -225,6 +234,20 @@ const TradingChart: React.FC = ({ } }, [mode, drawingTool]); + const volumeVisibleRef = useRef(volumeVisible); + useEffect(() => { volumeVisibleRef.current = volumeVisible; }, [volumeVisible]); + + useEffect(() => { + const mgr = managerRef.current; + if (!mgr) return; + const wrapperH = wrapperRef.current?.clientHeight ?? 0; + mgr.setVolumeVisible(volumeVisible, wrapperH > 0 ? wrapperH : undefined); + }, [volumeVisible]); + + useEffect(() => { + managerRef.current?.setSeriesPriceLabelsEnabled(seriesPriceLabelsEnabled); + }, [seriesPriceLabelsEnabled]); + /** * pane 높이 재배분 + 스크롤 컨테이너 확장 * @@ -509,6 +532,11 @@ const TradingChart: React.FC = ({ const mgr = new ChartManager(containerRef.current, theme); managerRef.current = mgr; setChartMgr(mgr); + if (!volumeVisibleRef.current) { + const wrapperH = wrapperRef.current?.clientHeight ?? 0; + mgr.setVolumeVisible(false, wrapperH > 0 ? wrapperH : undefined); + } + mgr.setSeriesPriceLabelsEnabled(seriesPriceLabelsEnabled); onManagerReady(mgr); const unsub = mgr.subscribeCrosshair((p: MouseEventParams