PYTHON/Kiwoom Open API

키움증권 Open API - 조건 검색식 불러오기

  • -

이번 포스팅에서는 영웅문 내에서 설정된 조건검색식을 Open API와 연결된 파이썬을 통해 불러오고, 그를 바탕으로 검색된 종목의 종목코드를 출력하는 방법에 대해 서술하고자 한다. 조건검색식을 사용하면 편한 이유는 파이썬 내에서 특정 조건들을 만들어내지 않아도 된다는 것이다. 즉, 특정 조건에 알맞은 종목을 검색하는 데에 필요한 조건들을 만드는 것이 파이썬 내에 구축하는 것보다 차라리 영웅문 내의 조건검색 화면 내에서 구축하는 것이 백배 천배는 편하다는 것이다. 그러면 왜 굳이 파이썬으로 이러고 앉아있냐는 의문이 들 수 있는데, 그 이유는 영웅문 내에서 제공하지 않는 분석 조건들을 파이썬에서는 구축할 수 있기 때문이다. 물론 이 방법은 영웅문 내에 조건검색식이 구축되어 있지 않다면 사용할 수 없다. 왜냐하면 영웅문 내에 저장되어 있는 조건검색식을 바탕으로 검색된 종목을 조회하는 것이 목적이기 때문이다.

조건검색식과 관련된 코드를 구축하는 것은 이전과는 달리 두 개의 이벤트를 발생시키는 일이니 만큼 구조가 상당히 복잡하게 되어 있으니, 시작하기 전에 앞서 한 숨 크게 쉬고 차분한 마음으로 읽어내려가길 권한다. 이해를 돕기 위해 조건검색식 데이터를 조회하는 과정을 살펴보면 아래와 같이 정리할 수 있다.


self.kiwoom.dynamicCall : GetConditionLoad()

이벤트 발생 - OnReceiveConditionVer 

CONNECT def OnReceiveConditionVer()

self.kiwoom.dynamicCall : GetConditionNameList()

self.kiwoom.dynamicCall : SendCondition()

이벤트 발생 - OnReceiveTrCondition
→ 수신 데이터 : 화면번호, 종목코드, 조건식 이름, 조건식 인덱스, 연속조회 여부


 

조건검색 관련 이벤트 구축하기

키움증권 개발 가이드 내에서는 조건검색식과 관련하여 다음과 같은 두 개의 이벤트가 있음을 설명하고 있다.

이름 설명
OnReceiveTrCondition 조건검색 조회 응답 이벤트
OnReceiveConditionVer 로컬 사용자조건식 저장 성공여부 응답 이벤트

그렇다면 앞의 포스팅에서 OnReceiveTrData 이벤트를 처리해주었던 것처럼, 다음과 같이 위의 두 이벤트를 처리하도록 하는 코드를 구축하자.

# def __init__ 아래에 작성
self.kiwoom.OnReceiveTrCondition.connect(self.OnReceiveTrCondition)
self.kiwoom.OnReceiveConditionVer.connect(self.OnReceiveConditionVer)

 

서버에 저장되어 있는 조건검색식 리스트 불러오기 - GetConditionLoad 함수

조건 검색식을 사용하기 위한 절차 중에서 가장 먼저 이루어져야 하는 것은 바로 GetConditionLoad 함수이다. 이에 대해 개발 가이드 내에서 설명하고 있는 내용을 살펴보자.

원형 GetConditionLoad()
설명 서버에 저장된 사용자 조건식을 조회해서 임시로 파일에 저장
입력값  
반환값 사용자 조건식을 파일로 임시 저장
비고 조건검색 사용 시 이 함수를 최소 한 번은 호출해야 조건검색을 할 수 있다.
영웅문에서 조건검색을 수정했을 경우에도 최신의 사용자 조건을 받고 싶으면 다시 조회해야 한다.

위의 설명으로 미루어보면 GetConditionLoad()라는 함수는 서버에 저장되어 있는 조건검색식을 불러오는 함수라는 것을 알 수 있으며 조건검색식이 영웅문 내에서 수정된 경우에는 해당 함수를 다시 사용함으로써 해당 조건검색식을 새롭게 불러와야 변경된 사항이 적용된다는 것을 알 수 있다. 그렇다면 다음과 같이 코드를 제작해주도록 하자. 일단 GetonditionLoad()를 사용하면 개발 가이드에는 없는 내용이지만 결과값이 나오게 되는데, 그 값이 1이라면 조건 검색식이 올바르게 조회되어 잘 저장된 경우이고 1이 아니라면 검색식이 조회되지 않고 오류가 발생한 경우이다. 따라서 해당 값(아래 코드에서는 result)을 기준으로 조회가 되었는지 안되었는지를 확인할 수 있는 조건문도 추가해주도록 하자. 

def GetConditionLoad(self):
	result = self.kiwoom.dynamicCall("GetConditionLoad()")
	print(result)
    
	if is_loaded == 1:
		print("조건검색식이 올바르게 조회되었습니다.")
	elif is_loaded != 1:
		print("조건검색식 조회 중 오류가 발생했습니다.")

이제 코드를 실행하게 된다면 서버에 "내 조건검색식 좀 주세요." 라고 했으니 서버에서는 "가져가세요."라고 할 것이다. 이 때 서버에서 "가져가세요."라고 하는 부분이 바로 OnReceiveConditionVer 이벤트이다. 

 


728x90

 

OnReceiveConditionVer 이벤트 처리하기

맨 위에서 OnReceiveTrCondition과 OnReceiveConditionVer 두 개의 이벤트를 각각 이벤트 명과 동일한 함수 명으로 연결되도록 함으로써 이벤트 처리는 완료되었으니 이제 OnReceiveConditionVer 이벤트가 발생했을 때 동작할 활동들이 담긴 OnReceiveConditionVer라는 함수를 제작해주도록 하자. 이 함수 역시 개발 가이드를 살펴보자.

원형 OnReceiveConditionVer(iRet, Msg)
설명 로컬에 사용자 조건식 저장 성공 여부를 확인
입력값 iRet : 조건식 저장 성공 여부(1: 성공, 나머지는 실패)
반환값 없음

개발 가이드를 살펴보니 OnReceiveConditionVer에는 두 가지 변수가 반환된다는 사실을 확인할 수 있다. 다만 iRet이라는 변수는 조건식이 저장되었는지 아니면 저장에 실패하였는지를 알려주는 값이기 때문에, 예전에 로그인을 처리할 때 사용했던 것처럼 iRet == 1이라면 조건 검색식 저장에 성공되었음을, iRet != 1이라면 조건 검색식 저장에 실패하였음을 확인하도록 하는 코드를 구축할 수 있다. 하지만 OnReceiveConditionVer에서는 단순하게 위에서 이야기하는 iRet이나 Msg와 같은 변수를 사용하지 않고도 이벤트를 처리할 수 있기 때문에 아래와 같이 제작하도록 하자.

def OnReceiveConditionVer(self):
	pass

 

조건검색식 번호와 이름 조회하기 - GetConditionNameList() 함수

키움증권 Open API를 통해 조회하는 조건검색식에는 각 조건검색식마다 일련의 번호가 부여된다. 이 번호는 해당 조건검색식을 바탕으로 검색된 종목들의 정보를 요청할 때에 전송해주어야 하는 변수이기도 하다. 그렇다면 아래의 코드를 살펴보자.

def OnReceiveConditionVer(self):
	condition_list = {'index': [], 'name': []}
	temporary_condition_list = self.kiwoom.dynamicCall("GetConditionNameList()").split(";")
	print(temporary_condition_list)

condition_list라는 변수 내에 'index'와 'name'이라는 두 가지 키 값이 있는 것을 확인할 수 있는데, 조건검색식이 여러 개인 경우에는 각각의 일련번호와 이름을 연결지어 사용해야 하기 때문에 필요하다. 위와 같이 제작한 후에 if문 아래에서 trade.GetConditionLoad()를 입력한 후 실행하게 되면, 아래와 같은 결과값이 나오게 된다.

['000^조건검색기1', '015^조건검색기2', '']

본인의 경우에는 영웅문 내에 구축되어 있는 조건검색식이 두 개 뿐이라 위와 같이 출력됐다. 결과값을 보면 각 번호와 이름이 출력되었음을 확인할 수 있는데, 앞에 있는 000과 뒤에 있는 015가 'index'에 들어갈 값이고 조건검색기1과 조건검색기2가 'name'에 들어갈 값이다. 그렇다면 이를 for문을 제작함으로써 각각 'index'와 'name'에 값을 입력해주도록 하자.

def OnReceiveConditionVer(self):
	condition_list = {'index': [], 'name': []}
	temporary_condition_list = self.kiwoom.dynamicCall("GetConditionNameList()").split(";")
	print(temporary_condition_list)

	for data in temporary_condition_list:
		try:
			a = data.split("^")
			condition_list['index'].append(str(a[0]))
			condition_list['name'].append(str(a[1]))
		except IndexError:
			pass

일단 for문 안에 보면 try:가 보이는데, 이는 오류를 처리하기 위해 사용하는 것이다. 위의 출력물에 보면 알 수 있듯이 맨 뒤에 별도의 일련번호나 이름 없이 단순하게 ''만 표시되어 있는 것을 확인할 수 있는데, 그 값에 접근할 때 오류가 발생하기 때문에 except를 통해 오류를 처리하도록 구축한 것이다.

코드의 내용을 보면 try문 아래에서는 a = data.split("^")이라는 내용을 통해 "^"라는 문자열을 기준으로 앞뒤로 나누도록 구축했고, 그 중에서 앞에 있는 값(000 또는 015)은 'index'란에 입력(append)하고 뒤에 있는 값(조건검색식1 또는 조건검색시2)는 'name'란에 입력(append)하도록 하는 것이다.

 

조건검색식을 통해 검색된 종목 정보 요청하기 - SendCondition() 함수

이제 서버에 저장되어 있는 조건검색식의 일련번호와 이름을 불러왔다면, 그를 바탕으로 해서 서버에 해당 조건검색식의 정보를 전송한 뒤 그 조건검색식이 찾아낸 종목들의 데이터를 반환받아와야 한다. 여기서 서버에 해당 조건검색식의 정보(예를 들면 000과 조건검색식1)를 전송하는 함수가 SendCondition() 함수인 것이다. 마찬가지로 개발 가이드 내에서는 어떻게 설명하고 있는지 확인해보도록 하자.

원형 SendCondition(ScrNo, ConditionName, Index, Search)
설명 조건검색 종목조회 TR을 송신한다.
입력값 ScrNo : 화면번호
ConditionName: 조건명(이 경우 '조건검색식1')
Index : 조건명 인덱스(이 경우 '000')
Search : 조회구분(0:일반, 1:실시간, 2:연속)
반환값 성공은 1, 실패는 0

기본적으로 네 개의 변수가 포함되어 있음을 확인할 수 있는데, 하나하나 살펴보도록 하자. 일단 조건검색식과 관련된 화면번호(ScrNo)는 영웅문 내에서도 확인할 수 있는데, [0156]이다. 다음으로 ConditionName과 Index는 앞서 우리가 condition_list의 'index'와 'name'에 저장해두었으니 넘어가도록 하자. 마지막으로 Search는 조회 구분인데, 단순하게 조건식에 맞는 종목을 조회하기 위해서는 조회 구분을 0으로 하면 된다. 하지만 실시간 조건검색을 하기 위해서는 조회구분을 1로 해야 하며 이 경우에는 OnReceiveTrCondition으로 결과값을 받게 된다. 간단하게 말하자면 장중에 필요한 것이라면 1을, 장마감 후에 조회가 목적이라면 0을 입력하면 된다. 본인은 0을 입력하고 사용하고 있으므로, 0을 기준으로 계속해서 코드를 작성하겠다.

일단 앞에서 condition_list라는 변수의 'name'이라는 키 안에는 '조건검색식1'과 '조건검색식2'가 입력되어 있기 때문에 condition_list['name'][0]는 '조건검색식1'이고, condition_list['name'][1]은 '조건검색식2'이다. 마찬가지로 'index'라는 키 안에는 '000'과 '015'가 입력되어 있기 때문에 condition_list['index'][0]는 '000'이고 condition_list[index'][1]은 '015'이다. 이 경우에는 인덱스 '000', 조건명 '조건검색식1'을 기준으로 해서 조회된 종목을 반환하도록 하는 코드를 작성하고자 한다. 맨 뒤의 인덱스 값([0])만 변경해주면 원하는 조건검색식으로 조회할 수 있으니, 변경을 원한다면 변경해도 된다.

# def OnReceiveConditionVer(self): 아래에 이어서 제작
conditionname = str(condition_list['name'][0])
nindex = str(condition_list['index'][0])

그렇다면 SendCondition() 함수를 제작해서 바로 위에 있는 conditionname과 nindex를 서버에 보내주도록 하자. 아, 그리고 위에 있는 개발 가이드에서 살펴봤듯이, SendCondition이라는 함수는 반환값으로 1과 0을 보내준다. 1은 조회 요청을 성공했다는 것이고, 0은 조회 요청에 실패했다는 것이다. 

# def OnReceiveConditionVer 아래 이어서 제작
a = self.kiwoom.dynamicCall("SendCondition(QString, QString, int, int)", "0156", str(conditionname), nindex, 0)
	if a == 1:
		print("조건검색 조회 요청 성공")
	elif a != 1:
		print("조건검색 조회 요청 실패")

 

그리고 이제 SendCondition 함수가 실행되면 해당 조건검색식이 찾아낸 종목 코드들을 서버에서 우리에게 알려주게 되는데, 그 정보가 도착했을 때 또 다른 이벤트가 발생하게 된다.

 

정보 받아가! - OnReceiveTrCondition 이벤트

이 이벤트는 OnReceiveConditionVer 이벤트를 처리할 때 같이 처리했었는데, 기억이 날지 모르겠지만 OnReceiveTrCondition이라는 함수로 연결되도록 설정했었다. 그렇다면 OnReceiveTrCondition 이벤트는 어떤 값들을 가지고 오는지 살펴보도록 하자.

원형 OnReceiveTrCondition(ScrNo, CodeList, ConditionName, index, Next)
설명 조건검색 조회응답으로 종목리스트를 구분자(";")로 받음
입력값 ScrNo : 
CodeList : 종목리스트(";")로 구분
ConditionName : 조건명
Index : 조건명 인덱스
Next : 연속조회 여부(0:연속조회 없음, 2:연속조회)
반환값 없음

사실 이 이벤트의 경우에는 총 5개의 변수를 가지고 오긴 하지만 사실 우리가 사용할 변수는 CodeList 뿐이다. 물론 변수 지정은 모두 해주어야 겠지만, 함수 내에서는 CodeList만 따로 사용하면 된다는 것이다. 

def OnReceiveTrCondition(self, scrno, codelist, conditionname, nindex, nnext):
	self.code_list = []
	self.code_list.append(codelist)
	print(self.code_list)	

 

이제 실행해보면 다음과 같이 본인만의 검색식에 따른 종목들의 코드가 세미콜론(;)을 달고 줄줄이 나오는 것을 확인해볼 수 있다. 이 역시 self.code_list 뒤에 .split(";")을 통해 각각 나누어준 다음에, for문 내에서 각각의 코드들을 특정 변수에 입력(append)하도록 구축하면 된다.

키움증권 Open API 에서 발생되는 이벤트의 개수는 총 8개인데 이번 포스팅까지 벌써 4개의 이벤트를 처리했다. 이제 남아 있는 이벤트는 OnReceiveRealData(실시간 데이터 처리, 장중에 사용), OnReceiveMsg(에러 메시지 발생시 발생하는 이벤트), OnReceiveChejanData(주문 접수 및 확인 수신 시 발생하는 이벤트), OnReceiveRealCondition(실시간 조건검색 시 사용하는 이벤트)의 네 개이다. 딱 보면 알겠지만, 거의 실시간 데이터를 처리하는 것들이기 때문에 논외로 하고 다음 포스팅에서는 MySQL 데이터베이스와 파이썬을 연결하는 방법에 대해 다뤄보고자 한다. 주식 주문 체결 함수인 OnReceiveChejanData에 대해서는 나중에 다룰 예정이다.

 


 

728x90
반응형
Contents

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

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