차트 수정
This commit is contained in:
@@ -192,21 +192,12 @@ export const useKisWebSocketStore = create<KisWebSocketState>((set, get) => ({
|
||||
const parts = data.split("|");
|
||||
if (parts.length >= 4) {
|
||||
const trId = parts[1];
|
||||
// 데이터 부분 (마지막 부분)에서 종목코드를 찾아야 함.
|
||||
// 하지만 응답에는 종목코드가 명시적으로 없는 경우가 많음 (순서로 추론).
|
||||
// 다행히 KIS API는 요청했던 TR_ID와 수신된 데이터의 호가/체결 데이터를 매핑해야 함.
|
||||
// 여기서는 모든 구독자에게 브로드캐스트하는 방식을 사용 (TR_ID 기준).
|
||||
|
||||
// 더 정확한 라우팅을 위해:
|
||||
// 실시간 체결/호가 데이터에는 종목코드가 포함되어 있음.
|
||||
// 체결(H0STCNT0): data.split("^")[0] (유가증권 단축종목코드)
|
||||
const body = parts[3];
|
||||
const values = body.split("^");
|
||||
const symbol = values[0]; // 대부분 첫 번째 필드가 종목코드
|
||||
const symbol = values[0] ?? "";
|
||||
|
||||
const key = `${trId}|${symbol}`;
|
||||
const callbacks = subscribers.get(key);
|
||||
callbacks?.forEach((cb) => cb(data));
|
||||
// UI 흐름: 소켓 수신 -> TR/심볼 정규화 매칭 -> 해당 구독 콜백 실행 -> 훅 파서(parseKisRealtime*) -> 화면 반영
|
||||
dispatchRealtimeMessageToSubscribers(trId, symbol, data);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -384,3 +375,67 @@ function waitForSocketClose(target: WebSocket, timeoutMs = 2_000) {
|
||||
target.addEventListener("error", onError);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 실시간 데이터(TR/종목코드)와 등록된 구독자를 매칭해 콜백을 실행합니다.
|
||||
* 종목코드 접두(prefix) 차이(A005930/J005930 등)와 구독 심볼 형식 차이를 허용합니다.
|
||||
* @param trId 수신 TR ID
|
||||
* @param rawSymbol 수신 데이터의 원본 종목코드
|
||||
* @param payload 웹소켓 원문 메시지
|
||||
* @see features/trade/hooks/useTradeTickSubscription.ts 체결 구독 콜백
|
||||
* @see features/trade/hooks/useOrderbookSubscription.ts 호가 구독 콜백
|
||||
*/
|
||||
function dispatchRealtimeMessageToSubscribers(
|
||||
trId: string,
|
||||
rawSymbol: string,
|
||||
payload: string,
|
||||
) {
|
||||
const callbackSet = new Set<RealtimeCallback>();
|
||||
const normalizedIncomingSymbol = normalizeRealtimeSymbol(rawSymbol);
|
||||
|
||||
// 1) 정확히 일치하는 key 우선
|
||||
const exactKey = `${trId}|${rawSymbol}`;
|
||||
subscribers.get(exactKey)?.forEach((callback) => callbackSet.add(callback));
|
||||
|
||||
// 2) 숫자 6자리 기준(정규화)으로 일치하는 key 매칭
|
||||
subscribers.forEach((callbacks, key) => {
|
||||
const [subscribedTrId, subscribedSymbol = ""] = key.split("|");
|
||||
if (subscribedTrId !== trId) return;
|
||||
if (!normalizedIncomingSymbol) return;
|
||||
|
||||
const normalizedSubscribedSymbol = normalizeRealtimeSymbol(subscribedSymbol);
|
||||
if (!normalizedSubscribedSymbol) return;
|
||||
if (normalizedIncomingSymbol !== normalizedSubscribedSymbol) return;
|
||||
|
||||
callbacks.forEach((callback) => callbackSet.add(callback));
|
||||
});
|
||||
|
||||
// 3) 심볼 매칭이 실패한 경우에도 같은 TR 전체 콜백으로 안전 fallback
|
||||
if (callbackSet.size === 0) {
|
||||
subscribers.forEach((callbacks, key) => {
|
||||
const [subscribedTrId] = key.split("|");
|
||||
if (subscribedTrId !== trId) return;
|
||||
callbacks.forEach((callback) => callbackSet.add(callback));
|
||||
});
|
||||
}
|
||||
|
||||
callbackSet.forEach((callback) => callback(payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 실시간 종목코드를 비교 가능한 6자리 숫자 코드로 정규화합니다.
|
||||
* @param value 원본 종목코드 (예: 005930, A005930)
|
||||
* @returns 정규화된 6자리 코드. 파싱 불가 시 원본 trim 값 반환
|
||||
* @see features/kis-realtime/stores/kisWebSocketStore.ts dispatchRealtimeMessageToSubscribers
|
||||
*/
|
||||
function normalizeRealtimeSymbol(value: string) {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return "";
|
||||
|
||||
const digits = trimmed.replace(/\D/g, "");
|
||||
if (digits.length >= 6) {
|
||||
return digits.slice(-6);
|
||||
}
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user