맨땅에 헤딩하는 사람

키움증권 Open API+ 구현 상 issue 해결 | python 본문

퀀트/구현

키움증권 Open API+ 구현 상 issue 해결 | python

purplechip 2020. 10. 24. 23:34

일봉 데이터를 DB화하는 과정을 구현하며 여러 issue를 겪었다. 키움증권 Open API+는 사용 메뉴얼이 있지만 반환 데이터나, 제약사항에 대한 자세한 내용은 기술되어 있지 않다. 이러한 문제들은 키움 Open API+ 고객문의 게시판에서 질의를 통해 해결해야 한다. 나 역시 고객 문의 게시판과 사용 메뉴얼을 참고해가며 당면한 여러 issue를 해결하였고 이 글에서는 그 과정들을 게시하겠다.

 

1. 조회데이터 부호 

가끔씩 몇몇 데이터를 수신받으면 '--4500' 혹은 '+-4500'와 같은 꼴을 가진다. 이는 키움 HTS나 MTS에서 매수/매도 여부와 직전대비 증감 여부를 동시에 표현하기 위해 사용하는 부호 방법이다. 과 고객문의 게시판에서 종종 이런 질문들이 올라오며 이에 대한 답은 다음과 같다.

해당 부호의 의미는 첫번째 부호가 색상(빨강/파랑)표시이고, 두번째 부호는 등락을 의미합니다.
가령 +-4000 이면 해당데이터를 화면상 빨강색으로 표시하라는 의미이고 전일/전틱 대비 하락 이라는 의미 입니다.
이러한 부호값은 영웅문4 HTS, 영웅문S MTS 등의 매체들에서 사용되고 있는 값이며
OpenAPI 역시 동일한 포맷의 데이터를 수신하고 가공없이 전달하는 것을 원칙으로 하기에 그대로 전달되고 있습니다.
불필요한 경우 Trim 하거나 Left, Right 등의 문자열 편집함수로 짤라내어 사용하셔도 되겠습니다.

개발단계에서 사용하시는 TR의 데이터들을 영웅문4 HTS 와 비교/검증 하며 진행하시기 바랍니다.

이는 요청 OPT에 따라 조금씩 다른 의미를 가진다. 일봉같은 가격의 경우 음수 값이 없으므로 아예 Trim 하는 것도 좋은 방법이지만 기관투자자별 거래량의 경우 음수가 의미를 가지므로 부호를 잘 살려주어야 한다. 통상적으로 거래량은 빨간색이 매수, 파란색이 매도를 의미하므로 첫 번째 부호에 따라 값을 결정하면 된다.  그 외 다른 OPT에 데이터를 수신받을 때는 TR 데이터를 영웅문4 HTS와 비교하거나 키움증권 Open API+ 고객문의 게시판을 이용하는 수 밖에 없겠다.

 

2. Zip Error 14

multiprocessing을 사용하다보니 다음과 같은 에러를 발견하였다.

[그림 1] multiprocessing 사용 시 에러

이에 대해 역시 고객문의 게시판에 문의한 결과 OPT 계열의 동일한 TR 서비스를 여러 프로세스가 반복적으로 요청할 경우 해당 오류가 발생할 가능성이 높다는 답변을 얻었다. multiprocessing을 사용해서 일봉, 거래량 데이터를 업데이트 하던 방식은 각각의 프로세스가 여러 기업 코드를 할당받아 일봉, 거래량 데이터를 한번에 계산하는 방식이라 에러가 발생한 것이다. 이에 따라 DB 업데이트를 위해서는 프로세스를 최대 2개밖에 사용하지 못하는 제약이 생김을 알게 되었다. (일봉, 기관투자자별 거래량 OPT이므로 2개)

 

3. 최적화

(1) Pandas 최적화

아래 링크에서와 같이 vectorization, apply 함수 사용해서 DataFrame 최적화, DB 반영해주었다.

2020/08/25 - [파이썬/이론] - [Python] pandas DataFrame 최적화 (삽입, 생성, 반복, 문자열)

 

(2) GetCommDataEx 사용

메뉴얼을 보면 TR 조회 요청에 대해 데이터를 얻는 함수가 두 가지가 있다. GetCommData 와 GetCommDataEx 인데 후자의 함수는 차트 데이터를 대량으로 받는 경우만 사용이 가능하다. GetCommData가 따로 원하는 속성의 데이터를 함수의 parameter로 받아 그에 해당하는 값을 리턴한다면, GetCommDataEx는 한번에 모든 속성, 모든 Row에 대한 값을 리턴한다. 코드로 보면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def _get_comm_data(self, tr_code, rq_name, idx, item):
    data = self.GetCommData(tr_code, rq_name, idx, item)
    return data.strip()
 
 
def _get_comm_data_ex(self, tr_code, rq_name):
    data = self.GetCommDataEx(tr_code, rq_name)
    return data
 
 
# GetCommData 사용
data = []
data_cnt = self._get_repeat_cnt(tr_code, rq_name)
    for i in range(data_cnt):
        date = self._get_comm_data(tr_code, rq_name, i, "일자")
        fore = self._get_comm_data(tr_code, rq_name, i, "외국인투자자")
        inst = self._get_comm_data(tr_code, rq_name, i, "기관계")
        indi = self._get_comm_data(tr_code, rq_name, i, "개인투자자")
        temp = [date, '1''2''3', indi, fore, inst]
        data.append(temp)
 
 
# GetCommDataEx 사용
data = self._get_comm_data_ex(tr_code, rq_name)
cs

보면 코드도 간단해질 뿐 아니라 속도도 월등하게 빠르다. 내 경우 삼성전자 모든 일봉 데이터 기준, 약 11,000 튜플 기준 5초 → 3.5초로 시간 단축을 할 수 있었다. (물론 TR 조회 대기 시간까지 고려된 것이다.)

 

최종적으로 초기 최적화 전 15.99초에서 5.76초로 단축되었다. 최적화의 힘을 다시 느낀다.

 

 

 

 

Comments