63 lines
1.8 KiB
TypeScript
63 lines
1.8 KiB
TypeScript
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,
|
|
};
|
|
}
|