Files
auto-trade/features/trade/hooks/useStockOverview.ts

105 lines
3.1 KiB
TypeScript
Raw Normal View History

2026-02-10 11:16:39 +09:00
import { useCallback, useState, useTransition } from "react";
2026-02-11 16:31:28 +09:00
import type { KisRuntimeCredentials } from "@/features/settings/store/use-kis-runtime-store";
2026-02-10 11:16:39 +09:00
import type {
DashboardMarketPhase,
DashboardPriceSource,
DashboardRealtimeTradeTick,
DashboardStockSearchItem,
DashboardStockItem,
2026-02-11 16:31:28 +09:00
} from "@/features/trade/types/trade.types";
import { fetchStockOverview } from "@/features/trade/apis/kis-stock.api";
2026-02-10 11:16:39 +09:00
interface OverviewMeta {
priceSource: DashboardPriceSource;
marketPhase: DashboardMarketPhase;
fetchedAt: string;
}
export function useStockOverview() {
const [selectedStock, setSelectedStock] = useState<DashboardStockItem | null>(
null,
);
const [meta, setMeta] = useState<OverviewMeta | null>(null);
const [error, setError] = useState<string | null>(null);
const [isLoading, startTransition] = useTransition();
const loadOverview = useCallback(
(
symbol: string,
credentials: KisRuntimeCredentials | null,
marketHint?: DashboardStockSearchItem["market"],
) => {
if (!credentials) return;
startTransition(async () => {
try {
setError(null);
const data = await fetchStockOverview(symbol, credentials);
setSelectedStock({
...data.stock,
market: marketHint ?? data.stock.market,
});
setMeta({
priceSource: data.priceSource,
marketPhase: data.marketPhase,
fetchedAt: data.fetchedAt,
});
} catch (err) {
const message =
err instanceof Error
? err.message
: "종목 조회 중 오류가 발생했습니다.";
setError(message);
setMeta(null);
}
});
},
[],
);
2026-02-11 11:18:15 +09:00
/**
* / .
* StockLineChart API .
2026-02-11 16:31:28 +09:00
* @see features/trade/components/TradeContainer.tsx useKisTradeWebSocket onTick
* @see features/trade/components/chart/StockLineChart.tsx fetchStockChart
2026-02-11 11:18:15 +09:00
*/
2026-02-10 11:16:39 +09:00
const updateRealtimeTradeTick = useCallback(
(tick: DashboardRealtimeTradeTick) => {
setSelectedStock((prev) => {
if (!prev) return prev;
2026-02-11 11:18:15 +09:00
const { price, accumulatedVolume, change, changeRate } = tick;
2026-02-10 11:16:39 +09:00
const nextChange = change;
const nextChangeRate = Number.isFinite(changeRate)
? changeRate
: prev.prevClose > 0
? (nextChange / prev.prevClose) * 100
: prev.changeRate;
return {
...prev,
currentPrice: price,
change: nextChange,
changeRate: nextChangeRate,
2026-02-11 11:18:15 +09:00
high: prev.high > 0 ? Math.max(prev.high, price) : price,
low: prev.low > 0 ? Math.min(prev.low, price) : price,
2026-02-10 11:16:39 +09:00
volume: accumulatedVolume > 0 ? accumulatedVolume : prev.volume,
};
});
},
[],
);
return {
selectedStock,
setSelectedStock,
meta,
setMeta,
error,
setError,
isLoading,
loadOverview,
updateRealtimeTradeTick,
};
}