안녕하세요?


지난번 포스팅에서 한번 주식 종목의 코드랑 종목의 이름을 가지고 오는 것을 PyCharm에서 실습해 보았는데, 이것에만 만족하지 말고, 이번에는 키움증권의 Open API를 이용해서 제대로 주식의 일봉 데이터를 가지고 오는 것에 대해서 포스팅을 해 보고자 합니다.



지난번과 코드 자체는 크게 다를 것이 없어 보이기는 합니다만, 먼저 import time이라고 해서 시간관련 모듈을 가지고 오기로 하고, 다음으로는 TR_REQ_TIME_INTERVAL 이라는 변수를 주어서, 나중에 데이터를 요청하는데, 키움증권에서는 서버에 1초에 5번의 요청만을 허용하기 때문에, 이를 위한 변수입니다.



다음으로 _set_signal_slots(self): 라는 메소드에 한줄을 추가하는데, 여기서는 OnReceiveTrData라고 해서, 서버에 특정한 형식(TR)로 요청한 데이터가 그 특정한 형식(TR)로 들어왔을때, _receive_tr_data()라는 메소드를 실행 시키기 위한 코드입니다.



다음으로는 def set_input_value(self, id, value):라는 메소드인데, 이 메소드는 키움증권 Open API에서 제공하는 SetInputValue(아이템명, 입력값)의 메소드를 사용하기 위한 것 입니다. 그리고 이 메소드는 바로 TR이라고 해서 서버와 통신하기 위한 형식을 만드는 명령이라고 보시면 됩니다. 즉, 무엇을 요청할 것인지 형식에 맞춰서 만든다고 보시면 됩니다.




다음으로 오는 def comm_rq_data(): 라는 메소드도 키움증권 Open API에서 제공하는 CommRqData()메소드를 사용하기 위한 메소드인데, 이 메소드의 역할은 서버로 송신을 하는 역할을 합니다. 한마디로 위에서 입력값을 만들었다고 끝이 아니라 서버에 보내야 하는데, 바로 보내는 역할을 하는 것 입니다.


그리고 여기에서도 당연하다면 당연하게 GUI로 프로그래밍이 되지 않았기 때문에, 이벤트 루프를 만들어 주어서 계속 실행시키는 행동을 하게 되는 것 입니다.


그리고 아래에 있는 def _comm_get_data(): 라는 메소드는 바로 서버에 데이터를 요청하는 송신을 했으니, 이제 데이터를 받아와야 하는 단계인 것 입니다. 여기서 사용되는 키움증권의 메소드는 바로 CommGetData()라는 메소드이며, 여기서 자체의 메소드는 공백으로 서로 띄워져 있기 때문에, 이를 위해서는 strip()이라고 입력 하기만 하면 됩니다.



다음으로는 얼마나 많은 데이터를 가지고 왔는지 알아봐야 하기 때문에, 위에서 처럼 갯수를 세는 메소드인데, 이렇게 하는 이유는 바로 얼마나 많은 데이터가 들어왔는지 알고 있어야 while이나 for문으로 데이터를 읽을 수 있기 때문입니다.



다음으로는 데이터가 도착했을 때, 이를 처리하기 위한 메소드입니다. 이 메소드는 그냥 차례대로 실행이 되는 것이 아니고, OnReceiveTrData라는 이벤트가 발생 했을 때 실행이 됩니다. 여기서 먼저 if next == '2': 라는 조건문이 있는데, 이게 있는 이유는 먼저 바로 연속조회에 대한 고려를 하기 위해서 입니다.


1번의 요청으로 모든 데이터를 다 받고 싶겠지만, 듣자니 TR 1번에 900개의 데이터만 오기 때문에 다시 요청을 보내야 한다고 합니다. 그래서 이런 경우에는 OnReceiveTrData이벤트에서 PrevNext라는 인자의 값이 2라고 나오게 됩니다. 이걸 여기서는 간단하게 next라고 대입을 해서, 그냥 문자열 2인 경우에는 남아 있는 데이터가 있다는 것을 인식하게 만들기 위한 장치입니다.


다음은 TR의 구분인데, 여기서는 일봉데이터를 요청한 것 때문에 TR의 코드가 OPT10081_req가 됩니다. 이렇게 하는 이유는 TR을 요청해서 받은 데이터가 요청한 데이터가 맞는지 확인하기 위한 코드로서, 제대로 정보를 받은 것이 맞는지를 확인하기 위한 장치입니다.


마지막으로는 이벤트 루프에 대한 처리입니다. 이미 데이터를 받았기 때문에, 이제 위에서 만든 def comm_rq_data(): 라는 메소드가 계속해서 실행되면서 대기를 하고 있을 필요가 없는 것 입니다. 그래서 exit()메소드를 지정해 주어서 이벤트 루프를 정지 시키도록 합니다.


여기서 짚고 넘어가야 하는 것이 하나 있는데, try:문은 아래에 있는 실행문을 실행을 하는데, 만약에 except 뒤에 있는 예외가 생겼을 경우에는 예외처리를 하라는 의미가 됩니다. 여기서는 그냥 간단하게 이벤트 루프를 정지하고, 만약에 AttributeError가 생겨도 그냥 넘어가라 라는 의미가 됩니다.



다음은 바로 지정한 대로 _opt10081()의 메소드가 실행이 되는데, 원래 키움증권의 Open API에서 제공하는 일봉 데이터의 내용에는 [종목코드, 현재가, 거래량, 거래대금, 일자, 시가, 고가, 저가, 수정주가 구분, 수정 비율, 대업종 구분, 소업종 구분, 종목정보, 수정 주가 이벤트, 전일종가]를 한꺼번에 제공합니다.


이 모든 데이터가 다 필요한 것이 아니기 때문에, 여기서는 먼저 for문을 통해서 일자, 시가, 고가, 저가, 현재가, 거래량을 가기고 오도록 하기 위해서 이렇게 for문을 사용한 것 입니다. 그런데 제가 한가지 드는 의문이, 현재가라는 것이 바로 종가를 의미하는 것이 아닌가 하는 생각이 듭니다.




여기서  # opt10081 TR 요청이라는 아래에 있는 내용은 ㅊ퍼음에 보내는 TR 요청의 내용인데, 뒤에 오는 while문의 의미는 간단합니다. 바로 remained_data가 있다=남아있는 데이터가 있다=다시 동일하게 요청을 보내라는 것 입니다. 그리고 가만히 보면 여기서 time.sleep()이라는 함수가 있는데, 키움증권의 서버가 1초에 5번을 초과하는 요청은 차단하기 때문에, 그 간격을 맞춰 주기 위한 것 입니다.



참고로 여기서 TR의 목록은 어떻게 확인이 가능한가 하면, 위에서 나와 있는 것처럼, KOA studio에서 확인을 할 수 있다고 합니다. 일단 제 경우에는 필요한 값이 나오기는 나왔는데, 기관과 외국인의 순매수량은 어떻게 해야 하는 것인지 아직 감이 안 잡힙니다.



마지막으로 대량의 데이터를 얻어 오는 데 성공한 것을 볼 수 있습니다. 이렇게 하는 것으로 좀 어려운 과정을 거치기는 했지만, 증권사의 서버로 부터 주식 데이터의 하나인 일봉 데이터를 얻어 오는데는 성공을 했는데, 문제는 아직 데이터 베이스에 저장을 하지 않아서, 그냥 허공으로 날라가 버린다는 것 입니다. 그래서 다음 포스팅에서는 이를 데이터베이스에 저장하는 방법을 실습해 본 다음, 관련된 내용을 포스팅 해 보고자 합니다.

  1. ddd 2020.10.24 19:36

    저 혹시 remained_data가 kiwoom instance에 없다고 나오는 attirbute error가 발생해서 질문 드려요 ㅠ 혹시 해결 방법을 아시는지..

    • ddd 2020.10.25 19:06

      어.. 해결했습니다. while문 위에

      kiwoom.set_input_value("종목코드", "039490")
      kiwoom.set_input_value("기준일자", "20170224")
      kiwoom.set_input_value("수정주가구분", "1")
      kiwoom.comm_rq_data("opt10081_req", "opt10081", 0, "0101")

      이 구문이 없으니 에러가 나는데, 아마 remained_data가 실제로 데이터가 남지 않았기에 생겨난 에러 같았습니다. 질 좋은 자료 감사합니다!

    • 안녕하세요?

      제가 일이 있어서 신경을 쓰지 못한 사이에 벌써 해결까지 다 해놓으셨군요. 일이 많아서 신경써 드리지 못한 점 죄송합니다.

+ Recent posts