PYTHON/Kiwoom Open API

키움증권 Open API 차트 데이터 불러오기 (2)

  • -

지난 포스팅에서 OnReceiveTrData 이벤트 발생 시 OnReceiveTrData() 함수로 연결되도록 하고, 이벤트 루프까지 제작해두었다. 또한 CommRqData를 통해 입력한 값들이 OnReceiveTrData() 함수를 통해 반환된다는 것도 확인하였다.

 

키움증권 Open API 차트 데이터 불러오기 (1)

OnReceiveTrData 이벤트 처리하기 지난 포스팅에서 Open API를 열고 로그인을 하는 코드까지 모두 구축하고 넘어왔다. 이번 포스팅에서는 로그인 이후에 조회하고자 하는 종목의 차트 데이터를 불러오

trustyou.tistory.com

이번 포스팅에서는 prenext가 2인 경우 즉, 추가로 조회할 데이터가 있는 경우에는 어떻게 불러올 수 있는지 그리고 차트 데이터를 어떻게 불러올 수 있는지 등에 대해 작성할 예정이다.

 

추가 데이터 조회 구축 - OnReceiveTrData 함수 수정하기

지난 게시글에서 prenext가 어떤 함수에서 사용할 수 있는 변수인지 기억이 나는가? 바로 OnReceiveTrData 함수에서 사용 가능했다. 하지만 우리가 차트 데이터 조회를 요청하는 함수는 rq_chart_data 함수였다. 즉, rq_chart_data 함수에서는 prenext 값을 얻어올 수 없다는 것이다. 지난 포스팅에서 제작했던 차트 데이터 조회 요청의 구조를 보면 다음과 같다.

rq_chart_data 함수 → OnReceiveTrData 이벤트 → OnReceiveTrData 함수

여기서 문제는 추가 데이터를 조회할 수 있는지의 여부를 OnReceiveTrData 함수에 도달해서야 확인할 수 있다는 것이다. 그렇다면 어떻게 해야 rq_chart_data 함수 내에서 추가로 조회가 가능한 데이터가 있는지의 여부를 확인할 수 있을까? 그는 바로 OnReceiveTrData 함수 내에서 self를 이용한 변수를 설정해주면 된다. self는 단순하게 말하자면, 특정 클래스(Class) 내에서의 전역 변수로 사용할 수 있도록 하는 방법이라고 생각하면 된다. 다시 말해, OnReceiveTrData에서 self를 이용한 변수에 추가로 조회가 가능한 데이터의 존재 유무를 확인할 수 있도록 한다면 이후 rq_chart_data 함수에서도 그 값을 이용할 수 있다는 것이다. 보다 편리한 이해를 위해 지난 게시글에서 작성했던 코드를 실행해보고 그를 바탕으로 OnReceiveTrData의 코드 구조를 수정하도록 하자. 현재 코드의 결과물은 다음과 같다.

연결되었습니다..
로그인에 성공하였습니다.
scrno: 0101
rqname: hello
trcordname: opt10081
recordname: 
prenext: 2

prenext: 2라는 부분을 바탕으로 우리는 추가로 조회할 수 있는 데이터가 있다는 것을 확인할 수 있기 때문에, 해당 함수 내에 다음과 같은 내용을 추가해주도록 하자.

if prenext == 2:
	self.remained_data = True
elif prenext != 2:
	self.remained_data = False

즉, prenext가 2라면 남아 있는 데이터가 Ture이며 2가 아니라면 False라는 값을 입력하도록 하는 것이다. 여기서 사용한 self.remained_data 변수는 rq_chart_data 함수 내에서도 이용할 수 있다. 현재의 OnReceiveTrData 함수의 코드는 아래의 더보기를 클릭하면 볼 수 있다.

더보기
def OnReceiveTrData(self, scrno, rqname, trcode, recordname, prenext, unused1, unused2, unused3, unused4):
	if prenext == '2':
		self.remained_data = True
	elif prenext != '2':
		self.remained_data = False

	print(self.remained_data)
	print("scrno:", scrno)
   	print("rqname:", rqname)
	print("trcordname:", trcode)
	print("recordname:", recordname)
	print("prenext:", prenext)

 

추가 데이터 조회 구축 - rq_chart_data 함수 수정하기

이제 OnReceiveTrData 함수 내에서 추가로 조회 가능한 데이터가 있는지의 여부를 self.remained_data 변수에 입력하였으니 rq_chart_data 함수 내에서는 self.remained_data라는 변수를 통해 추가 조회를 요청할 것인지를 제작할 수 있다.

while self.remained_data = True:
	self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", itemcode)
	self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "기준일자", date)
	self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "수정주가구분", justify)
	self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "hello", "opt10081", 2, "0101")
	self.tr_event_loop = QEventLoop()
	self.tr_event_loop.exec_()

즉, 위와 같은 코드를 rq_chart_data의 하단 부분에 추가해주면 된다. 그렇다면 아래와 같은 코드의 모습을 갖추게 될텐데, 의아한 점이 있다. while 문을 기준으로 위와 아래의 코드에 어떤 차이점이 있는지 잘 모를 수 있는데, 바로 CommRqData를 사용하는 부분에서 세 번째 변수로 '2'라는 값을 입력해주었다. 마찬가지로, 현재의 rq_chart_data 함수의 코드 구조는 더보기를 클릭하면 확인할 수 있다.

더보기
def rq_chart_data(self, itemcode, date, justify):
	self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", itemcode)
	self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "기준일자", date)
	self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "수정주가구분", justify)
	self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "hello", "opt10081", 0, "0101")
	self.tr_event_loop = QEventLoop()
	self.tr_event_loop.exec_()

	while self.remained_data == True:
		self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", itemcode)
		self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "기준일자", date)
		self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "수정주가구분", justify)
		self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "hello", "opt10081", 2, "0101")
		self.tr_event_loop = QEventLoop()
		self.tr_event_loop.exec_()

삼성전자의 경우 상장일이 1900년대이기 때문에 엄청나게 많은 데이터들이 있기 때문에 이제 여기까지의 코드를 바탕으로 실행해보면, self.remained_data라는 변수의 값이 True가 입력되어 있다는 것을 확인할 수 있다.

 

차트 데이터 가져오기 - GetCommData() 함수

일단 앞서 제작한 코드 내에서, CommRqData 내에 입력한 값들이 OnReceiveTrData라는 함수 내에서 각각 scrno, rqname, trcord, recordname 등의 변수로 출력된다는 것을 확인하였다. 다만 여기서 이야기하고자 하는 것은 바로 KOA Studio 내에서도 확인할 수 있듯이, 차트 조회를 요청할 경우 일봉 차트를 조회할 때에는 opt10081이라는 trcode만을 사용해야 한다는 것이다. 하지만 우리는 일봉 차트에서는 괜찮을진 몰라도 분봉 차트를 조회할 경우에는 3분봉이든 5분봉이든 15분봉이든 간에 opt10080을 사용해야만 한다. 그렇다면 3분봉을 사용하든 5분봉을 사용하든 여러 개의 함수를 제작하게 될 수도 있고 opt10080을 사용하는 함수를 여러 번 제작하게 될 수도 있기 때문에 사용자가 임의적으로 사용할 수 있는 rqname이라는 변수를 바탕으로 데이터를 불러오도록 할 것이다. 다시 말해, 지금의 경우에는 rqname이 hello로 설정되어 있으며 이 hello라는 값은 우리가 입력한 값이다. 그렇기 때문에 OnReceiveTrData 내에서 rqname이 hello라면 다음과 같은 함수를 실행하라는 코드를 구축할 수 있다. 그렇다면 이제 OnReceiveTrData 내에 다음과 같은 코드를 추가해주도록 하자.

if rqname == 'hello':
	self.opt10081()

 

즉, rqname이 hello라면 opt10081이라는 함수를 실행하도록 하는 코드이다. 이에 따라서 우리는 opt10081이라는 함수를 제작해주면 되는데, 그 안에서 사용할 함수가 바로 GetCommData()함수이다. 이 함수도 마찬가지로 개발 가이드 내에 서술되어 있는 설명을 한 번 보고 넘어가도록 하자. 앞으로 사용할 모든 정보 요청은 위와 같이 OnReceiveTrData 내에서 수신된 rqname을 바탕으로 함수를 연결해주면 된다. opt10081의 경우에는 rqname을 hello로 입력하고 정보를 요청했기 때문에 if rqname == 'hello':라는 조건문을 내걸어 함수를 연결하는 것 뿐이다. 만약 다른 정보를 요청할 때 CommRqData 내에서 rqname 자리에 hi를 입력했다면 마찬가지로 OnReceiveTrData 내에서는 rqname == 'hi':를 통해 연결하고자 하는 함수와 연동하면 된다.

원형 GetCommData(Trcode, RecordName, index, itemName)
설명 수신 데이터를 반환한다
입력값 Trcode : Tran 코드
RecordName : 레코드 명
Index : 복수데이터 인덱스
ItemName : 아이템 명
반환값 수신 데이터

즉, GetCommData를 사용하기 위해서는 TrCode, RecordName, index, itemName이라는 네 개의 변수를 사용해야 한다. 이와 관련하여 우리는 앞에서 제작했던 코드를 실행하고 OnReceiveTrData에 반환된 그 결과값을 확인했었는데, 그 결과값 안에는 scrno, rqname, trcord, prenext만 있었고 recordname와 index, itemname이라는 세 개의 변수는 찾아볼 수 없었다. 즉, 'TrCode가 opt10081이다'라는 정보만 우리가 확인할 수 있다는 것이다. 그렇다면 나머지 세 개의 변수는 무엇을 입력해야하는지 어디서 확인할 수 있는가? 사실 이는 앞의 포스팅에서 이미 한 번 다루었었다. 물론 여기서도 재차 설명할 것이지만, 앞서 작성했던 포스팅을 읽으면서 봤던 기억이 있다면 그 부분을 상기시키면 보다 이해가 잘 될 수 있으니 봤었나? 싶다면 보고 올 수 있도록 링크를 걸어두도록 하겠다.

 

키움증권 Open API 작동 과정

키움증권의 경우 Open API를 제공하고 있으며, 실제로 사용할 함수의 종류는 키움증권 사이트 내 '개발 가이드' 파일 또는 'KOA Studio'라는 프로그램을 통해 확인할 수 있다. 이번 글에서는 이 함수들

trustyou.tistory.com

자 이제 우리는 KOA Studio 프로그램을 켜서 Recordname과 index, itemname을 확인해보자. 지금 현재 사용하고자 하는 opt10081을 더블클릭하면 다음과 같은 화면이 나온다는 것을 확인할 수 있다.

위의 사진에서 파란색 배경으로 칠해져 있는 구간을 보면 opt10081 : 주식일봉차트조회요청이라고 작성되어 있는데, opt10081은 여러 번 봤듯이 TrCode이며 그 뒤에 있는 주식일봉차트조회요청이 RecordName이다. 마지막으로 ItemName은 그 아래에 있는 종목코드, 현재가, 거래량, 거래대금, 일자, 시가, 고가, 저가, 전일종가 등등 다양한 데이터들을 의미한다. 그렇다면 Index는 어디서 확인할 수 있는지 궁금할 수도 있는데, 이 index라는 값은 지금 몇 번째 조회하고 있는지에 관한 정보를 담고 있는 변수이다. 그렇다면 이제 opt10081이라는 새로운 함수를 만들고 GetCommData를 제작해보도록 하자.

def opt10081(self):
	item_code = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10081", "주식일봉차트조회요청", 0, "종목코드")
	print(item_code)

앞서 살펴봤듯이 trcode(첫 번째 자리)에는 opt10081을, recordname(두 번째 자리)에는 주식일봉차트조회요청을, index(세 번째 자리)에는 0을, itemname(네 번째 자리)에는 종목코드를 입력했다. 이제 이를 실행해보면 005930이라는 값을 얻을 수 있게 된다.

 

아니 근데 이걸 다 일일이 써야 되나? 귀찮은데..

일단 바로 위에 있는 코드를 보면 알 수 있듯이, 코드가 길다보니 지 혼자 줄을 바꾸는 일이 생기게 되는데, 이는 GetCommData라는 함수를 별도로 제작함으로써 보다 깔끔하게 이용할 수 있다. 이제 함수를 만들어보도록 하자.

def GetCommData(self, trcode, recordname, index, itemname):
	result = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", trcode, recordname, index, itemname)
	return result

즉 GetCommData 함수는 trcode, recordname, index, itemname이라는 네 가지 변수를 받아오도록 제작했다. 그리고 그 값을 result라는 변수에 입력한 후, 그 변수를 반환하도록 제작하였다. 이제 self.GetCommData라는 코드를 입력함으로써 길다란 self.kiwoom. 뭐시기 뭐시기 코드를 일일이 입력하지 않아도 사용할 수 있게 되었다. 물론 복사 붙여넣기 신공으로 제작할 수도 있지만, 코드가 좌우로 길어지게 되면 알아서 줄이 넘어간다거나 하는 문제점들이 있기 때문에 별도의 함수를 제작함으로써 이용하는 것이 깔끔하고 편리할 수도 있다. 그렇다면 이제 opt10081이라는 함수 내에 지저분하게 제작되어 있던 코드를 다음과 같이 수정해보자.

def opt10081(self):
	item_code = self.GetCommData("opt10081", "주식일봉차트조회요청", 0, "종목코드")
	print(item_code)

그 후에 다시 실행해보면 역시 마찬가지로 005930이라는 결과값을 얻어오는 모습을 확인할 수 있다. 이제부터 우리는 self.GetCommData(trcode, recordname, index, itemname)이라는 구조를 통해 길다란 코드를 대체할 수 있게 됐다. 앞전의 코드와 비교하여 백배 천배는 깔끔해졌다는 걸 확인할 수 있다. 이를 응용하여, Open API를 사용할 때 자주 사용하게 되는 SetInputValue 또는 CommRqData 역시 하나의 함수로 제작하여 사용할 수도 있으니, 사용하고 싶다면 미리 함수를 제작해놓고 본인만의 방법대로 이 글을 따라와도 된다.

 

시가와 고가, 저가, 현재가(종가) 전일 종가 불러오기

다시 본론으로 돌아와, 아까 제작하다 말았던 opt10081이라는 함수 내에 종목 코드 외에도 여러 가지 아이템명을 입력하여 데이터를 불러오도록 하자. 아이템 명은 위의 사진에 있는 여러 가지 정보들이 모두 아이템 명이기 때문에, 아래의 코드에 포함되지 않은 정보가 궁금하다면 그에 관한 정보도 따로 구축해도 된다. 본인이 사용할 정보라면 가리지 말고 모두 사용하도록 하자.

def opt10081(self):
	item_code = self.GetCommData("opt10081", "주식일봉차트조회요청", 0, "종목코드")
	date = self..GetCommData("opt10081", "주식일봉차트조회요청", 0, "일자")
	open = self.GetCommData("opt10081", "주식일봉차트조회요청", 0, "시가")
	high = self..GetCommData("opt10081", "주식일봉차트조회요청", 0, "고가")
	low = self..GetCommData("opt10081", "주식일봉차트조회요청", 0, "저가")
	close = self..GetCommData("opt10081", "주식일봉차트조회요청", 0, "현재가")
	yester_close = self..GetCommData("opt10081", "주식일봉차트조회요청", 0, "전일종가")
	volume = self..GetCommData("opt10081", "주식일봉차트조회요청", 0, "거래량")
	trade_volume = self..GetCommData("opt10081", "주식일봉차트조회요청", 0, "거래대금")

	print("종목코드:", item_code)
	print("조회일자:", date)
	print("전일종가:", yester_close)
	print("시가:", open)
	print("고가:", high)
	print("저가:", low)
	print("종가:", close)
	print("거래량:", volume)
	print("거래대금:", trade_volume)

이제 위의 코드를 실행하면, 아래와 같은 결과물을 얻을 수 있다.

종목코드:               005930
조회일자:             20210528
전일종가:                     
시가:                79800
고가:                80400
저가:                79400
종가:                80100
거래량:             12360199
거래대금:               988666

결과값을 보니 서버로부터 받아온 결과값 안에 의미 없는 띄어쓰기가 많이 포함되어 있는 것을 확인할 수 있다. 이 띄어쓰기는 strip()을 사용함으로써 제거할 수 있는데, 사용례는 아래와 같다. 코드 하나하나 맨 뒤 부분에 .strip()을 붙여넣어주면 띄어쓰기가 제거된 후 깔끔한 결과물을 출력되는 것을 확인할 수 있다.

item_code = self.GetCommData("opt10081", "주식일봉차트조회요청", 0, "종목코드").strip()

 

종목코드: 005930
조회일자: 20210528
전일종가: 
시가: 79800
고가: 80400
저가: 79400
종가: 80100
거래량: 12360199
거래대금: 988666

 

이번 포스팅에서 차트 데이터 조회에 대한 내용을 마무리하려 했으나 작성하다보니 내용도 길어지고 눈도 뻑뻑해져서 현재 데이터 뿐만 아니라 이전의 데이터를 불러오도록 하는 내용은 다음 포스팅에서 마무리하도록 하겠습니다.

728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.