PYTHON/Kiwoom Open API

키움증권 OpenAPI 개발 가이드 사용 설명서 (2)

  • -

지난 포스팅에서는 OnEventConnect 이벤트가 발생할 경우 특정 함수를 실행하도록 한 후에, 그 함수 내에서는 CommConnect() 함수를 통해 해당 함수의 반환값을 받아와서 로그인 성공 여부를 판단하는 코드를 구축했었다.
이번 포스팅에서는 OnReceiveTrData 이벤트에 대해 자세한 사용 방법에 대해서 알아보도록 하자. 

키움증권 Open API에서 제공하는 이벤트 별 상세 내용과 사용 예시는 아래의 포스팅을 참고

 

키움증권 Open API 개발 가이드 사용 설명서 (1)

키움증권에서는 자사의 Open API의 사용 방법에 대해 기본적인 가이드 자료를 제공하고 있다. 다만 기본적으로 제공하는 함수의 형태가 파이썬에서 사용하기가 다소 어려운 형태로 되어 있기 때

trustyou.tistory.com

 

OnReceiveTrData 이벤트 처리 방법

일단 앞전의 포스팅에서도 살펴보았듯이 각 이벤트를 처리하는 코드는 다음과 같다.

self.kiwoom.OnReceiveTrData.connect(self.DEF_name)
self.kiwoom.OnReceiveReadlData.connect(self.DER_name)
self.kiwoom.OnReceiveMsg.coonect(self.DEF_name)
self.kiwoom.OnReceiveChejanData(self.DEF_name)
self.kiwoom.OnEvenctConnect.connect(self.DEF_name)
self.kiwoom.OnReceiveRealCondition.connect(self.DEF_name)
self.kiwoom.OnReceiveTrCondition.connect(self.DEF_name)
self.kiwoom.OnReceiveConditionVer.connect(self.DEF_name)

위의 코드 중 맨 윗 줄에 있는 코드가 바로 OnReceiveTrData 이벤트가 발생했을 경우에 특정 함수로 연결되도록 하는 부분이다. 해당 코드가 없는 경우에는 데이터를 요청하더라도 요청한 데이터의 결과값을 사용할 수 없게 되니, 반드시 사용하도록 하자.

 

OnReceiveTrData 이벤트가 뭔데?

결론부터 말씀드리자면, LONG CommRqData()를 사용했을 경우에 그 요청에 대한 응답으로 발생한다.
물론 이 외에도 다양한 함수들이 있지만, 대체적으로 OnReceiveTrData는 CommRqData()와 함께 쓰인다. 

그리고 키움증권의 개발 가이드 내에서의 해당 이벤트에 대한 정보를 살펴보자면 다음과 같은 구조를 가지고 있다.
void OnReceiveTrData(LPCTSTR sCcrNo, LPCTSTR sRQName, LPCTSTR sTrCode, LPCTSTR sRecordName, LPCTSTR sPreNext, LONG nDataLength, LPCTSTR sErrorCode, LPCTSTR sMessage, LPCTSTR sSplmMsg)
ScrNo : 화면번호
RQName : 사용자구분 명
TrCode : Tran 명
Recordname : record 명
PreNext : 연속조회 유무
DataLength, ErrorCode, Message, SplmMsg는 미지원

 

CommRqData()의 사용 방법

키움증권에서 제공하는 Open API 개발 가이드 자료를 보면 CommRqData의 원형에 대해 다음과 같이 설명하고 있다.

LONG CommRqData(BSTR sRQName, BSTR sTrCode, long nPrevNext, BSTR sScreenNo)
RQName : 사용자구분 명
TrCode : Tran 명 입력
nPrevNext : 0은 단순 조회, 2는 연속 조회
ScreenNo : 사용할 4자리의 화면 번호

여기서 RQName에는 단순하게 어디서 어떤 정보를 요청했는지를 확인할 수 있을 정도의 값을 입력하면 된다. 이에 대한 자세한 내용은 아래에서 확인해보도록 하고, TrCode에 대한 정보부터 확인해보도록 하자.

다음으로 TrCode는 키움증권에서 제공하는 KOA Studio 안에 보면 TR 목록이라는 것이 나오고, 그 안에는 opt10001, opt10080, opt10081 등등 opt로 시작하는 여러 가지 메뉴들이 있는데, 그것이 바로 TrCode이다.

다음으로 nPrevNext는 단순 조회를 요청할 것인지, 아니면 조회할 데이터가 더 있다면 추가적으로 조회할 연속인지를 정해서 요청하는 것이다. 이와 관련하여 추가적으로 서술하자면, 키움증권 OpenAPI의 경우에는 차트 데이터를 조회할 경우 한 번의 조회 시에 최대 600개의 데이터를 반환한다. 하지만 일봉 차트의 경우에는 1년이 약 240일의 거래일로 이루어져 있기 때문에, 3년치의 일봉 데이터를 불러오고자 할 경우에는 총 720개의 데이터로 이루어져 있기 때문에 요청 횟수 당 600번으로 제한하고 있기 때문에 120개의 데이터를 불러올 수 없게 된다. 이 경우에 nPrevNext를 연속 조회로 설정할 경우, 600번을 조회한 후에 그 뒤에 추가적인 데이터가 있는 경우에는 그 데이터까지 불러오도록 하는 것이다.

마지막으로 ScreenNo는 앞의 내용과 마찬가지로, 키움증권 '영웅문' 내에서 사용하는 화면 번호를 입력하면 된다. 영웅문 내에서 왼쪽 상단에 검색어를 입력하면 해당 화면 번호와 같이 창이 뜨니, 검색한 후에 그 값을 입력해주면 되고 만약에 잘 모르겠다면 KOA Studio 내에서 사용하고자 하는 TrCode의 입력 값을 눌러보면 해당 TrCode를 사용하고자 할 때 입력해야 할 화면 번호가 나온다. 거기서도 잘 모르겠다면, 영웅문 내에서 이 정보를 포함하고 있을 것 같다는 화면 번호를 입력하면 알아서 잘 데이터를 넘겨주니 걱정하지 말자.

자 그렇다면 이제 아래와 같은 코드를 통해 CommRqData 함수를 어떻게 사용하는지 살펴보도록 하자.
일단 첫 번째로, 정보를 요청하는 코드를 입력해야 정보를 요청할 수 있게 된다.

self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", 000020)
self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "RQRQRQ", "opt100001", 0, "0101")

SetInputValue 함수를 통해 입력하는 값이 000020이고 이 값은 "종목코드"라는 정보를 입력하고, 그 정보를 입력한 후에 해당 정보를 바탕으로 CommRqData 함수를 통해 해당 값을 opt100001이라는 TrCode에 요청하는 함수이다.
자 그렇다면 이제 정보에 RQRQRQ라는 이름으로 opt100001이라는 메뉴가 갖고 있는 정보를 요청했다. 그렇다면 이제 정보를 요청했으니, 파이썬 내에서는 OnReceiveTrData라는 이벤트가 발생하게 될 것이고 그와 연결된 함수가 실행된다.

다만 앞에서 살펴봤듯이, OnReceiveTrData는 그 뒤에 정말 다양한 정보들을 받아오게 되는데, 사실 4개의 변수는 사용하지 않으므로 앞에 있는 ScrNo, RQName, TrCode, RecordName, PreNext만 사용하면 된다. 
그런데 우리가 앞에서 CommRqData 함수를 사용할 때, 전송한 데이터는 사용자구분 명(RQName), Tran 명(TrCode), 연속 조회 여부(PrevNext), 화면 번호(ScrNo) 4개 뿐이었는데 OnReceiveTrData에서는 RecordName이라는 변수가 더 있다. 즉, 요청하지 않았는데 얘는 받아온다는 것이다. 즉, 우리가 정보를 입력하지 않은 값인데 지 혼자 받아왔다는 것은 우리가 별도로 관리해주지 않아도 된다는 것이다. 

self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", 000020)
self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "RQRQRQ", "opt100001", 0, "0101")

self.kiwoom.OnReceiveTrData.connect(self.OnReceiveTrData)

def OnReceiveTrData(ScrNo, RQName, TrCode, RecordName, PreNext):

여기까지 왔다면, 우리는 이제 앞에서 나중에 설명하기로 했던 RQName을 사용하게 된다. 즉, 사용자구분 명(RQName)이라는 변수는 무엇인지가 중요한데, 앞에서 입력했던 "RQRQRQ"가 바로 우리의 사용자구분명이다. 이것이 왜 필요한가 하면, CommRqData를 통해서 opt10001의 정보를 요청할 수도 있지만 opt10080, opt10081 등등 정말 다양한 정보를 요청할 수 있다. 하지만 종목에 대한 기본 정보를 요청하는 opt10001같은 경우에는 한 번만 요청하면 되겠지만, 차트 정보를 요청하는 opt10080같은 경우에는 한 곳 이상, 즉 두 군데 또는 세 군데에서 사용할 수 있다. 그렇기 때문에 사용자 구분명(위 예시의 경우에는 RQRQRQ가 사용자 구분명이 된다.)를 통해 어떤 작업을 실행할 것인지를 구분해주는 것이다. 
그렇다면 이제, def OnReceiveTrData((ScrNo, RQName, TrCode, RecordName, PreNext):의 아래에 어떤 작업을 하도록 할 것인지를 구축해주도록 하자.

 

고객님, 정보 요청을 했으면 받아가셔야죠 - GetCommData() 함수

앞의 부분에서 SetInputValue를 통해 요청할 정보를 입력한 후 CommRqData() 함수를 통해 그 정보를 키움증권 서버로 전송했고 그로 인해 OnReceiveTrData라는 이벤트가 발생해서 OnReceiveTrData라는 함수로 연결되었다. 
다시 말해, 알고자 하는 종목의 종목코드라는 정보를 입력해서 키움증권에 요청했고, 이제 그 정보를 받을 준비가 된 것이다. 이제 여기서 그 정보를 받아오는 함수가 바로 GetCommData() 함수이다. 그 GetCommData() 함수를 def OnReceiveTrData((ScrNo, RQName, TrCode, RecordName, PreNext): 아래에 넣어주기만 하면, 이제 요청한 정보의 결과값을 받아볼 수 있게 된다. 

앞에서도 그랬듯이, 코드를 작성하기 전에 앞서 GetCommData()에 대한 설명을 살펴보도록 하자.

BSTR GetCommData(LPCTSTR strTrCode, LPCTSTR strRecordName, long nindex, LPCTSTR strItemName)
strTrCode : Tran 코드 명
strRecordName : 레코드 명
nindex : 복수 데이터 인덱스
strItemName : 아이템 명

여기서 4개의 변수 중 Tran 코드 명(TrCode)은 우리가 앞전에 입력했으며, 레코드명(RecordName)은 다룰 필요가 없다고 설명했기 때문에 두 가지 변수에 대한 설명만 하도록 하겠다. 먼저 복수 데이터 인덱스(nindex)는 너무 복잡하니 항상 0만을 사용한다고 알고 넘어가도록 하자. 마지막으로 아이템 명(ItemName)은 바로 KOA Studio의 메뉴에서 볼 수 있는 값이다. 그렇다면 지금 사용하고 있는 TrCode = opt10001의 경우에는 어떤 아이템들이 있는지 아래의 사진을 통해 확인해보도록 하자.

[추신] 레코드 명(RecordName)에 대한 설명은 하지 않아도 된다고 이야기했는데, 위의 사진 중 맨 윗 부분에 opt10001 : 주식기본정보요청이라는 부분이 있다. 저기서 opt10001이 TrCode이고, 그 옆에 있는 주식기본정보요청이 바로 RecordName에 해당하는 값이다. 다만 정보를 따로 입력할 필요는 없기 때문에 그냥 '아 그게 그거구나' 하는 정도로만 짚고 넘어가자. 

다시 본론으로 돌아와, [OUTPUT]이라는 메뉴 아래에 보면 종목코드, 종목명, 자본금, PER, 매출액, 시가, 고가, 저가 등등 여러 가지 데이터들을 얻어올 수 있는데, 저기에 있는 하나하나가 모두 아이템 명에 해당한다. 즉, 종목명을 반환받고 싶다면 종목명을 ItemName 변수 자리에 입력해주면 되는 것이다. 

def OnReceiveTrData(ScrNo, RQName, TrCode, RecordName, PreNext):
	if RQname == "RQRQRQ":
		self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", TrCode, RecordName, 0, "종목명")

지금까지 설명한 코드는 위와 같은 형태이다. 즉, OnReceiveTrData라는 이벤트가 발생하면 OnReceiveTrData라는 함수가 실행되도록 하고, 만약 요청(CommRqData)했던 데이터의 RQName이 "RQRQRQ"라면 GetCommData 함수를 통해 "종목명"을 받아오도록 하는 구조이다. 

이제 요청한 정보에 대한 결과값 데이터를 받아오기까지 했으니, 그 정보를 처리하는 과정은 단순하다. 

# 정보를 바로 프린트하는 방법
print(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", TrCode, RecordName, 0, "종목명"))

# 정보를 변수에 저장한 후 프린트하는 방법
# 이 방법은 해당 정보를 다른 곳에 사용하거나 할 경우에 유용합니다.
valuable = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", TrCode, RecordName, 0, "종목명")
print(valuable)
log.debug("%s에 대한 종목명 조회가 완료되었습니다.", valuable)

 

지금까지 작성한 코드는 아래와 같다.

# 정보 요청하기
self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", 000020)
self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "RQRQRQ", "opt100001", 0, "0101")

# 이벤트 발생 시 이벤트 처리하기
self.kiwoom.OnReceiveTrData.connect(self.OnReceiveTrData)

# 반환 값 받아오기
def OnReceiveTrData(ScrNo, RQName, TrCode, RecordName, PreNext):
	if RQname == "RQRQRQ":
		self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", TrCode, RecordName, 0, "종목명")
		# 정보를 바로 프린트하는 방법
		print(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", TrCode, RecordName, 0, "종목명"))

		# 정보를 변수에 저장한 후 프린트하는 방법
		# 이 방법은 해당 정보를 다른 곳에 사용하거나 할 경우에 유용합니다.
		valuable = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", TrCode, RecordName, 0, "종목명")
		print(valuable)

 

728x90
반응형
Contents

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

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