Skip to content

Repository files navigation

krx-reader

CI License: MIT JVM

한국거래소(KRX) 공식 OPEN API를 위한 Kotlin 클라이언트. Java에서도 쓸 수 있습니다.

pykrx에서 영감을 받았습니다. 코드를 이식하지 않았고, 웹 스크래핑이 아니라 KRX 공식 OPEN API를 사용합니다.

같은 저자의 자매 프로젝트 — 공시·재무제표가 필요하다면 opendart-reader를 보세요. 이쪽은 시세, 그쪽은 공시입니다.

설치

dependencies {
    implementation("io.github.aaron-jang:krx-reader-core:0.1.0")
}

0.1.0은 첫 배포입니다. 13개 엔드포인트 전부 실제 응답으로 모델을 검증했지만 공개 API가 아직 실사용을 거치지 않았으므로 0.x로 시작합니다. 마이너 버전에서 시그니처가 바뀔 수 있습니다.

krx-reader-spring-boot-starterkrx-reader-dataframe도 같은 버전으로 함께 배포됩니다. 각 섹션에서 설명합니다.

인증키 발급

  1. https://openapi.krx.co.kr 에서 회원가입 후 로그인합니다.
  2. 마이페이지 → API 인증키 신청. 담당자 승인은 보통 1일 이내입니다.
  3. 사용할 엔드포인트를 각각 신청합니다. 인증키만으로는 아무 데이터도 받을 수 없습니다. 예를 들어 유가증권 일별매매정보를 쓰려면 그 서비스를 따로 신청해야 합니다.

키 발급과 엔드포인트 승인은 별개의 절차입니다. 이 두 번째 단계를 건너뛰는 것이 새 사용자가 가장 흔히 막히는 지점입니다 — 모든 호출이 401을 반환하는데, "키가 잘못됐나?"라는 결론은 틀린 경우가 대부분입니다. 실제로는 키는 유효하지만 그 엔드포인트에 대한 승인이 없는 것입니다.

무료이며 유효기간은 발급일로부터 1년입니다. 하루 호출 한도는 10,000회입니다.

승인되지 않은 엔드포인트를 부르면 KrxServiceNotGrantedException이 발생하고, 어떤 엔드포인트를 신청해야 하는지 예외 메시지에 나옵니다.

사용법

val krx = KrxClient(authKey = System.getenv("KRX_AUTH_KEY"))

// 계층 1 — 호출 1회 = 요청 1회. 해당 일자의 전 종목
val snapshot = krx.stock.dailyTrade(StockMarket.KOSPI, LocalDate.of(2024, 1, 2))

val from = LocalDate.of(2024, 1, 1)
val to = LocalDate.of(2024, 12, 31)

// 계층 2 — 기간 조회. 내부적으로 영업일 수만큼 요청이 나갑니다
val samsung = krx.series.stockOhlcv(
    market = StockMarket.KOSPI,
    ticker = "005930",
    from = from,
    to = to,
)

// 나가기 전에 요청 수를 확인할 수 있습니다
krx.series.estimateStockOhlcvCalls(StockMarket.KOSPI, from, to)   // 예: 262

Java에서 사용하기

Java는 Kotlin의 이름 있는 인자를 쓸 수 없으므로, 뒤쪽 파라미터 하나만 바꾸려 해도 앞쪽 전부를 위치 인자로 채워야 합니다. KrxClient.builder(authKey)가 이 문제를 피합니다.

KrxClient krx = KrxClient.builder(System.getenv("KRX_AUTH_KEY"))
    .maxConcurrency(8)
    .cache(new InMemorySnapshotCache(256))
    .build();

baseUrl, maxConcurrency, maxCallsPerQuery, cache, transport, clock을 체이닝으로 설정할 수 있습니다. Kotlin에서도 쓸 수 있지만, 이름 있는 인자를 쓸 수 있는 주 생성자 쪽이 더 자연스럽습니다.

호출 수를 왜 신경 써야 하나

KRX OPEN API는 날짜 하나당 전 종목 스냅샷을 줍니다. 시세를 종목 단위가 아니라 날짜 단위로만 내려주기 때문에, 종목 하나의 1년치 시계열을 얻으려면 주말을 제외한 약 262일만큼 호출해서 그중 원하는 종목 행만 골라내야 합니다. 하루 한도가 10,000회이므로 이런 조회를 약 38번만 반복해도 한도에 근접합니다(38 × 262 = 9,956회).

262는 공휴일을 뺀 실제 개장일 수(약 245일)가 아니라 krx-reader가 실제로 요청하는 날짜 수입니다. 공휴일 목록을 코드에 내장하지 않기 때문입니다 — 임시공휴일이 생기면 그 목록은 그 순간 틀리고 고치려면 라이브러리를 다시 배포해야 합니다. 대신 주말만 건너뛰고 휴장일은 빈 응답으로 판별한 뒤 그 사실을 캐시합니다. estimateStockOhlcvCalls가 돌려주는 수도 이 기준입니다.

krx-reader는 이 비용을 두 가지로 관리합니다.

캐시. 날짜별 스냅샷을 캐시하므로, 같은 기간으로 여러 종목을 조회하면 두 번째 종목부터는 요청이 나가지 않습니다. 어차피 스냅샷 하나에 전 종목이 들어있으므로, 같은 (엔드포인트, 날짜)를 다시 요청할 이유가 없습니다.

사용 패턴 캐시 없음 캐시 있음
종목 1개 × 1년 262회 262회
종목 10개 × 1년 (같은 기간) 2,620회 262회
종목 100개 × 1년 (같은 기간) 26,200회 → 한도 초과 262회

기본 캐시는 280 스냅샷 LRU입니다 — 1년 요청 일수(약 262일)보다 조금 크게 잡은 값으로, 계층 2의 정석 사용례인 "1년치 시계열"에서 두 번째 종목부터 캐시가 확실히 재사용되도록 합니다. 가득 찼을 때 코스피 기준 약 80MB, 코스닥 기준 약 150MB입니다. 캐시 용량이 조회 범위의 영업일 수보다 작으면 쿼리 간 재사용은 전혀 일어나지 않습니다 — 날짜 오름차순 팬아웃이 캐시를 다 채우기도 전에 앞부분을 밀어내기 때문입니다. 이 경우 estimateStockOhlcvCallsmaxCallsPerQuery 가드는 낙관적인 "지금 캐시 안 된 날짜 수" 대신 전체 영업일 수를 그대로 보고합니다.

val key = System.getenv("KRX_AUTH_KEY")
KrxClient(authKey = key, cache = InMemorySnapshotCache(maxSnapshots = 256))
KrxClient(authKey = key, cache = SnapshotCache.none())

폭주 차단. 한 번의 기간 조회가 maxCallsPerQuery(기본 400)를 넘으면 요청을 보내기 전에 KrxQuotaGuardException으로 막습니다.

Spring Boot

Spring Boot 자동 설정이 필요하면 스타터를 추가합니다.

dependencies {
    implementation("io.github.aaron-jang:krx-reader-spring-boot-starter:0.1.0")
}
krx:
  auth-key: ${KRX_AUTH_KEY}
  max-concurrency: 4
  max-calls-per-query: 400
  cache:
    type: auto              # auto | spring | in-memory | none
    cache-name: krx-snapshots
    in-memory-max-snapshots: 280
@Service
class MarketService(private val krx: KrxClient) {
    fun samsungLastMonth() = krx.series.stockOhlcv(
        StockMarket.KOSPI, "005930", LocalDate.now().minusMonths(1), LocalDate.now(),
    )
}

type: autoCacheManager 빈이 있으면 그것을 쓰고, 없으면 인메모리 LRU로 떨어집니다. Caffeine이나 Redis를 쓰려면 평소처럼 설정하면 됩니다. krx-reader는 캐시 구현체를 전이 의존성으로 딸려보내지 않습니다.

Redis를 쓸 때는 JSON 직렬화 설정을 권장합니다. JDK 직렬화는 모델 클래스가 바뀌면 깨지는데, krx-reader는 그 경우를 캐시 미스로 처리하므로 조회가 실패하지는 않습니다.

DataFrame

Kotlin DataFrame 변환이 필요하면 추가합니다. 두 변환 함수 모두 @ExperimentalKrxApi로 표시되어 옵트인이 필요합니다.

dependencies {
    implementation("io.github.aaron-jang:krx-reader-dataframe:0.1.0")
}
@OptIn(io.github.aaronjang.krx.ExperimentalKrxApi::class)
fun example(krx: KrxClient, from: LocalDate, to: LocalDate) {
    val stocks = krx.series.stockOhlcv(StockMarket.KOSPI, "005930", from, to).toStockDataFrame()
    println(stocks.rowsCount())

    val indices = krx.series.indexOhlcv(IndexSeries.KOSPI, "코스피 200", from, to).toIndexDataFrame()
    println(indices.rowsCount())
}

krx-reader-dataframe 모듈은 Kotlin DataFrame 컴파일러 플러그인 없이 List<T>.toDataFrame()에 얇게 위임하므로, 플러그인이 생성하는 changeRate { ... } 형태의 타입 세이프 컬럼 접근자는 기본적으로 제공되지 않습니다. 컬럼은 이름으로 접근합니다(예: df["changeRate"]). 타입 세이프 접근자가 필요하다면 소비자가 자신의 빌드에 Kotlin DataFrame 컴파일러 플러그인을 직접 적용해야 합니다.

krx-reader-dataframe 모듈은 실험적입니다. Kotlin DataFrame이 1.0에 도달할 때까지 바이너리 호환성을 보장하지 않습니다.

pykrx 대응표

pykrx krx-reader
stock.get_market_ohlcv(from, to, ticker) krx.series.stockOhlcv(market, ticker, from, to)
stock.get_market_ohlcv(date, market=...) krx.stock.dailyTrade(market, basDd)
stock.get_market_ticker_list(date) krx.stock.issueInfo(market, basDd).map { it.ticker }
stock.get_market_ticker_name(ticker) krx.stock.issueInfo(market, basDd).first { it.ticker == ... }.name
stock.get_market_cap(date) krx.stock.dailyTrade(market, basDd)marketCap
stock.get_index_ohlcv(from, to, code) krx.series.indexOhlcv(series, indexName, from, to)
stock.get_index_ticker_list(date) krx.index.dailyQuote(series, basDd).map { it.indexName }

pykrx와 달리 krx-reader는 시장 인자를 요구합니다. 티커만으로는 어느 엔드포인트를 불러야 할지 알 수 없고, 추측하면 호출 수가 늘어나기 때문입니다.

지수 조회는 코드가 아니라 지수명으로 지정합니다("코스피 200"). KRX 응답에서 확실히 존재가 보장되는 필드는 IDX_NM(지수명)뿐이고, 지수 코드(IDX_IND_CD)는 응답에 없을 수 있어 krx-reader 모델에서도 nullable입니다. 조회 키로 쓸 수 없는 필드이므로 지수명을 씁니다.

지원 범위

주식 8개, 지수 5개 엔드포인트를 지원합니다. 증권상품(ETF/ETN/ELW), 채권, 파생상품, 일반상품, ESG는 아직 지원하지 않습니다.

라이선스

MIT

About

KRX(한국거래소) OPEN API client for Kotlin/Java - 국내 주식·지수 일별시세, 종목기본정보 조회 라이브러리 (Spring Boot 지원)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages