대시보드 실시간 기능 추가
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import type { KisRuntimeCredentials } from "@/features/settings/store/use-kis-runtime-store";
|
||||
import type { DashboardStockOrderBookResponse } from "@/features/trade/types/trade.types";
|
||||
import { fetchStockOrderBook } from "@/features/trade/apis/kis-stock.api";
|
||||
@@ -29,9 +29,22 @@ export function useOrderBook(
|
||||
|
||||
const [initialData, setInitialData] =
|
||||
useState<DashboardStockOrderBookResponse | null>(null);
|
||||
const [lastRealtimeWithLevels, setLastRealtimeWithLevels] =
|
||||
useState<DashboardStockOrderBookResponse | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRequestEnabled) {
|
||||
setLastRealtimeWithLevels(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (externalRealtimeOrderBook && hasOrderBookLevelData(externalRealtimeOrderBook)) {
|
||||
setLastRealtimeWithLevels(externalRealtimeOrderBook);
|
||||
}
|
||||
}, [externalRealtimeOrderBook, isRequestEnabled]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRequestEnabled || !symbol || !credentials) {
|
||||
return;
|
||||
@@ -75,10 +88,67 @@ export function useOrderBook(
|
||||
};
|
||||
}, [isRequestEnabled, symbol, credentials]);
|
||||
|
||||
// 외부 실시간 호가 → 초기 데이터 → null 순 우선
|
||||
const orderBook = isRequestEnabled
|
||||
? (externalRealtimeOrderBook ?? initialData)
|
||||
: null;
|
||||
// 외부 실시간 호가가 비어 있으면(가격/잔량 레벨 0) 마지막 정상 실시간 또는 REST 초기값을 유지합니다.
|
||||
const orderBook = useMemo(() => {
|
||||
if (!isRequestEnabled) return null;
|
||||
|
||||
if (externalRealtimeOrderBook) {
|
||||
if (hasOrderBookLevelData(externalRealtimeOrderBook)) {
|
||||
return externalRealtimeOrderBook;
|
||||
}
|
||||
|
||||
if (lastRealtimeWithLevels) {
|
||||
return {
|
||||
...lastRealtimeWithLevels,
|
||||
totalAskSize: externalRealtimeOrderBook.totalAskSize,
|
||||
totalBidSize: externalRealtimeOrderBook.totalBidSize,
|
||||
anticipatedPrice: externalRealtimeOrderBook.anticipatedPrice,
|
||||
anticipatedVolume: externalRealtimeOrderBook.anticipatedVolume,
|
||||
anticipatedTotalVolume: externalRealtimeOrderBook.anticipatedTotalVolume,
|
||||
anticipatedChange: externalRealtimeOrderBook.anticipatedChange,
|
||||
anticipatedChangeSign: externalRealtimeOrderBook.anticipatedChangeSign,
|
||||
anticipatedChangeRate: externalRealtimeOrderBook.anticipatedChangeRate,
|
||||
accumulatedVolume: externalRealtimeOrderBook.accumulatedVolume,
|
||||
totalAskSizeDelta: externalRealtimeOrderBook.totalAskSizeDelta,
|
||||
totalBidSizeDelta: externalRealtimeOrderBook.totalBidSizeDelta,
|
||||
businessHour:
|
||||
externalRealtimeOrderBook.businessHour ?? lastRealtimeWithLevels.businessHour,
|
||||
hourClassCode:
|
||||
externalRealtimeOrderBook.hourClassCode ?? lastRealtimeWithLevels.hourClassCode,
|
||||
fetchedAt: externalRealtimeOrderBook.fetchedAt,
|
||||
tradingEnv: externalRealtimeOrderBook.tradingEnv,
|
||||
source: externalRealtimeOrderBook.source,
|
||||
};
|
||||
}
|
||||
|
||||
if (initialData && hasOrderBookLevelData(initialData)) {
|
||||
return {
|
||||
...initialData,
|
||||
totalAskSize: externalRealtimeOrderBook.totalAskSize,
|
||||
totalBidSize: externalRealtimeOrderBook.totalBidSize,
|
||||
anticipatedPrice: externalRealtimeOrderBook.anticipatedPrice,
|
||||
anticipatedVolume: externalRealtimeOrderBook.anticipatedVolume,
|
||||
anticipatedTotalVolume: externalRealtimeOrderBook.anticipatedTotalVolume,
|
||||
anticipatedChange: externalRealtimeOrderBook.anticipatedChange,
|
||||
anticipatedChangeSign: externalRealtimeOrderBook.anticipatedChangeSign,
|
||||
anticipatedChangeRate: externalRealtimeOrderBook.anticipatedChangeRate,
|
||||
accumulatedVolume: externalRealtimeOrderBook.accumulatedVolume,
|
||||
totalAskSizeDelta: externalRealtimeOrderBook.totalAskSizeDelta,
|
||||
totalBidSizeDelta: externalRealtimeOrderBook.totalBidSizeDelta,
|
||||
businessHour: externalRealtimeOrderBook.businessHour ?? initialData.businessHour,
|
||||
hourClassCode: externalRealtimeOrderBook.hourClassCode ?? initialData.hourClassCode,
|
||||
fetchedAt: externalRealtimeOrderBook.fetchedAt,
|
||||
tradingEnv: externalRealtimeOrderBook.tradingEnv,
|
||||
source: externalRealtimeOrderBook.source,
|
||||
};
|
||||
}
|
||||
|
||||
return externalRealtimeOrderBook;
|
||||
}
|
||||
|
||||
return initialData;
|
||||
}, [externalRealtimeOrderBook, initialData, isRequestEnabled, lastRealtimeWithLevels]);
|
||||
|
||||
const mergedError = isRequestEnabled ? error : null;
|
||||
const mergedLoading = isRequestEnabled ? isLoading && !orderBook : false;
|
||||
|
||||
@@ -89,3 +159,13 @@ export function useOrderBook(
|
||||
isWsConnected: !!externalRealtimeOrderBook,
|
||||
};
|
||||
}
|
||||
|
||||
function hasOrderBookLevelData(orderBook: DashboardStockOrderBookResponse) {
|
||||
return orderBook.levels.some(
|
||||
(level) =>
|
||||
level.askPrice > 0 ||
|
||||
level.bidPrice > 0 ||
|
||||
level.askSize > 0 ||
|
||||
level.bidSize > 0,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user