From 3585357e0ea2e8463be5cd0a252927143818a7ae Mon Sep 17 00:00:00 2001 From: shuim Date: Fri, 27 Feb 2026 09:11:49 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8C=80=EC=8B=9C=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/OrderbookPanel.tsx | 37 +++++++--------------- frontend/src/pages/Dashboard.tsx | 22 ++++++++++++- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/frontend/src/components/OrderbookPanel.tsx b/frontend/src/components/OrderbookPanel.tsx index 2150a06..36a941d 100644 --- a/frontend/src/components/OrderbookPanel.tsx +++ b/frontend/src/components/OrderbookPanel.tsx @@ -15,34 +15,19 @@ const OrderbookPanel = React.memo(({ orderbook }: OrderbookPanelProps) => {
{orderbook ? (() => { const currentPrice = orderbook.current_price - const priceUnit = - currentPrice < 1000 ? 1 - : currentPrice < 5000 ? 5 - : currentPrice < 10000 ? 10 - : currentPrice < 50000 ? 50 - : currentPrice < 100000 ? 100 - : currentPrice < 500000 ? 500 - : 1000 - const steps = 10 - - const sequentialAsks: { price: number; volume: number }[] = [] - for (let i = steps; i >= 1; i--) { - const price = currentPrice + priceUnit * i - const existingAsk = orderbook.asks?.find((ask: any) => ask.price === price) - sequentialAsks.push({ price, volume: existingAsk ? existingAsk.volume : 0 }) - } - - const sequentialBids: { price: number; volume: number }[] = [] - for (let i = 1; i <= steps; i++) { - const price = currentPrice - priceUnit * i - const existingBid = orderbook.bids?.find((bid: any) => bid.price === price) - sequentialBids.push({ price, volume: existingBid ? existingBid.volume : 0 }) - } + // 높은 가격 → 낮은 가격 순으로 정렬된 매도호가 (최대 10개) + const asks: { price: number; volume: number }[] = [...(orderbook.asks || [])] + .sort((a, b) => b.price - a.price) + .slice(0, 10) + // 높은 가격 → 낮은 가격 순으로 정렬된 매수호가 (최대 10개) + const bids: { price: number; volume: number }[] = [...(orderbook.bids || [])] + .sort((a, b) => b.price - a.price) + .slice(0, 10) return (
- {sequentialAsks.map((ask, i) => ( + {asks.map((ask, i) => (
{ask.volume > 0 ? ask.volume.toLocaleString() : '-'} @@ -66,11 +51,11 @@ const OrderbookPanel = React.memo(({ orderbook }: OrderbookPanelProps) => {
)}
-
연속 호가창
+
실시간 호가창
- {sequentialBids.map((bid, i) => ( + {bids.map((bid, i) => (
diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index b13d0f6..f665098 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -267,6 +267,26 @@ const Dashboard = () => { setLiveQuote(null) }, [selectedStock]) + // 실시간 평가손익/총자산 — livePrices 기반 매 틱마다 재계산 + const liveSummary = useMemo(() => { + if (!portfolioSummary || !portfolio) return portfolioSummary + const liveValue = portfolio.reduce((sum, s) => { + const price = livePrices[s.stock_code] ?? Number(s.current_price || 0) + return sum + price * Number(s.quantity || 0) + }, 0) + const totalInvestment = portfolio.reduce((sum, s) => + sum + Number(s.average_price || 0) * Number(s.quantity || 0), 0) + const liveProfitLoss = liveValue - totalInvestment + const liveProfitLossRate = totalInvestment > 0 ? (liveProfitLoss / totalInvestment) * 100 : 0 + return { + ...portfolioSummary, + total_value: liveValue, + total_profit_loss: liveProfitLoss, + total_profit_loss_rate: liveProfitLossRate, + total_assets: (portfolioSummary.available_cash || 0) + liveValue, + } + }, [portfolioSummary, portfolio, livePrices]) + // 실시간 차트: 마지막 캔들에 live price 반영 (close/high/low) // livePrice가 selectedStock에 대해서만 변경될 때 재계산 const livePrice = livePrices[selectedStock] @@ -488,7 +508,7 @@ const Dashboard = () => {
- +