Files
auto-trade/features/dashboard/utils/kis-stock-realtime.utils.ts

70 lines
2.2 KiB
TypeScript
Raw Normal View History

2026-02-13 12:17:35 +09:00
export interface KisRealtimeStockTick {
symbol: string; // 종목코드
time: string; // 체결시간
currentPrice: number; // 현재가
sign: string; // 전일대비부호 (1:상한, 2:상승, 3:보합, 4:하한, 5:하락)
change: number; // 전일대비
changeRate: number; // 전일대비율
accumulatedVolume: number; // 누적거래량
}
const STOCK_realtime_TR_ID = "H0STCNT0";
// H0STCNT0 Output format indices based on typical KIS Realtime API
// Format: MKSC_SHRN_ISCD^STCK_CNTG_HOUR^STCK_PRPR^PRDY_VRSS_SIGN^PRDY_VRSS^PRDY_CTRT^...
const STOCK_FIELD_INDEX = {
symbol: 0, // MKSC_SHRN_ISCD
time: 1, // STCK_CNTG_HOUR
currentPrice: 2, // STCK_PRPR
sign: 3, // PRDY_VRSS_SIGN
change: 4, // PRDY_VRSS
changeRate: 5, // PRDY_CTRT
accumulatedVolume: 12, // ACML_VOL (Usually at index 12 or similar, need to be careful here)
} as const;
export function parseKisRealtimeStockTick(
raw: string,
): KisRealtimeStockTick | null {
// Format: 0|H0STCNT0|001|SYMBOL^TIME^PRICE^SIGN^CHANGE^...
if (!/^([01])\|/.test(raw)) return null;
const parts = raw.split("|");
if (parts.length < 4) return null;
// Check TR ID
if (parts[1] !== STOCK_realtime_TR_ID) {
return null;
}
const values = parts[3].split("^");
if (values.length < 6) return null; // Ensure minimum fields exist
const symbol = values[STOCK_FIELD_INDEX.symbol];
const currentPrice = parseFloat(values[STOCK_FIELD_INDEX.currentPrice]);
const sign = values[STOCK_FIELD_INDEX.sign];
const changeRaw = parseFloat(values[STOCK_FIELD_INDEX.change]);
const changeRateRaw = parseFloat(values[STOCK_FIELD_INDEX.changeRate]);
// Adjust sign for negative values if necessary
const isNegative = sign === "5" || sign === "4"; // 5: 하락, 4: 하한
const change = isNegative ? -Math.abs(changeRaw) : Math.abs(changeRaw);
const changeRate = isNegative
? -Math.abs(changeRateRaw)
: Math.abs(changeRateRaw);
// Validate numeric values
if (isNaN(currentPrice)) return null;
return {
symbol,
time: values[STOCK_FIELD_INDEX.time],
currentPrice,
sign,
change,
changeRate,
accumulatedVolume:
parseFloat(values[STOCK_FIELD_INDEX.accumulatedVolume]) || 0,
};
}