export interface KisRealtimeIndexTick { symbol: string; // 업종코드 (0001: KOSPI, 1001: KOSDAQ) price: number; // 현재가 change: number; // 전일대비 changeRate: number; // 전일대비율 sign: string; // 대비부호 time: string; // 체결시간 } const INDEX_REALTIME_TR_ID = "H0UPCNT0"; const INDEX_FIELD_INDEX = { symbol: 0, // bstp_cls_code time: 1, // bsop_hour price: 2, // prpr_nmix sign: 3, // prdy_vrss_sign change: 4, // bstp_nmix_prdy_vrss accumulatedVolume: 5, // acml_vol accumulatedAmount: 6, // acml_tr_pbmn changeRate: 9, // prdy_ctrt } as const; export function parseKisRealtimeIndexTick( raw: string, ): KisRealtimeIndexTick | null { // Format: 0|H0UPCNT0|001|0001^123456^... if (!/^([01])\|/.test(raw)) return null; const parts = raw.split("|"); if (parts.length < 4) return null; // Check TR ID if (parts[1] !== INDEX_REALTIME_TR_ID) { return null; } const values = parts[3].split("^"); if (values.length < 10) return null; // Ensure minimum fields exist const symbol = values[INDEX_FIELD_INDEX.symbol]; const price = parseFloat(values[INDEX_FIELD_INDEX.price]); const sign = values[INDEX_FIELD_INDEX.sign]; const changeRaw = parseFloat(values[INDEX_FIELD_INDEX.change]); const changeRateRaw = parseFloat(values[INDEX_FIELD_INDEX.changeRate]); // Adjust sign for negative values if necessary (usually API sends absolute values for change) 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); return { symbol, time: values[INDEX_FIELD_INDEX.time], price, change, changeRate, sign, }; }