/** * @file lib/kis/config.ts * @description KIS 거래 환경(real/mock) 설정과 키/도메인 로딩 */ export type KisTradingEnv = "real" | "mock"; export interface KisCredentialInput { tradingEnv?: KisTradingEnv; appKey?: string; appSecret?: string; baseUrl?: string; } export interface KisConfig { tradingEnv: KisTradingEnv; appKey: string; appSecret: string; baseUrl: string; } const DEFAULT_KIS_REAL_BASE_URL = "https://openapi.koreainvestment.com:9443"; const DEFAULT_KIS_MOCK_BASE_URL = "https://openapivts.koreainvestment.com:29443"; const DEFAULT_KIS_REAL_WS_URL = "ws://ops.koreainvestment.com:21000"; const DEFAULT_KIS_MOCK_WS_URL = "ws://ops.koreainvestment.com:31000"; /** * 거래 환경 문자열을 정규화합니다. * @param value 환경값 * @returns real | mock */ export function normalizeTradingEnv(value?: string): KisTradingEnv { return (value ?? "mock").toLowerCase() === "real" ? "real" : "mock"; } /** * 현재 거래 환경을 반환합니다. * @returns real | mock */ export function getKisTradingEnv() { return normalizeTradingEnv(process.env.KIS_TRADING_ENV); } /** * KIS 웹소켓 URL을 반환합니다. * @param tradingEnvInput 거래 모드(real/mock) * @returns websocket base url */ export function getKisWebSocketUrl(tradingEnvInput?: KisTradingEnv) { const tradingEnv = normalizeTradingEnv(tradingEnvInput); if (tradingEnv === "real") { return process.env.KIS_WS_URL_REAL ?? DEFAULT_KIS_REAL_WS_URL; } return process.env.KIS_WS_URL_MOCK ?? DEFAULT_KIS_MOCK_WS_URL; } /** * 설정 준비 여부를 확인합니다. * @param input 외부(사용자 입력) 키가 있으면 우선 사용 * @returns 사용 가능 여부 */ export function hasKisConfig(input?: KisCredentialInput) { if (input?.appKey && input?.appSecret) return true; const env = getKisTradingEnv(); if (env === "real") { return Boolean(process.env.KIS_APP_KEY_REAL && process.env.KIS_APP_SECRET_REAL); } return Boolean(process.env.KIS_APP_KEY_MOCK && process.env.KIS_APP_SECRET_MOCK); } /** * KIS 호출에 필요한 설정을 반환합니다. * @param input 사용자 입력 키(선택) * @returns tradingEnv/appKey/appSecret/baseUrl */ export function getKisConfig(input?: KisCredentialInput): KisConfig { if (input?.appKey && input?.appSecret) { const tradingEnv = normalizeTradingEnv(input.tradingEnv); const baseUrl = input.baseUrl ?? (tradingEnv === "real" ? DEFAULT_KIS_REAL_BASE_URL : DEFAULT_KIS_MOCK_BASE_URL); return { tradingEnv, appKey: input.appKey, appSecret: input.appSecret, baseUrl, }; } const tradingEnv = getKisTradingEnv(); if (tradingEnv === "real") { const appKey = process.env.KIS_APP_KEY_REAL; const appSecret = process.env.KIS_APP_SECRET_REAL; const baseUrl = process.env.KIS_BASE_URL_REAL ?? DEFAULT_KIS_REAL_BASE_URL; if (!appKey || !appSecret) { throw new Error( "KIS 실전투자 키가 없습니다. KIS_APP_KEY_REAL, KIS_APP_SECRET_REAL 환경변수를 설정하세요.", ); } return { tradingEnv, appKey, appSecret, baseUrl }; } const appKey = process.env.KIS_APP_KEY_MOCK; const appSecret = process.env.KIS_APP_SECRET_MOCK; const baseUrl = process.env.KIS_BASE_URL_MOCK ?? DEFAULT_KIS_MOCK_BASE_URL; if (!appKey || !appSecret) { throw new Error( "KIS 모의투자 키가 없습니다. KIS_APP_KEY_MOCK, KIS_APP_SECRET_MOCK 환경변수를 설정하세요.", ); } return { tradingEnv, appKey, appSecret, baseUrl }; }