키움증권 Open API - 관심종목 관리하기 (2)
지난 게시글에서 언급했듯, 이번 글에서는 개별적 문제점들에 대한 해결 방법을 살펴볼 예정이다. 다만 문제점 ①이 아닌 문제점 ②를 먼저 다룰 예정인데, 이렇게 해야 수순이 맞다.
왜냐하면 관심종목이라는 역할을 수행할 수 있는 데이터베이스를 생성하기 위해서는 일단 대입할 종목코드 리스트가 필요한데, 그 종목코드 리스트는 조건검색식[0151]을 통해야 보다 수월하게 데이터를 조회할 수 있기 때문이다. 키움증권 상에서 조건검색식을 만드는 방법에 대해서는 여타 다른 게시글에서 충분히 설명하고 있으니 검색해서 보시길 바란다.
본격적인 설명에 앞서 영웅문 내에서 설정한 조건검색식의 조건을 바탕으로 선정된 종목을 살펴보도록 하겠다.
- A : [골든 크로스] 10일 이동평균선이 20일 이동평균선을
- D : [골든 크로스] 5일 이동평균선이 10일 이동평균선을
- B : 거래량 10,000,000주 이상
- C : 거래대금 500억 이상
조건식을 자세히 보면 (A or D) and B and C 라고 적혀있는데, 이는 A와 D 둘 중에 하나의 조건이 들어맞는 동시에 B와 C가 충족되는 종목을 찾으라는 의미이다. 이 조건 하에 검색된 종목은 까뮤이앤씨[013700] 와 세종메디칼[258830] 두 종목이다. 이제 이 데이터를 가지고 조건검색식을 조회했을 때 두 종목의 종목 코드를 제대로 가져오는지 한 번 살펴보도록 하자.
self.kiwoom.dynamicCall : GetConditionLoad()
▼
이벤트 발생 - OnReceiveConditionVer
▼
CONNECT def OnReceiveConditionVer()
▼
self.kiwoom.dynamicCall : GetConditionNameList()
▼
self.kiwoom.dynamicCall : SendCondition()
▼
이벤트 발생 - OnReceiveTrCondition
→ 수신 데이터 : 화면번호, 종목코드, 조건식 이름, 조건식 인덱스, 연속조회 여부
조건검색식 조회 ① GetConditionLoad()
여기서 GetConditionLoad()는 단순하게 로그인된 계정에 등록되어 있는 조건검색식 데이터를 불러오는 절차에 해당하며 이 함수는 OnReceiveConditionVer라는 이벤트를 발생시키게 된다. 이벤트 이름만 봐도 알 수 있듯이, 조건검색식의 버전 처리에 해당하는 함수라고 봐도 무방하다.
## GetConditionLoad 함수 실행하기
def _getconditionload():
self.kiwoom.dynamicCall("GetConditionLoad()")
조건검색식 조회 ② OnReceiveConditionVer()
이제 GetConditionVer() 함수를 실행했다면 OnReceiveConditionVer 이벤트가 발생하게 되는데, 그 이벤트를 처리해주면 된다. 여기서 이벤트를 처리한다는 것은 이벤트가 발생했을 때 실행할 함수와 연결한다고 생각하면 이해가 쉽다.
다만 OnReceiveConditionVer 이벤트에서는 반드시 주의해야 하는 점이 있다면 GetConditionNameList() 함수를 반드시 OnReceiveConditionVer 내에서 처리해주어야 한다는 것이다. 이 GetConditionNameList() 함수는 현재 조건검색식으로 등록되어 있는 조건검색식의 제목과 각 조건검색식에 할당된 인덱스 번호를 전달해준다는 것이다.
※ 여기서의 인덱스 번호는 경험상 무작위적으로 부여되는 것 같기도 한데, 정확하지는 않다.
여기서 조건검색식 별로 할당되어 있는 인덱스 번호와 조건검색식 명은 해당 조건검색식을 통해 검색된 종목 코드를 얻기 위해 반드시 전달해주어야 하는 변수이다.
## 이벤트 처리하기
self.kiwoom.OnReceiveConditionVer.connect(self.OnReceiveConditionVer)
## OnRecieveConditionVer 처리하기
## GetConditionNameList() 함수 실행하기
def OnReceiveConditionVer():
condition_list = self.kiwoom.dynamicCall("GetConditionNameList()").split(";")
## GetConditionLoad 함수 실행하기
def _getconditionload():
self.kiwoom.dynamicCall("GetConditionLoad()")
그렇다면 위의 OnReceiveConditionVer() 함수 내에서 GetConditionNameList() 함수를 통해 조건검색식 별 조건검색식명과 인덱스 번호를 condition_list 변수에 입력했으니 해당 변수를 가공해서 조건검색식 별 이름과 인덱스를 정리한 데이터를 생성해주어야 한다.
GetConditionNameList() 함수를 통해 condition_list 변수에 조건검색식 관련 데이터를 입력했는데, 그 데이터 형식은 ['인덱스번호^조건검색식명' , '인덱스번호^조건검색식명', '인덱스번호^조건검색식명', '']과 같이 생성된다. 즉 데이터가 리스트 형태로 전달되기 때문에 인덱싱을 통해 각각의 데이터에 접근할 수 있도록 하였으며 각각의 데이터는 조건검색식별로 부여된 인덱스번호와 조건검색식의 이름이 특수문자 ^를 기준으로 좌우에 위치해있다는 것이다.
따라서 우리는 for 문을 통해 condition_list 내에 입력된 데이터를 각각 인덱스 번호와 조건검색식 명으로 구분하여 데이터를 가공해주어야 한다. 일단 2번 줄에서 self.condition_list 변수를 생성해서 조건검색식과 관련된 데이터를 입력할 수 있도록 한 후에, for문 내에서 self.condition_list에 데이터를 입력하도록 하면 되는 것이다.
## 조건검색식 데이터를 입력할 변수 설정
self.condition_list = {'index':[], 'name':[]}
## 이벤트 처리하기
self.kiwoom.OnReceiveConditionVer.connect(self.OnReceiveConditionVer)
## OnRecieveConditionVer 처리하기
## GetConditionNameList() 함수 실행하기
def OnReceiveConditionVer():
condition_list = self.kiwoom.dynamicCall("GetConditionNameList()").split(";")
for data in temporary_condition_list:
try:
a = data.split("^")
self.condition_list['index'].append(str(a[0]))
self.condition_list['name'].append(str(a[1]))
except IndexError:
pass
## GetConditionLoad 함수 실행하기
def _getconditionload():
self.kiwoom.dynamicCall("GetConditionLoad()")
위와 같은 절차를 거친 후 self.condition_list 변수를 확인해보면 {'index':['인덱스번호', '인덱스번호', '인덱스번호', 'name':['조건검색식명', '조건검색식명', '조건검색식명']}과 같은 형태로 출력될 것이다. 이제 우리는 이 인덱스번호와 조건검색식명을 아래의 SendCondition() 함수의 인자로 전달함으로써 해당 조건검색식이 찾은 종목코드들을 조회할 수 있다.
조건검색식 조회 ③ SendCondition()
SendCondition() 의 경우에는 화면번호, 조건검색식명, 인덱스번호, 실시간조회여부라는 네 개의 변수를 인자로 전달받으며 결과값으로 조회요청 성공 여부를 반환하며 OnReceiveTrCondition이라는 이벤트를 발생시킨다.
어렵게 생각할 것 없이, 아래와 같이 이해하면 된다.
SendCondition('0156', '조건검색식명', '인덱스번호', '0')
▼
① 결과값이 1인 경우 조회요청 성공, 아니면 실패
② OnReceiveTrCondition 이벤트 발생
여기서 조건검색식명과 인덱스 번호는 앞서 self.condition_list 변수 내에 입력해두었으니 본인이 원하는 조건검색식명과 인덱스 번호를 전달해주면 된다. SendCondition 함수는 아래의 코드에서 10번째 줄부터 확인하면 된다.
12번째 줄을 보면 결과 데이터는 OnReceiveTrCondition 또는 OnReceiveRealCondition으로 반환된다는 내용이 있는데, SendCondition 함수의 맨 마지막 자리에 있는 인자에 0을 입력하면 단순 조회이기 때문에 OnReceiveTrCondition 이벤트가 발생하지만 1을 입력하게 되면 실시간 조회이기 때문에 OnReceiveRealCondition 이벤트가 발생하게 된다.
※ 이벤트라는 이야기가 나와서 말인데, 이 역시 이벤트 처리를 해주어야 한다.
## 조건검색식 데이터를 입력할 변수 설정
self.condition_list = {'index':[], 'name':[]}
## 이벤트 처리하기
self.kiwoom.OnReceiveConditionVer.connect(self.OnReceiveConditionVer)
## SendCondition() 함수 실행하기
def _sendcondition(scr_no, con_name, con_index, int):
result = self.kiwoom.dynamicCall("SendCondition(QString, QString, int, int)", scrno, con_name, con_index, int)
## 요청 이후의 결과 데이터는 OnReceiveTrCondition 또는 OnReceiveRealCondition으로 반환받음
if result == 1:
print("[조건검색] 조회요청 성공")
if result != 1:
print("[조건검색] 조회요청 실패")
## OnRecieveConditionVer 처리하기
## GetConditionNameList() 함수 실행하기
def OnReceiveConditionVer():
condition_list = self.kiwoom.dynamicCall("GetConditionNameList()").split(";")
for data in temporary_condition_list:
try:
a = data.split("^")
self.condition_list['index'].append(str(a[0]))
self.condition_list['name'].append(str(a[1]))
except IndexError:
pass
## GetConditionLoad 함수 실행하기
def _getconditionload():
self.kiwoom.dynamicCall("GetConditionLoad()")
조건검색식 조회 ④ OnReceiveTrCondition
앞서 언급했듯 이 역시 하나의 이벤트에 해당하므로 이벤트로 처리해주어야 한다. 그리고 OnRecieveTrCondition 이벤트의 경우에는 화면번호와 종목코드, 조건검색식명, 인덱스 번호 등의 데이터를 전달해주게 되는데 우리는 여기서 앞에 있는 종목코드 리스트만 사용하면 된다.
## 조건검색식 데이터를 입력할 변수 설정
self.condition_list = {'index':[], 'name':[]}
## 이벤트 처리하기
self.kiwoom.OnReceiveConditionVer.connect(self.OnReceiveConditionVer)
self.kiwoom.OnReceiveTrCondition.connect(self.OnReceiveTrCondition)
self.kiwoom.OnReceiveRealCondition.connect(self.OnReceiveRealCondition)
## OnRecieveTrCondition 이벤트 처리하기
def OnReceiveTrCondition(scrno, codelist, con_name, con_index, next):
## codelist 안에 해당 조건검색식이 찾아낸 종목코드가 담겨 있다.
print(codelist)
## SendCondition() 함수 실행하기
def _sendcondition(scr_no, con_name, con_index, int):
result = self.kiwoom.dynamicCall("SendCondition(QString, QString, int, int)", scrno, con_name, con_index, int)
## 요청 이후의 결과 데이터는 OnReceiveTrCondition 또는 OnReceiveRealCondition으로 반환받음
if result == 1:
print("[조건검색] 조회요청 성공")
if result != 1:
print("[조건검색] 조회요청 실패")
## OnRecieveConditionVer 처리하기
## GetConditionNameList() 함수 실행하기
def OnReceiveConditionVer():
condition_list = self.kiwoom.dynamicCall("GetConditionNameList()").split(";")
for data in temporary_condition_list:
try:
a = data.split("^")
self.condition_list['index'].append(str(a[0]))
self.condition_list['name'].append(str(a[1]))
except IndexError:
pass
## GetConditionLoad 함수 실행하기
def _getconditionload():
self.kiwoom.dynamicCall("GetConditionLoad()")
14번째 줄에서 print(codelist)라고 적어놨는데, 해당 부분의 결과값을 확인하면 아래와 같다. 앞서 확인했던 까뮤이앤씨와 세종메디칼의 종목코드에 해당하는 데이터들이다.
['013700;258830;']
그렇다면 이제 이 데이터를 하나의 변수에 입력해주면 된다. 여기서는 self.code_list 라는 변수 안에 종목코드 데이터가 담긴 codelist 변수를 입력해주었다.
# OnRecieveTrCondition 이벤트 처리하기
def OnReceiveTrCondition(scrno, codelist, con_name, con_index, next):
self.code_list = []
self.code_list.append(codelist)
이제 다음 게시글에서는 self.code_list 라는 변수를 이용해서 관심종목에 등록하는 방법에 대해 알아볼 예정이다.
'PYTHON > Kiwoom Open API' 카테고리의 다른 글
키움증권 Open API - 거래 내역 조회하기 (1) (0) | 2022.04.06 |
---|---|
키움증권 Open API - 관심종목 관리하기 (3) (0) | 2022.04.02 |
키움증권 Open API - 관심종목 관리하기 (1) (2) | 2022.03.12 |
opt10170 : 당일매매일지 요청 (0) | 2022.02.20 |
opt90002 : 테마구성종목 요청 (0) | 2022.02.20 |
소중한 공감 감사합니다