shinalokandClaude Sonnet 5 eaf18362f4 Add NH(나무) broker integration and fix balance/holds parsing
- finestock/nh/: Nh/NhV 브로커 클래스 추가 (시세/주문/잔고/실시간 WS)
- api_factory.py, path.py: APIProvider.NH/NHV 등록, 도메인/엔드포인트 매핑
- kis.py: get_holds/get_ohlcv_min/get_index_min/get_stock_list 스텁 추가,
  oauth() Content-Type 헤더 수정
- get_balance()의 실전 디버깅으로 드러난 버그 수정:
  - Hold.total(매입금액)이 존재하지 않는 byn_amt 필드를 참조해 항상 0이던 것을
    eal_amt - eal_pls_amt로 계산하도록 수정
  - rsp_cd를 "00000" 단일 값으로만 성공 판정해 정상 응답('00218' 연속조회 중,
    '00166' 마지막 페이지 등)을 실패로 오판하던 것을 Output_0 존재 여부로 판정
  - 응답 헤더의 cts/cts_flag로 연속조회를 재귀 처리해 10건 넘는 보유종목도
    전부 합쳐서 반환하도록 구현
- doc/, tests/, example_*.py, setup.py, requirements.txt, CLAUDE.md 등 추가
- README.md에 .env 환경변수 설정 가이드 추가

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01225Lu4Fc2UpMz6QixEcNT8
2026-08-31 14:35:30 +09:00
2026-04-23 15:55:16 +09:00

finestock

Korean Stock OpenAPI Package (LS, KIS)
Created by alshin


Table of Contents

  1. 설치
  2. 환경변수 설정 (.env)
  3. 아키텍처
  4. 사용법
  5. Release Notes
  6. License

설치

pip install finestock

환경변수 설정 (.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만 커밋 대상).

값 로드 방법

example.py, example_async.py는 모두 os.environ.get("APP_KEY", ...) 형태로 값을 읽는다. .env 파일 자체는 셸이나 파이썬이 자동으로 읽어주지 않으므로 아래 두 방법 중 하나가 필요하다.

1) python-dotenv로 자동 로드 (권장)

pip install python-dotenv

예제 스크립트는 python-dotenv가 설치되어 있으면 시작 시 자동으로 .env를 읽어 os.environ에 채워 넣는다(설치돼 있지 않으면 조용히 건너뛴다). 직접 스크립트를 작성할 때도 아래처럼 최상단에서 호출하면 된다.

from dotenv import load_dotenv
load_dotenv()

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"
python example.py
# bash
export APP_KEY="YOUR_APP_KEY"
export APP_SECRET="YOUR_APP_SECRET"
python example.py

아키텍처

finestock은 **파사드 패턴(Facade Pattern)**과 **인터페이스 분리 원칙(ISP)**을 결합하여 설계되었습니다.

1. 통합된 상태 관리 (Facade)

create_api로 생성되는 객체는 인증, 시세, 주문 등 모든 기능을 통합하여 관리합니다. 이를 통해 로그인 세션이나 소켓 연결 상태를 여러 모듈이 공유할 수 있어 사용이 편리합니다.

2. 인터페이스를 통한 명확한 사용 (ISP)

하나의 거대한 객체이지만, **타입 힌팅(Type Hinting)**을 통해 필요한 기능만 노출하여 안전하게 사용할 수 있습니다.

  • AuthenticationProvider: 로그인 및 토큰 관리
  • MarketDataProvider: 과거 시세(이력) 조회
  • RealtimeProvider: 실시간 시세 수신
  • TradingProvider: 주식 주문 및 잔고 조회

사용법

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 등 시세 관련 메서드만 자동완성됨
    df = api.get_ohlcv("005930", frdate="20250101", todate="20250110")
    print(df)

2. 실시간 데이터 (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. 데이터 수신 (비동기 루프 실행 필요)
    # ... (자세한 예제는 example_v1.py 참조)

3. 타입 힌팅 활용 (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 등만 보임)
df = market_api.get_ohlcv("005930")
S
Description
No description provided
Readme
197 KiB
Languages
Python 100%