키움증권 OpenAPI를 활용한 주가 데이터 수집 방법
이번 포스트에서는 키움증권 OpenAPI를 이용해 종목의 주가 데이터를 수집하는 방법을 알아보겠습니다. 주식 데이터 수집은 자동매매 시스템을 만들거나, 주식 데이터 분석에 있어 중요한 부분입니다. 이 예시에서는 PyQt5와 Kiwoom API를 사용하여 특정 종목의 일봉 데이터를 가져오는 코드를 설명합니다.
1. Kiwoom 클래스 설정
키움증권 OpenAPI를 연동하기 위해 QAxWidget을 상속받는 Kiwoom 클래스를 정의합니다. 이 클래스는 키움증권 API와의 통신을 위한 초기 설정, 종목 코드 요청, 주가 데이터를 받아오는 함수들을 포함하고 있습니다.
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import pandas as pd
class Kiwoom(QAxWidget):
def __init__(self):
super().__init__()
self._make_kiwoom_instance()
self._set_signal_slots()
self._comm_connect()
self.tr_event_loop = QEventLoop()
# 키움 API 인스턴스 생성
def _make_kiwoom_instance(self):
self.setControl("KHOPENAPI.KHOpenAPICtrl.1")
# 이벤트와 슬롯 연결
def _set_signal_slots(self):
self.OnEventConnect.connect(self._login_slot)
self.OnReceiveTrData.connect(self._on_receive_tr_data)
# 로그인 처리
def _login_slot(self, err_code):
if err_code == 0:
print("connected")
else:
print("not connected")
self.login_event_loop.exit()
# 로그인 요청
def _comm_connect(self):
self.dynamicCall("CommConnect")
self.login_event_loop = QEventLoop()
self.login_event_loop.exec_()
# 종목코드별 주가 데이터를 가져오는 함수
def get_price_data(self, code):
# 주가 데이터를 요청하기 위해 입력값 설정
self.dynamicCall("SetInputValue(QString, QString)", "종목코드", code)
self.dynamicCall("SetInputValue(QString, QString)", "수정주가구분", "1")
self.dynamicCall("CommRqData(QString, QString, int, QString)", "opt10081_req", "opt10081", 0, "0001")
self.tr_event_loop.exec_()
ohlcv = self.tr_data
# 추가 데이터가 있을 경우 반복적으로 호출하여 데이터를 수집
while self.has_next_tr_dara:
self.dynamicCall("SetInputValue(QString, QString)", "종목코드", code)
self.dynamicCall("SetInputValue(QString, QString)", "수정주가구분", "1")
self.dynamicCall("CommRqData(QString, QString, int, QString)", "opt10081_req", "opt10081", 2, "0001")
self.tr_event_loop.exec_()
for key, val in self.tr_data.items():
ohlcv[key] += val
# 수집된 데이터를 DataFrame으로 변환하여 반환
df = pd.DataFrame(ohlcv, columns=['open', 'high', 'low', 'close', 'volume'], index=ohlcv['data'])
return df[::-1]
# TR 데이터 수신 처리
def _on_receive_tr_data(self, screen_no, rqname, trcode, record_name, next, unused1, unused2, unused3, unused4):
tr_data_cnt = self.dynamicCall("GetRepeatCnt(QString, QString)", trcode, rqname)
if next == '2':
self.has_next_tr_dara = True
else:
self.has_next_tr_dara = False
if rqname == "opt10081_req":
ohlcv = {'data': [], 'open': [], 'high': [], 'low': [], 'close': [], 'volume': []}
for i in range(tr_data_cnt):
data = self.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, rqname, i, "일자")
open = self.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, rqname, i, "시가")
high = self.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, rqname, i, "고가")
low = self.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, rqname, i, "저가")
close = self.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, rqname, i, "현재가")
volume = self.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, rqname, i, "거래량")
ohlcv['data'].append(data.strip())
ohlcv['open'].append(int(open))
ohlcv['high'].append(int(high))
ohlcv['low'].append(int(low))
ohlcv['close'].append(int(close))
ohlcv['volume'].append(int(volume))
self.tr_data = ohlcv
self.tr_event_loop.exit()
2. 주가 데이터 요청 흐름
get_price_data 메서드를 통해 종목코드와 수정주가구분(1)을 설정하여 CommRqData로 주가 데이터를 요청합니다. 이 때 opt10081 요청을 통해 일봉 데이터를 받아옵니다.
수신된 데이터는 _on_receive_tr_data 함수에서 처리되며, GetCommData 메서드를 통해 시가, 고가, 저가, 종가, 거래량 등의 데이터를 가져와서 ohlcv라는 딕셔너리 형태로 저장합니다. 수집된 데이터를 pandas의 DataFrame으로 변환하여 역순으로 반환하게 됩니다.
3. 데이터 요청 예시
이제 특정 종목의 주가 데이터를 가져오는 간단한 예시를 실행해보겠습니다. 예를 들어 삼성전자의 주가 데이터를 요청하는 경우입니다.
from api.Kiwoom import *
import sys
app = QApplication(sys.argv)
kiwoom = Kiwoom()
# 삼성전자(005930) 주가 데이터 요청 및 출력
df = kiwoom.get_price_data("005930")
print(df)
app.exec_()
이 코드를 실행하면 삼성전자의 일봉 데이터를 얻을 수 있습니다. 이 데이터는 DataFrame으로 반환되며, 각 열에는 시가, 고가, 저가, 종가, 거래량 등의 정보가 포함되어 있습니다.
4. 실행결과
이 코드를 실행하면 삼성전자의 주가데이터를 출력할 수 있습니다.
결론
이 포스트에서는 키움증권 OpenAPI를 활용하여 특정 종목의 주가 데이터를 수집하는 방법을 살펴보았습니다. 이 데이터를 활용하여 차트를 그리거나, 특정 조건에 맞는 종목을 필터링하여 분석하는 등 다양한 방식으로 응용할 수 있습니다.