시세 조회, 차트 대시보드, 급등락 감시, 모의매매에 LLM을 붙이는 방법

API로 만드는 주식 프로그램

증권사 API를 사용하면 HTS 화면을 사람이 직접 누르지 않아도 프로그램이 시세를 조회하고, 차트를 그리고, 조건을 감시하고, 모의 또는 실전 주문 흐름을 만들 수 있다. 한국투자증권의 KIS Developers는 이런 기능을 Open API 형태로 제공한다. 공식 포털은 API 설명, 예제 코드, 개발자 지원 자료를 제공하며, 프로젝트의 코드는 이 흐름을 Python 프로그램으로 옮긴 것이다.

여기서 중요한 점은 자동매매 자체가 목적이 아니라 데이터 흐름을 이해하는 것이다. 토큰을 발급받고, 종목코드로 시세를 조회하고, 캔들 데이터를 표준 형태로 바꾸고, 조건을 만족하는 이벤트를 탐지하고, 그 결과를 사람이 이해할 수 있는 화면과 로그로 보여 주는 과정이 핵심이다.

앱키 준비, 접근 토큰 발급, TR ID 지정, 시세 조회, 정규화, 조건 이벤트 탐지, 화면과 로그로 이어지는 KIS API 흐름
그림. KIS API는 키 → 토큰 → TR ID → 시세 → 표준 표 순서로 다룬다

공식 API 흐름

단계설명프로젝트 위치
1. 앱키 준비KIS Developers에서 앱키와 앱시크릿을 발급받고 .env.local에 저장한다.chart/kis_client.py
2. 접근 토큰 발급POST /oauth2/tokenP로 access_token을 받아 이후 요청의 Authorization 헤더에 넣는다.KISClient.issue_access_token
3. TR ID 지정API마다 정해진 tr_id를 헤더에 넣는다. 모의투자에서는 일부 TR 접두사가 바뀐다._tr_id_for_domestic
4. 시세 조회국내주식 현재가, 일/주/월봉, 1분봉 등을 REST GET으로 조회한다.inquire_daily_itemchart, fetch_minute_candles
5. 결과 정규화KIS 응답 필드를 Open, High, Low, Close, Volume 같은 표준 컬럼으로 바꾼다.candles_to_dataframe
client = KISClient()
client.issue_access_token()
body = client.inquire_daily_itemchart(
    fid_input_iscd="005930",
    period="D",
)
df = candles_to_dataframe(body)

프로젝트 구성

파일역할
moei/main.py가장 작은 KIS API 예제다. 토큰 발급 후 삼성전자 현재가를 조회한다.
chart/kis_client.pyREST 인증, 토큰 재발급, 일봉 조회, KIS 응답을 DataFrame으로 바꾸는 공통 클라이언트다.
chart/main.pyPyQt5와 matplotlib로 캔들 차트, 이동평균, RSI, 거래량, LLM 판단 패널을 배치한 대시보드다.
chart/build_stock_list.pyKRX 종목 목록을 만들고 관리종목, 투자주의, 거래정지 등 위험 표시 종목을 제외한다.
chart/fetch_positive_news.py네이버 금융 뉴스를 수집하고 호재/악재 키워드로 종목별 후보를 만든다.
chart/paper_trade.py호재 종목을 대상으로 익절/손절 규칙을 적용하는 모의매매 스케줄러다.
chart/surge_monitor.pyKIS 1분봉 데이터를 반복 조회해 급등과 급락 이벤트를 감시한다.
chart/surge_paper_trade.py급등 뒤 저점과 호가를 보고 가상 매수한다. 실주문은 넣지 않는다.
chart/surge_minute_redis_writer.py모의투자 1분봉만 조회해 Redis에 넣는다.
chart/surge_paper_train_loop.py장중 가상매매가 끝나면 손익 데이터를 만들고 LoRA 학습을 반복한다.
chart/training/train_surge_lora.py끝난 가상매매의 손익 원인을 설명하도록 작은 텍스트 모델을 미세조정한다.

응용 프로그램 1: 현재가 조회

가장 작은 프로그램은 종목코드 하나를 넣고 현재가를 조회하는 것이다. 이 단계에서 독자는 API 키, 토큰, 헤더, 파라미터, 응답 JSON의 의미를 익힌다. 아래 예제는 흐름을 쉽게 확인할 수 있도록 삼성전자 종목코드 005930을 사용한다.

python moei/main.py

# 흐름
# 1) .env.local에서 APP_KEY / APP_SECRET 읽기
# 2) /oauth2/tokenP로 접근 토큰 발급
# 3) /uapi/domestic-stock/v1/quotations/inquire-price 호출
# 4) output JSON 출력

응용 프로그램 2: 차트 대시보드

차트 프로그램은 일봉, 주봉, 월봉 데이터를 가져와 캔들, 이동평균, RSI, 거래량을 한 화면에 보여 준다. 오른쪽에는 LLM 판단, 판단 이유, 이력 영역이 이미 준비되어 있다. 현재 코드에서는 placeholder에 가깝지만, 이 빈자리가 바로 LLM을 붙이기 좋은 자리다.

화면 영역기능LLM 적용 아이디어
캔들 차트가격 흐름, 이동평균, RSI, 거래량 표시최근 20봉의 변화와 기술적 조건을 자연어로 요약한다.
LLM 판단매수/관망/주의 같은 사람이 읽는 판단 표시규칙 기반 신호를 받아 이유를 설명한다. 직접 주문 판단을 맡기지는 않는다.
판단 이유근거 문장 표시가격, 거래량, 뉴스, 리스크를 한 문단으로 정리한다.
이력자동 판단의 누적 기록이전 판단과 현재 판단이 왜 달라졌는지 비교 설명한다.

응용 프로그램 3: 뉴스 기반 후보 선정

fetch_positive_news.py는 네이버 금융 뉴스를 수집하고, 호재와 악재 키워드 사전으로 점수를 계산한 뒤 종목명과 매칭한다. 현재 positive_news.csv에는 호재성 기사에서 추출한 종목별 행이 저장되어 있다. 이 구조는 초보자에게 매우 좋다. 왜냐하면 처음부터 LLM에게 모든 판단을 맡기지 않고, 키워드 규칙으로 작동하는 기준선을 먼저 만들기 때문이다.

현재 방식장점LLM으로 개선할 부분
키워드 점수동작이 빠르고 이유가 명확하다.문맥을 보지 못해 '급등 후 우려' 같은 문장을 오해할 수 있다.
종목명 문자열 매칭구현이 단순하다.짧은 종목명, 동명이슈, 지주사/자회사 관계를 구분하기 어렵다.
CSV 저장검증과 재현이 쉽다.LLM 요약과 근거 문장을 함께 저장하면 리뷰가 쉬워진다.
뉴스 제목 + 요약
  -> 종목명 매칭
  -> 호재/악재 키워드 점수
  -> 후보 종목 CSV
  -> LLM 요약과 리스크 설명 추가

응용 프로그램 4: 급등락 실시간 감시

surge_monitor.py는 KIS 1분봉을 일정 주기로 조회하고, 최근 N분 수익률, 거래량 급증, 캔들 폭 조건을 동시에 만족할 때 이벤트를 출력한다. watchlist를 직접 지정할 수도 있고, 거래대금 상위 종목이나 호재 후보 종목으로 자동 구성할 수도 있다.

1분봉 차트에서 최근 N분 수익률, 평균 대비 거래량 배수, 마지막 캔들 폭 세 조건을 표시한 급등 감지 예시
그림. 수익률·거래량·캔들 폭 세 조건이 동시에 맞을 때만 급등 이벤트를 낸다
탐지 조건의미
최근 N분 누적 수익률짧은 시간 안에 가격이 얼마나 움직였는지 본다.
거래량 평균 대비 배수평소보다 시장 참여가 갑자기 늘었는지 본다.
마지막 1분봉 캔들 폭순간 변동성이 충분히 큰지 본다.
중복 알림 방지같은 분봉 이벤트를 반복해서 출력하지 않는다.

LLM은 이 이벤트의 원인을 추정하는 보조자로 쓸 수 있다. 예를 들어 방금 발생한 급등 이벤트에 대해 최근 뉴스, 공시, 업종 흐름, 과거 이벤트 이력을 모아 '왜 알림이 발생했는지' 설명하게 할 수 있다. 단, LLM의 설명은 사실 확인 전의 가설로 표시해야 한다.

응용 프로그램 5: 모의매매 스케줄러

paper_trade.py는 실거래가 아니라 모의 실험이다. 매일 아침 호재 후보를 고르고, 장 마감 후 당일 OHLC 데이터로 익절 +5%, 손절 -3%, 미도달 시 종가 청산 규칙을 적용한다. 결과는 날짜별 CSV로 저장된다. 프로젝트에는 2026년 4월 29일, 4월 30일, 5월 4일, 5월 6일의 모의매매 결과 파일이 있다.

시초가 매수 기준선과 +5% 익절선, −3% 손절선 사이에서 네 가지 캔들이 각각 익절, 손절, 손절 우선, 종가 청산으로 끝나는 예
그림. 모의매매는 시초가 매수, +5% 익절, −3% 손절, 종가 청산 규칙으로 계산한다
규칙설명
매수후보 종목을 당일 시초가에 매수했다고 가정한다.
익절당일 고가가 매수가의 +5% 이상이면 익절 체결로 본다.
손절당일 저가가 매수가의 -3% 이하이면 손절 체결로 본다.
동시 도달일봉만으로 순서를 알 수 없으므로 보수적으로 손절을 먼저 적용한다.
마감 청산익절/손절 모두 없으면 종가에 청산해 다음 날로 넘기지 않는다.

4일치 결과 파일을 모아 보면 체결된 33건 중 이익으로 끝난 거래는 15건이고, 4일 순손익은 −11,558원이다. 손절 14건은 모두 −3%에, 익절 6건은 +5%에 몰려 있다. 나머지 13건은 어느 쪽에도 닿지 않아 종가에 청산되었는데, 하루 손익을 가른 것은 오히려 이 거래들이었다. 종가 청산이 대부분 플러스였던 5월 4일은 이익이, 손절이 많았던 4월 30일과 5월 6일은 손실이 났다.

4일간 일별 익절·종가 청산·손절 건수와 손익 막대, 거래별 수익률 분포(−3%에 14건, +5%에 6건)
그림. paper_trade.py 모의매매 4일 결과 — 일별 체결 유형과 거래별 수익률 분포

LLM을 넣기 좋은 부분

LLM을 주식 프로그램에 넣을 때 가장 좋은 위치는 '사람이 읽고 판단해야 하는 정보의 압축'이다. 숫자 계산, 주문 전송, 손절 조건 같은 부분은 결정적 코드와 규칙으로 처리하고, LLM은 설명, 요약, 분류, 질의응답, 리포트 작성에 배치하는 것이 안전하다.

뉴스 요약, 차트 설명, 급등락 해설 같은 LLM에 맡기기 좋은 일과 주문, 손절, API 키 처리 같은 맡기면 위험한 일을 나눈 두 칸 그림
그림. LLM은 정보를 압축하는 곳에 두고, 돈과 위험을 다루는 곳에는 두지 않는다
적용 위치LLM 역할주의점
뉴스 분석기사 여러 개를 읽고 호재, 악재, 중립으로 분류하며 핵심 근거를 요약한다.기사 원문 출처와 시간, 불확실성을 함께 남긴다.
차트 설명이동평균, RSI, 거래량 변화가 어떤 상태인지 자연어로 설명한다.기술적 지표를 투자 권유처럼 단정하지 않는다.
급등락 알림왜 알림이 떴는지 가격/거래량/뉴스 관점으로 설명한다.원인 추정과 확인된 사실을 구분한다.
모의매매 회고오늘의 결과 CSV를 읽고 승률, 손익, 실패 원인을 요약한다.과최적화나 사후 해석을 경계한다.
사용자 질의응답사용자가 '왜 이 종목이 후보인가'라고 물으면 근거를 찾아 답한다.개인 맞춤 투자 조언으로 넘어가지 않게 제한한다.
전략 문서화규칙, 파라미터, 변경 이력, 리스크를 자동 문서로 남긴다.LLM이 만든 문서는 사람이 최종 검토한다.

LLM에게 맡기면 위험한 부분

  • 실전 주문 버튼을 LLM 판단만으로 누르게 하지 않는다.
  • 손절, 익절, 포지션 크기 같은 위험 관리 규칙을 자연어 출력에 의존하지 않는다.
  • API 키, 앱시크릿, 계좌번호 같은 민감 정보를 프롬프트에 넣지 않는다.
  • 뉴스 요약만으로 사실 여부가 확인된 것처럼 표시하지 않는다.
  • 백테스트 결과가 좋다는 이유로 미래 수익이 보장된다고 쓰지 않는다.

추천 아키텍처

KIS Open API
  -> KISClient: 인증, 토큰 재발급, REST 호출
  -> DataFrame: OHLCV, 1분봉, 현재가 정규화
  -> Rule Engine: 급등락, 손절/익절, 후보 필터
  -> Storage: CSV 로그, 이벤트 기록, 모의매매 결과
  -> LLM Layer: 뉴스 요약, 차트 설명, 이벤트 해설, 회고 리포트
  -> UI: PyQt 대시보드, 알림, 사용자 질문

이 구조에서 LLM은 마지막 판단자가 아니라 해설자와 분석 보조자다. 수치 계산은 코드가 하고, LLM은 그 숫자가 무엇을 의미하는지 독자와 사용자에게 설명한다. 이 역할 분담을 지키면 프로그램은 훨씬 안정적이고 책의 메시지도 명확해진다.

KIS Open API, KISClient, DataFrame, Rule Engine, Storage, LLM Layer, UI가 위에서 아래로 쌓인 계층 구조
그림. 조건 판정은 규칙 엔진이 하고, LLM은 결과를 설명하는 층에 둔다

실습 순서

  • 1단계: KIS Developers에서 API 키를 발급받고 .env.local에 APP_KEY와 APP_SECRET을 설정한다.
  • 2단계: moei/main.py로 현재가 조회가 되는지 확인한다.
  • 3단계: chart/main.py로 일봉 차트를 그리고 종목코드를 바꿔 본다.
  • 4단계: build_stock_list.py로 투자 유의 종목을 제외한 종목 목록을 만든다.
  • 5단계: fetch_positive_news.py로 뉴스 기반 후보 CSV를 만든다.
  • 6단계: paper_trade.py --runonce로 모의매매 결과를 저장한다.
  • 7단계: surge_monitor.py로 1분봉 급등락 감시 조건을 실험한다.
  • 8단계: surge_paper_trade.py로 같은 신호를 가상 매매까지 이어 본다. 실주문은 켜지 않는다.
  • 9단계: 장마감 CSV를 training/build_surge_dataset.py로 바꾸고 train_surge_lora.py로 회고 문장을 학습한다.

안전 장치

주식 API 프로그램은 재미있는 장난감처럼 보이지만, 실전 계좌와 연결되면 곧바로 돈이 움직인다. 따라서 이 예제는 모의투자와 페이퍼 트레이딩을 기본값으로 둔다. 실전 주문을 연결하려면 위험 고지, 권한 분리, 주문 전 확인, 최대 손실 제한과 로그 보존을 먼저 구현해야 한다.

분봉 가상매매와 장후 회고

앞의 paper_trade.py와 surge_monitor.py는 초안에 가깝다. 하나는 일봉으로 하루를 통째로 가정하고, 다른 하나는 1분봉 급등락을 알림으로만 남긴다. 그 다음 코드는 신호를 받자마자 사지 않는다. surge_paper_trade.py는 급등이 뜬 뒤 몇 분 동안 저점, 고점, 호가 스프레드, 매수 잔량을 본다. 스프레드가 벌어졌다가 다시 좁혀지고, 매수 잔량이 우세하고, 가격이 저점 근처에 있을 때만 가상으로 들어간다. 이 진입을 dip_peak이라고 부른다. 신호 봉 종가에 바로 사는 surge-close는 비교용으로만 남아 있다.

급등 뒤 눌림 구간의 저점에서 dip_peak 진입, 목표 +5%에서 익절하는 가격 곡선과 호가 스프레드가 벌어졌다 좁혀지는 모습, 진입 조건과 운용 규칙
그림. dip_peak 전략은 급등 직후가 아니라 눌림이 끝나는 지점에서 들어간다

체결은 한국투자증권 모의투자 시세와 메모리, CSV로만 계산한다. 주문 API는 호출하지 않는다. 종목당 한도는 100만 원이고, 동시에 보유하거나 관찰하는 종목은 기본적으로 셋이다. 목표 수익은 최소 +5%이고 손절은 매수가 기준이다. 장이 끝나면 남은 포지션은 마지막 분봉 종가로 정리하고, 들어가지 못한 관찰은 취소한다.

실제로 남은 기록(2026년 5월 13일~6월 4일, 청산 81건)을 모으면 이 설계의 과제가 숫자로 보인다. 처음에는 신호 봉 종가에 바로 사는 방식이었고, 곧 dip_peak 저점 매수로 바꾼 뒤 6월에는 돌파와 관찰 종료 후 추세 진입을 시험했다. 승률은 25.9%(21건)였고 누적 실현손익은 약 −109만 원이다. 손실 거래는 −3%에서 정확히 끊겼지만 이익 거래도 평균 +3.3%에 그쳐, 본전을 맞추려면 승률이 47.6%는 되어야 했다. 목표 수익을 손절 폭보다 충분히 크게 잡아야 하는 이유가 여기에 있다.

청산 81건의 누적 실현손익 곡선(약 −109만 원)과 신호 봉 종가·dip_peak·돌파·관찰 종료 후 추세 진입별 승률 막대
그림. 1분봉 급등 가상매매 81건의 누적 실현손익과 진입 방식별 승률

분봉 조회와 매매 판단을 한 프로세스에 두면 시세가 늦을 때 판단까지 멈춘다. surge_minute_redis_writer.py가 모의 분봉만 Redis에 넣고, surge_paper_trade.py는 그 값을 읽어 진입 여부만 정한다. 키는 hankook:surge:minute:{종목코드}다.

모의 분봉 수집이 Redis에 쓰고 가상매매 판단이 읽어 당일 CSV를 남기면, 데이터셋 만들기와 LoRA 학습으로 이어지는 반복 구조
그림. 시세 수집과 판단을 Redis로 나누고, 끝난 거래로 LoRA를 학습한다
chart/surge_paper_trade.py급등 뒤 저점과 호가를 보고 가상 매수·청산한다.
chart/surge_minute_redis_writer.py모의 1분봉만 조회해 Redis에 적재한다.
chart/surge_redis_common.py분봉 JSON 키 형식을 맞춘다.
chart/surge_paper_train_loop.py장중 가상매매 뒤 데이터셋 생성과 LoRA 학습을 반복한다.
chart/training/build_surge_dataset.py당일 CSV의 매수·매도 쌍을 손익 원인 설명으로 바꾼다.
chart/training/train_surge_lora.pyQwen2.5-0.5B 같은 작은 텍스트 모델에 LoRA를 얹는다.
surge_minute_redis_writer.py
  -> Redis hankook:surge:minute:{code}
  -> surge_paper_trade.py
  -> surge_paper_trades_YYYY-MM-DD.csv
  -> training/build_surge_dataset.py
  -> training/train_surge_lora.py

이 학습에서 LLM은 주문을 내지 않는다. 데이터는 이미 끝난 가상매매의 매수가, 매도가, 실현손익이다. 모델이 배우는 일은 그 급등 뒤에 왜 익절이었거나 손절이었는지를 문장으로 말하는 것이다. 차트 화면의 LLM 패널은 아직 자리만 있고, 사고 파는 조건은 규칙이 맡는다.

남아 있는 학습 기록은 이 단계가 아직 시작점이라는 것도 보여 준다. Qwen2.5-0.5B-Instruct에 붙인 LoRA는 17개 예제로 4 epoch, 28 step을 학습했고, loss는 2.86에서 0.009로, 토큰 정확도는 0.43에서 1.00으로 올라갔다. 그러나 17개 중 15개는 거래 4건을 질문만 바꿔 늘린 것이라, 이 숫자는 원인을 이해했다기보다 문장을 외웠다는 뜻에 가깝다. 끝난 가상매매가 매일 쌓여야 회고 모델도 의미를 갖는다.

28 step 동안 loss가 2.86에서 0.009로 내려가고 토큰 정확도가 0.43에서 1.00으로 올라가는 학습 곡선
그림. 장후 회고 LoRA(Qwen2.5-0.5B)의 loss와 토큰 정확도 — 17개 예제, 4 epoch

마무리

한국투자증권 API를 사용하면 개인 개발자도 시세 조회, 차트 대시보드, 이벤트 감시, 모의매매 같은 실전적인 프로그램을 만들 수 있다. 여기에 LLM을 붙이면 숫자와 로그가 사람의 언어로 바뀐다. 좋은 구조는 명확하다. API는 데이터를 가져오고, 규칙 엔진은 조건을 판정하고, LLM은 그 결과를 설명한다. 이 분업이 지켜질 때 주식 프로그램은 더 똑똑해지면서도 더 안전해진다.

참고 자료

  • KIS Developers 공식 포털: https://apiportal.koreainvestment.com/
  • 한국투자증권 공식 GitHub: https://github.com/koreainvestment/open-trading-api
  • KIS Developers 공식 GitHub 조직: https://github.com/koreainvestment