finestock
Korean Stock OpenAPI Package (EBest, LS, KIS, Kiwoom, NH, DB증권) Created by alshin
Table of Contents
설치
PyPI에 배포된 버전을 쓰려면:
pip install finestock
저장소를 직접 클론해서 최신 소스로 개발/테스트하려면(editable install):
git clone https://github.com/shinalok/finestock.git
cd finestock
pip install -e .
런타임 의존성은 websockets, requests, loguru 세 개뿐입니다(requirements.txt 참고).
지원 브로커
APIProvider enum(finestock/api_factory.py)으로 브로커를 선택하고, mode로 실전("live", 기본값) 또는 모의투자("virtual")를 지정합니다.
| Provider | 브로커 | 지원 환경 |
|---|---|---|
APIProvider.EBEST |
이베스트투자증권 | 실전 |
APIProvider.LS |
LS증권 | 실전·모의 |
APIProvider.KIS |
한국투자증권 | 실전·모의 |
APIProvider.KIWOOM |
키움증권 | 실전·모의 |
APIProvider.NH |
NH투자증권(나무) | 실전·모의 |
APIProvider.DB |
DB증권(DB금융투자) | 실전·모의 |
import finestock
from finestock import APIProvider
api = finestock.create_api(APIProvider.LS)
virtual_api = finestock.create_api(APIProvider.LS, mode="virtual")
기존 APIProvider.LSV, KISV, KIWOOMV, NHV, DBV도 호환을 위해 모의투자로 동작합니다. 새 코드에서는 증권사 Provider와 mode를 사용하세요. EBEST는 모의투자 환경을 지원하지 않습니다.
가격 조회의 기본 기준은 통합 시세(UNIFIED, KRX+NXT) 입니다. 거래소를 지정하려면 QuoteExchange를 사용합니다. KRX, NXT, UNIFIED는 각각 한국거래소, 넥스트레이드, 통합 시세를 뜻하며 결과의 Price.exchange에서도 확인할 수 있습니다.
from finestock import APIProvider, QuoteExchange, create_api
api = create_api(APIProvider.KIS)
unified_price = api.get_price("005930") # 기본: 통합
krx_price = api.get_price("005930", exchange=QuoteExchange.KRX)
nxt_price = api.get_price("005930", exchange=QuoteExchange.NXT)
get_price, get_ohlcv, get_ohlcv_min 모두 exchange를 지원합니다. 기존 exchgubun 인자(분봉)는 호환성을 위해 유지하지만 exchange와 함께 쓸 수 없습니다.
minute_prices = api.get_ohlcv_min("005930", todate="20261002", exchange=QuoteExchange.NXT)
증권사별 내부 코드는 LS K/N/U, KIS J/NX/UN, NH KRX/NXT/UNT, 키움은 종목코드 접미사(없음/_NX/_AL), DB는 J/NJ/UJ와 거래소별 종목코드 접두사(없음/N-/U-)입니다. DB의 통합(UJ) 일봉 종가는 KRX가 아닌 NXT 거래소 종가입니다(DB증권 공식 예제 주석).
정규장 마감 기준 (regular_close)
regular_close=True를 주면 KRX 정규장 마감 기준으로 조회하며 exchange는 KRX로 고정됩니다. NXT·통합과 함께 지정하면 ValueError입니다. 증권사 API가 제공하는 경우에만 동작하고, 그 밖에는 요청을 보내기 전에 NotImplementedError를 냅니다.
| 증권사 | get_price |
get_ohlcv / get_ohlcv_min |
|---|---|---|
| LS·이베스트 | 지원 — 응답의 KRX정규종가(krx_mcls_price)로 price/close를 채웁니다. 정규종가가 아직 없으면 None |
미지원 |
한국투자 (KIS, KISV) |
미지원 — 현재가·시가·고가·저가가 20:00까지의 기준이라 KRX로 조회해도 정규장 종가가 아닙니다 | get_ohlcv 지원(KRX 일봉이 정규장 기준), get_ohlcv_min 미지원 |
NH (NH, NHV) |
지원 — 응답의 정규장 종가(main_cls_prpr)로 price/close를 채웁니다. 아직 없으면 None |
미지원 |
| 키움·DB | 미지원 | 미지원 |
KIS의 KRX 일봉은 정규장 기준이지만, LS는 exchange=KRX로 조회해도 일봉 종가가 20:00 마감 값입니다(2026-10-16 삼성전자: LS 217,000, KIS 일봉·krx_mcls_price 215,500). LS·NH에서 정규장 종가가 필요하면 get_price(regular_close=True)를 쓰세요(최근 값 하나만 제공). 키움·DB는 현재가 응답의 기준가(키움 base_pric, DB Sdpr)가 다음 거래일부터 전일 정규장 종가이지만 같은 날 값은 없어 미지원입니다. KIS는 다음 거래일부터 현재가 응답의 stck_sdpr(기준가)가 전일 정규장 종가입니다. LS get_price(regular_close=True)의 시가·고가·저가·거래량은 KRX 조회 값 그대로입니다.
price = api.get_price("005930", regular_close=True) # LS·NH 가능, 나머지는 NotImplementedError
daily = api.get_ohlcv("005930", "20261001", "20261016", regular_close=True) # KIS만 가능
브로커마다 구현된 메서드 범위가 다릅니다. 아래 지원·미지원 기능 표와 각 클래스의 docstring(finestock/{ebest,ls,kis,kiwoom,nh,db}/*.py)을 참고하세요.
증권사별 지원 기능
현재 저장소 코드 기준(2026-09-28)으로 실제 요청·응답 처리 또는 실시간 구독·수신 코드가 구현된 기능을 정리했습니다. 실전·모의 서버 검증 완료를 의미하지 않으며, 같은 행의 모의투자 Provider도 서버 제공 범위에 따라 사용이 제한될 수 있습니다.
모든 증권사 계열에 인증(oauth, set_oauth_info, set_access_token), 주식 가격·일봉·분봉·호가 조회(get_price, get_ohlcv, get_ohlcv_min, get_orderbook), 잔고·보유종목 조회(get_balance, get_holds), 주문·취소(do_order, do_order_cancel)가 구현되어 있습니다. 추가 기능은 다음과 같습니다.
| 증권사 / Provider | 지수 조회 | 주문 정정 | 종목·지수 목록 | 실시간 수신 |
|---|---|---|---|---|
LS·이베스트 (LS, LSV, EBEST) |
일봉·분봉 | do_order_modify |
get_stock_list, get_index_list |
가격·호가·지수, 계좌 주문·체결 이벤트(recv_order_status) |
한국투자 (KIS, KISV) |
일봉·분봉 | do_order_modify |
— | 가격·지수·호가·계좌 통보 구독 (수신 범위는 아래 참고) |
키움 (KIWOOM, KIWOOMV) |
일봉·분봉 | — | get_stock_list, get_index_list |
가격·호가·지수, 주문·체결 이벤트(recv_trade / recv_order_status) |
NH (NH, NHV) |
— | — | — | 가격·호가 |
DB (DB, DBV) |
일봉·분봉 | do_order_modify |
— | 가격·호가, 계좌 체결 이벤트(recv_trade) |
지수 일봉·분봉은 각각 get_index·get_index_min, 실시간 가격·호가·지수는 각각 recv_price·recv_orderbook·recv_index에 대응합니다. 표의 —는 미구현이며, 자세한 호출 결과는 아래 미지원 기능 표를 참고하세요.
주식 분봉은 모든 계열에서 별도 시각 입력 없이 호출할 수 있지만 반환 범위는 다릅니다. KIS는 지정 날짜를 자동 연속조회하여 중복 제거·시간순 정렬하고, LS는 서버의 연속조회 정보를 따라 추가 조회합니다. NH·키움·DB는 현재 한 요청의 결과를 반환하므로 하루치 전체 수집이나 해당 날짜만의 반환을 공통으로 보장하지 않습니다.
증권사별 미지원 기능
현재 저장소 코드 기준(2026-09-28)으로, 미지원은 finestock에서 미구현·미연동된 기능을 뜻합니다. 증권사 API 자체의 제공 여부를 뜻하지 않으며, 표에 없는 기능도 실전·모의 서버 검증이 완료되었다는 의미는 아닙니다. 같은 행의 Provider는 아래 미지원 메서드를 공유합니다.
| 증권사 / Provider | 미지원 기능 및 메서드 | 현재 호출 결과 |
|---|---|---|
LS·이베스트 (LS, LSV, EBEST) |
공통 체결 구독 recv_trade |
경고만 출력하며 구독하지 않음 |
한국투자 (KIS, KISV) |
종목·지수 목록 get_stock_list, get_index_list |
[] 반환 |
키움 (KIWOOM, KIWOOMV) |
주문 정정 do_order_modify |
None 반환 |
NH (NH, NHV) |
지수 일봉·분봉 get_index, get_index_min종목·지수 목록 get_stock_list, get_index_list주문 정정 do_order_modify실시간 지수·체결 구독 recv_index, recv_trade |
조회는 [], 정정은 None 반환. 실시간 구독은 안내만 출력하며 구독하지 않음 |
DB (DB, DBV) |
종목·지수 목록 get_stock_list, get_index_list실시간 지수 구독 recv_index |
목록은 [] 반환. 지수 구독은 경고만 출력하며 구독하지 않음 |
관련 대체 경로와 구현 제한:
- LS·이베스트: 계좌 주문·체결 이벤트에는
await api.recv_order_status()를 사용합니다. 공통recv_trade()와는 별도 메서드입니다. - 한국투자:
await connect()후 네recv_*메서드로 구독하며status=False로 해제합니다.recv_trade(code)에는 HTS ID를 전달합니다. 실서버에서 네 구독·해제와 가격·호가 수신을 확인했습니다. 지수·계좌 통보 데이터 수신, AES 복호화 및 모의 서버는 미검증입니다. 아래 실시간 실행 예제와 검증 범위를 참고하세요. - 한국투자 분봉:
KIS.get_ohlcv_min()은 주식일별분봉조회로 구현했습니다.KISV도 같은 구현을 상속하지만 모의 서버의 해당 API 지원 여부는 검증되지 않았습니다. 아래 사용 예제는KIS기준입니다. - NH: 지수 조회는 현재 빈 목록을 반환하며, 라이브러리에 대체 조회 경로가 구현되어 있지 않습니다.
- DB: 지수 일봉·분봉은 차트 조회의 시장 구분값
U를 사용하는 구현이 있습니다.recv_trade(code, status=True)는code를 사용하지 않고 계좌 전체를 구독하며,status=False로 구독을 해제하는 동작은 검증되지 않았습니다.
메서드가 존재하거나 isinstance(api, RealtimeProvider) 등이 참이어도 개별 기능의 구현을 보장하지 않습니다. 현재 []와 None만으로는 미지원·빈 결과·업무 실패를 구분할 수 없으므로 호출 전 위 표를 확인하세요.
한국투자 지수 분봉 조회
인증을 설정한 KIS 인스턴스에서 다음과 같이 호출합니다.
prices = api.get_index_min("0001") # 코스피 1분봉, Price 목록
prices = api.get_index_min("0001", interval=600, include_past=False) # 당일 10분봉
prices = api.get_index_min("0001", todate="20260928", exclude_after_hours=True)
interval은 초 단위이며 기본값은 60입니다. include_past=True는 과거 데이터를
포함하고, exclude_after_hours=True는 장마감·시간외를 제외합니다.
todate는 한 번의 API 응답에서 해당 날짜만 선택합니다. 임의 과거 날짜 지정 조회와
커서 연속조회는 지원하지 않으므로 응답 범위 밖의 날짜는 빈 목록을 반환합니다.
Price.time은 체결 시간, volume은 체결 거래량, volume_amt는 응답의 누적 거래대금입니다.
실전·모의 서버 호출은 검증하지 않았습니다.
요청·응답 필드는 한국투자증권 공식 샘플을 참고했습니다.
환경변수 설정 (.env)
브로커 앱키/시크릿/계좌번호/액세스 토큰은 코드에 직접 하드코딩하지 말고 환경변수로 주입합니다. 저장소 루트의 .env.example을 복사해 .env로 만들고 실제 값을 채워 넣으세요.
cp .env.example .env
.env 파일 내용:
APP_KEY=YOUR_APP_KEY
APP_SECRET=YOUR_APP_SECRET
ACCOUNT_NUM=YOUR_ACCOUNT_NUM
ACCOUNT_NUM_SUB=01
ACCESS_TOKEN=
.env는 .gitignore에 의해 커밋되지 않습니다(.env.example만 커밋 대상).
⚠️ 실제 앱키/시크릿을 스크립트에 직접 문자열로 적어두고 커밋하지 마세요. 한 번이라도 원격 저장소(특히 public)에 올라간 값은 즉시 노출된 것으로 간주하고 발급처(브로커 개발자센터)에서 폐기 후 재발급받아야 합니다.
값 로드 방법
1) python-dotenv로 자동 로드 (권장)
pip install python-dotenv
스크립트 최상단에서 아래처럼 호출하면 .env 값이 os.environ에 채워집니다(설치돼 있지 않으면 ImportError를 잡아 조용히 건너뛰도록 작성하는 게 일반적입니다).
try:
from dotenv import load_dotenv
load_dotenv()
except ImportError:
pass
import os
app_key = os.environ.get("APP_KEY")
app_secret = os.environ.get("APP_SECRET")
2) 셸에서 직접 환경변수 설정
# PowerShell
$env:APP_KEY = "YOUR_APP_KEY"
$env:APP_SECRET = "YOUR_APP_SECRET"
# bash
export APP_KEY="YOUR_APP_KEY"
export APP_SECRET="YOUR_APP_SECRET"
아키텍처
finestock은 **파사드 패턴(Facade Pattern)**과 **인터페이스 분리 원칙(ISP)**을 결합하여 설계되었습니다.
1. 통합된 상태 관리 (Facade)
create_api로 생성되는 객체는 인증, 시세, 주문, 잔고, 실시간 등 모든 기능을 통합하여 관리합니다. 이를 통해 로그인 세션이나 소켓 연결 상태를 여러 모듈이 공유할 수 있어 사용이 편리합니다.
2. 인터페이스를 통한 명확한 사용 (ISP)
하나의 거대한 객체이지만, **타입 힌팅(Type Hinting)**을 통해 필요한 기능만 노출하여 안전하게 사용할 수 있습니다. finestock/comm/api_interface.py에 정의된 세그먼트:
AuthenticationProvider: 로그인 및 토큰 관리(oauth,set_oauth_info,set_access_token)MarketDataProvider: 시세/OHLCV/지수/호가 조회(get_price,get_ohlcv,get_ohlcv_min,get_index,get_orderbook, ...)TradingProvider: 주문 실행/취소(do_order,do_order_cancel)RealtimeProvider: WebSocket 실시간 구독(set_data_queue,recv_price,recv_orderbook, ...)AccountProvider: 계좌 잔고/보유종목 조회(get_balance,get_holds)InfoProvider: 종목/지수 마스터 목록(get_stock_list,get_index_list)
이 인터페이스들의 합집합(BaseProvider)을 모든 브로커 클래스가 구현합니다. 타입 힌팅은 IDE 자동완성을 좁히기 위한 것일 뿐, 런타임 제약은 없습니다.
3. 데이터 모델 (finestock/model/)
브로커가 반환하는 원시 JSON/TR 응답은 파싱되어 공통 @dataclass(frozen=True) 타입(Price, OrderBook, Hold, Account, Order, Trade, Stock, Index)으로 통일됩니다.
사용법
1. 기본 사용 (Factory & Interface)
import finestock
from finestock import APIProvider
from finestock.comm.api_interface import AuthenticationProvider, MarketDataProvider
# 1. API 객체 생성 (통합 객체)
api = finestock.create_api(APIProvider.LS)
# 2. 인증 (AuthenticationProvider 인터페이스 활용)
if isinstance(api, AuthenticationProvider):
api.set_oauth_info("YOUR_APP_KEY", "YOUR_APP_SECRET")
# api.oauth() # 로그인 필요 시 호출
# 3. 데이터 조회 (MarketDataProvider 인터페이스 활용)
if isinstance(api, MarketDataProvider):
# IDE에서 get_ohlcv 등 시세 관련 메서드만 자동완성됨
ohlcvs = api.get_ohlcv("005930", frdate="20260101", todate="20260110")
print(ohlcvs)
2. 계좌 조회 (AccountProvider)
from finestock.comm.api_interface import AccountProvider
if isinstance(api, AccountProvider):
account = api.get_balance()
if account:
print(account.deposit, len(account.hold))
3. 실시간 데이터 (Queue Injection)
import queue
from finestock.comm.api_interface import RealtimeProvider
if isinstance(api, RealtimeProvider):
# 1. 데이터를 받을 큐 생성
q = queue.Queue()
# 2. 큐 주입
api.set_data_queue(q)
# 3. 데이터 수신 (asyncio 이벤트 루프에서 api.connect()/api.run() 실행 필요)
# 브로커별 recv_price / recv_orderbook / recv_trade 등을 구독한 뒤
# q.get()으로 파싱된 finestock.Price / OrderBook / Trade 객체를 받는다.
4. 타입 힌팅 활용 (Type Hinting)
IDE에서 각 인터페이스별 메서드만 자동완성되도록 하려면 변수에 타입을 명시할 수 있습니다.
from finestock.comm.api_interface import MarketDataProvider
# api 변수는 모든 기능을 가지고 있지만...
full_api = finestock.create_api(APIProvider.LS)
# MarketDataProvider로 타입을 명시하면 시세 관련 메서드만 자동완성에 노출됩니다.
market_api: MarketDataProvider = full_api
# market_api. (여기서 get_ohlcv 등만 보임)
ohlcvs = market_api.get_ohlcv("005930", frdate="20260101", todate="20260110")
5. 한국투자증권 주식 분봉 조회
인증을 마친 APIProvider.KIS 객체에서 날짜만 지정하면 내부에서 연속조회하여 하루치 분봉을 반환합니다.
# api = finestock.create_api(APIProvider.KIS)
# set_oauth_info / oauth 또는 set_access_token으로 실전 인증을 완료한 뒤 호출
prices = api.get_ohlcv_min("005930", todate="20260925")
for price in prices:
print(price.workday, price.time, price.open, price.high, price.low,
price.close, price.volume, price.volume_amt)
주식일별분봉조회 공식 문서와 한국투자증권 공식 예제를 기준으로 FHKST03010230을 사용합니다. 서버의 요청당 최대 120건 제한에 맞춰 내부에서 조회 시각을 이동하며 해당 날짜의 분봉을 모읍니다. 오늘은 현재까지 서버에서 제공하는 분봉을 반환합니다. 과거 데이터는 서버 보관 범위(공식 예제 기준 최대 1년)에 한정됩니다.
| 인자 | 한국투자 분봉에서의 의미 |
|---|---|
todate |
조회 날짜 YYYYMMDD. 생략하면 호출 시점의 한국 날짜 |
cts_time |
생략하면 하루 전체 조회. 지정하면 해당 시각(HHMMSS)까지 조회 |
cts_date |
지정하면 todate 대신 사용할 조회 날짜 |
exchgubun |
K 또는 J: KRX(기본), NX: NXT, UN: 통합 |
pw_data_incu_yn |
과거 데이터 포함 여부. N(기본) 또는 Y |
fake_tick_incu_yn |
허봉 포함 여부. 기본 빈 문자열, Y 또는 N 지정 가능 |
tr_cont_key |
이 API에서는 사용하지 않음. 값을 전달하면 ValueError |
결과는 해당 날짜만 남기고 날짜·시각 중복을 제거한 시간 오름차순 Price 목록입니다. workday·time은 각 행의 영업일·체결 시각, price·close는 현재가, volume은 체결 거래량입니다. volume_amt는 API의 누적 거래 대금(acml_tr_pbmn)이며 해당 1분만의 거래 대금이 아닙니다.
빈 응답이나 이전 날짜에 도달하면 연속조회를 종료합니다. 첫 요청의 업무 거절이나 빈 결과는 [], 잘못된 인자는 ValueError로 처리합니다. 중간 요청의 업무 거절·반복 응답·잘못된 성공 응답은 FinestockAPIError를 발생시켜 불완전한 하루치를 정상 결과로 반환하지 않습니다. 통신 오류는 공통 예외를 그대로 전달합니다. 테스트는 합성 응답 기반이며 실제 서버 호출은 검증하지 않았습니다.
LS 주문 정정
인증된 LS 객체에서 기존 미체결 주문의 번호와 새 가격·수량을 전달합니다.
# 실제 정정 주문을 전송합니다. order_num은 기존 주문의 주문번호입니다.
modified = api.do_order_modify(order_num, "005930", price=70000, qty=2)
if modified is not None:
print(modified.order_num, modified.price, modified.qty)
CSPAT00701을 사용하며price=0은 시장가, 그 외는 지정가입니다. 주문조건은 없음(0)으로 전송합니다.LSV는 6자리 숫자 주식코드에A를 붙입니다. 이미 지정한A·J·Q접두사는 유지합니다.EBEST도 구현을 상속합니다.- 반환되는
order_num은 원주문번호가 아닌 응답의 정정 주문번호(OrdNo)입니다. 매수·매도 구분은 응답의BnsTpCode를 사용합니다. - 제공된
doc/ls-openapi-tr-guides.json에는 성공 코드 목록이 없어 HTTP 200의 양수OrdNo를 접수 근거로 사용합니다. HTTP 거절 또는 주문번호가 없는 거절 응답은None, 잘못된 접수 응답은FinestockAPIError입니다.Order반환은 체결 완료를 의미하지 않습니다. - 통신 오류와 비정상 응답은 자동 재전송하지 않습니다. 명세 기반 합성 응답으로 테스트했으며 실제 정정 주문은 전송하지 않았습니다.
표준 오류 응답 (ErrorResponse)
증권사마다 오류 필드와 코드가 달라 호출부가 증권사별로 분기하지 않도록, 공통 오류 코드·메시지와 증권사 원본 정보를 하나의 객체로 돌려줍니다. 기존 oauth() 반환값은 그대로이며, request_token()이 표준 형식으로 감싸 줍니다.
result = api.request_token() # 예외도 던지지 않고 TokenResult로 반환
if result.ok:
token = result.token
else:
error = result.error # ErrorResponse
print(error.code) # ErrorCode.RATE_LIMITED (공통 오류 코드)
print(error.message) # 공통 메시지
print(error.broker_code) # 증권사 오류 코드 (예: EGW00133)
print(error.broker_message) # 증권사 오류 메시지
print(error.http_status) # HTTP 상태 코드
print(error.to_dict()) # 원본 응답(raw, 민감 값 마스킹) 포함
| 공통 코드 | 의미 |
|---|---|
AUTH_FAILED |
앱 키/시크릿 오류 등 인증 실패 |
TOKEN_INVALID / TOKEN_EXPIRED |
접근 토큰이 유효하지 않음 / 만료 |
RATE_LIMITED |
호출 횟수 제한 초과 |
INVALID_REQUEST |
잘못된 요청 값 |
INSUFFICIENT_FUNDS |
주문가능금액 부족 |
INSUFFICIENT_QUANTITY |
주문가능수량 초과(보유·미체결 수량 부족) |
NOT_PERMITTED |
계좌·종목 권한 없음(파생ETF 미신청 등) |
NETWORK_ERROR |
연결 실패, 타임아웃 |
SERVER_ERROR |
증권사 서버 오류 (5xx, JSON이 아닌 응답) |
UNKNOWN |
분류하지 못한 오류 (증권사 원본 정보는 그대로 담김) |
분류는 알려진 증권사 오류 코드 → 오류 메시지 키워드 → HTTP 상태 순으로 하며, 현재 코드 표(finestock/comm/error_response.py의 BROKER_ERROR_CODES)에는 KIS의 확인된 코드만 있습니다. 다른 증권사는 메시지 키워드와 HTTP 상태로 분류하므로 실제 응답으로 확인하는 대로 표에 추가하세요.
호출 계약 변경 (개발 버전)
- 키움/키움V 주문·취소는 성공 시
Order, HTTP/업무 거절 시None을 반환합니다. 기존result['ord_no']는result.order_num으로 변경하고None을 먼저 확인하세요. 성공 판정은return_code를 사용합니다. - 비-JSON 응답이나 성공 응답의 주문번호 누락은
FinestockAPIError입니다. 접수 여부가 불명확한 오류를 자동 재주문으로 처리하지 마세요. Order는 접수 결과이며 체결 완료를 뜻하지 않습니다. 키움 취소 결과의qty는 요청 수량입니다(0은 잔량 전부 요청). 실제 취소·체결 수량을 확인한 값은 아닙니다. 제공되지 않는 이름·시간은 빈 문자열·None입니다.- LS 계열
recv_trade(code, status=True)는 이제await가 필요합니다. 여전히 미구현이며 경고만 출력합니다. 계좌 이벤트에는 기존recv_order_status()를 사용하세요. - LS
get_stock_list(mrkt_tp='0')는 시장 인자를 받습니다(LS 기준 0 전체, 1 코스피, 2 코스닥). 시장 코드 의미는 증권사마다 다릅니다. LS 종목·지수 목록은 원본 dict 목록을 유지합니다. - LS 목록형 조회의 암묵적
None과 KIS 미지원 지수 목록 반환은[]로 정리했습니다. 빈 결과·업무 실패·미지원 구분과 목록 원소 모델 통일은 후속 작업입니다. - LS·KIS의 수정된 차트 경로는
Price.from_values()로 숫자를 변환합니다. 잘못된 숫자는ValueError등으로 전달되며 전체 파서 오류의 공통 예외화는 후속 작업입니다.
키움 응답 필드 근거: 키움 공식 REST API 주문 문서. 이번 응답 테스트는 명세와 기존 코드에 맞춘 합성 데이터이며 실제 계좌 응답을 수집한 것이 아닙니다.
한국투자증권 실시간 실행 테스트
example_async.py에 KIS 구독·해제 및 응답 확인 기능을 추가했습니다. 환경변수 또는 .env에 APP_KEY, APP_SECRET, HTS_ID를 설정합니다. 소문자 htsid도 지원하며 HTS ID가 없으면 계좌 통보 구독은 건너뜁니다.
.\venv\Scripts\python.exe -m pip install python-dotenv
.\venv\Scripts\python.exe -B example_async.py --provider KIS --seconds 30
--code로 종목(기본 005930), --index로 지수(기본 0001)를 지정합니다. --provider 생략 시 기본값은 LSV입니다. KIS에서는 지정 시간 동안 수신 후 구독을 해제하고 최대 5초 동안 해제 응답을 확인한 다음 연결을 닫습니다. 거절 또는 응답 누락은 오류로 처리합니다. 주문은 전송하지 않으며 인증정보·계좌 통보 원문 대신 응답 코드와 데이터 건수를 출력합니다.
| 메서드 | TR ID | code 인자 |
|---|---|---|
recv_price |
H0STCNT0 |
종목코드 |
recv_index |
H0UPCNT0 |
업종코드 |
recv_orderbook |
H0STASP0 |
종목코드 |
recv_trade |
실전 H0STCNI0, 모의 H0STCNI9 |
HTS ID |
await api.connect()
await api.recv_price("005930")
await api.recv_index("0001")
await api.recv_orderbook("005930")
await api.recv_trade("YOUR_HTS_ID")
await api.recv_price("005930", status=False) # 해제
실서버 테스트 결과(2026-09-28, KIS, 30초):
| 메서드 | 구독 / 해제 | 수신 건수 |
|---|---|---|
recv_price |
성공 / 성공 | 25 |
recv_index |
성공 / 성공 | 0 |
recv_orderbook |
성공 / 성공 | 148 |
recv_trade |
성공 / 성공 | 0 |
네 TR 모두 구독 응답은 rt_cd=0, msg_cd=OPSP0000, 해제 응답은 rt_cd=0, msg_cd=OPSP0001이었습니다. 위 건수는 30초 수신 구간 기준이며 해제 응답 대기 중 호가 2건이 추가 수신되었습니다. 건수는 실행 시점에 따라 달라집니다.
지수·계좌 통보는 해당 구간에 데이터가 없어 실제 데이터 수신을 검증하지 못했습니다. 계좌 통보 AES 복호화와 모의 서버도 미검증입니다. 구독 메서드는 요청을 전송하고 None을 반환합니다. KIS 라이브러리에는 아직 run(), 모델 변환, 자동 큐 전달이 없으며 예제 수신 루프는 구독 응답·PINGPONG·데이터 건수만 처리합니다. 계좌 통보는 구독 응답의 key/IV를 이용해 별도로 AES 복호화해야 합니다.
프로토콜 참고: 공식 구독 예제, 요청 형식 및 해제 구현.
테스트
Provider 선택형 OAuth 예제
python example_oauth.py를 실행하면 Provider를 이름이나 번호로 선택한 뒤
1. OAuth 하기를 선택할 수 있습니다. python-dotenv가 필요합니다
(pip install "finestock[examples]").
프로젝트 루트 .env에 선택한 Provider 이름을 접두어로 설정하세요:
DB_APP_KEY="발급받은 앱 키"
DB_APP_SECRET="발급받은 앱 시크릿"
KISV_APP_KEY="모의투자 앱 키"
KISV_APP_SECRET="모의투자 앱 시크릿"
키가 없으면 필요한 항목을 안내하고 요청을 보내지 않습니다. 실전과 모의의
키는 각각 설정하며, .env를 수정한 후 메뉴에서 OAuth를 다시 실행할 수 있습니다.
전체 Provider 설정 항목은 .env.example을 참고하세요.
python -m unittest discover tests # 전체 테스트
python -m unittest tests.test_model -v # 특정 모듈만
pytest 설정은 없으며 표준 라이브러리 unittest를 사용합니다.
Release Notes
전체 변경 이력은 CHANGELOG.md를 참고하세요. 최근 주요 변경:
- 1.0.1.0:
MarketDataProvider에get_price(code)추가(당일 OHLCV를 단일Price로 반환) - 2.0.0.0: Kiwoom 주문·취소 반환값을
Order로 통일, KIS 분봉·실시간 구독과 LS 주문 정정 추가, DB 브로커 구현 및 배포 도구 도입. 호환성 변경과 미검증 범위는 CHANGELOG.md를 확인하세요. - 1.0.0.1:
APIFactorylazy loading 도입, 인터페이스 분리(ISP) 리팩터링, 메서드 네이밍 PEP 8 표준화 - (개발 중) NH투자증권(나무) 브로커 지원 추가 —
APIProvider.NH/APIProvider.NHV - (개발 중) DB증권(DB금융투자) 브로커 지원 추가 —
APIProvider.DB/APIProvider.DBV
License
별도의 LICENSE 파일은 아직 저장소에 포함되어 있지 않습니다. 라이선스 조건이 필요하다면 저장소 관리자(shinalok)에게 문의해 주세요.
Metadata
Release files for finestock 3.0.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| finestock-3.0.0.0.tar.gz | 138.9 kB | Without provenance | Details for finestock-3.0.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| finestock-3.0.0.0-py3-none-any.whl | Python 3 | none | any | Details for finestock-3.0.0.0-py3-none-any.whl |
Total release size: 232.6 kB
Release files / finestock-3.0.0.0.tar.gz
| Download URL | finestock-3.0.0.0.tar.gz |
|---|---|
| Size | 138.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4677b90dfe7c6664292a74b6159d0eddaebee8b106f4384b05486c0498104eb8
|
|
BLAKE2b-256 checksum How to use checksums |
8cf366781bd20d62f4afe22e1aa342a78869a7c255abf2ad8a32f4b7f85c2267
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.11 {"installer":{"name":"uv","version":"0.12.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / finestock-3.0.0.0-py3-none-any.whl
| Download URL | finestock-3.0.0.0-py3-none-any.whl |
|---|---|
| Size | 93.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
475ac224b1194450114a4c1457cd720b739107fff2f451f097691e3a10817c9a
|
|
BLAKE2b-256 checksum How to use checksums |
18f44907396208768d6975ae2695c9882629b4b993eeb98d46842c7ce63f54e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.11 {"installer":{"name":"uv","version":"0.12.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for finestock 3.0.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.