2. 해외선물/2-1. 해외선물 자동매매 연구

(키움증권 해외선물 자동매매 파이썬) 9. 1분봉 데이터 받기(opc10002)

봄이오네 2023. 9. 28. 08:10
반응형
목 차
1. 들어가며
2. 사전설명
   1) WKOAStudio에서 1분봉 데이터 받는 방법
   2) OpenAPI-W에 로그인 하는 방법
3. 코드 설명
4. 전체코드
5. 마치며

 

1. 들어가며

지난 글에서는 tr 동작 원리에 대해 알아보았다. tr을 통해 데이터를 받아오는 구조는 데이터 입력(SetInputValue) - 데이터 요청(CommRqData) - 연결(OnReceiveTrData) - 데이터 수신(GetCommData)의 4단계이다. 데이터를 받아오는 상호작용(trans-action)의 구조로 생각하면 된다.

 

이번 글에서는 opc10002(해외선물옵션 분차트조회)를 통해 1분봉의 데이터(시가, 고가, 저가, 종가, 거래량 등)을 받아오는 방법을 알아볼 것이다.

 

이제부터는 1분봉 데이터 받기(opc10002), 미체결정보(opw30002) 등의 단편적인 정보가 아닌, 한 파일에 코드를 작성하도록 할 것이다. 글에서 추가된 부분은 별도로 표기를 해둘 것이다. 기존 내용의 이해가 선행되어야, 추가되는 코드를 이해할 수 있을 것으로 생각된다. 인내심을 가지고 이해하려고 노력하자! ^^

 

※ 키움증권 OpenAPI-W를 이용하여 시세정보(시가, 고가 등)를 받아오려면, 시세정보 이용료(월 $185)를 지불하여야 한다. 바꾸어 이야기하면, 시세 이용료를 지불하지 않으면 시세정보를 받아올 수 없다. 이용료 신청 방법은 아래 링크에서 참고하자.

 

※ 시세정보 이용료 지불방법 : https://springcoming.tistory.com/140

 

(키움증권 해외선물 OpenAPI-W) 해외선물 시세조회 이용료 결재 및 미결재시 출력 메시지

목 차 1. 들어가며 2. 시세조회 이용료 관련 설명 1) 미접속 상태에서 종목정보조회(opt10001)를 조회한 경우 2) 시세조회 이용료를 결재하지 아니한 경우 출력메시지 3. 시세조회 이용료 결재 경로 1)

springcoming.tistory.com


2. 사전설명

필자가 추구하는 시스템은 1분봉 데이터(OHLCV)로 패턴을 만들어서 long/short으로 진입하는 시스템을 생각하고 있다. 필요한 것은 1분봉 데이터이다.

 

1) WKOAStudio에서 1분봉 데이터 받는 방법

1분봉 데이터 받아오는 방법은 예전에 한번 설명한 적이 있다. (https://springcoming.tistory.com/144)

위 링크는 opt10001(종목정보조회)로 1분봉 데이터를 조회하는 내용인데, 받아오는 내용(output)이 복잡한것 같아서 opc10002(해외선물옵션 분차트조회)을 통해 데이터를 받아오고자 한다. (opt10001을 이용해도 분봉 데이터는 받아올 수 있다)

 

아래 < 그림1 >은 지난 글에서 WKOAStudio를 사용하여 데이터를 받아온 내용이다. 화면 중앙의 ③번 부분을 주목하자.

첫번째, 받아오는 데이터 시간순을 확인하자. 데이터의 정렬 순서는 최신 → 과거로 출력되는 것을 알 수 있다.

 

[0] [opc10002 현재가 = 14764.000000]

[0] [opc10002 거래량 = 204]

[0] [opc10002 체결시간 = 20230927014400]

[0] [opc10002 시가 = 14766.75]

...

[1] [opc10002 현재가 = 14766.25000000]

[1] [opc10002 거래량 = 1051]

[1] [opc10002 체결시간 = 20230927014300]

[1] [opc10002 시가 = 14769.950000]

 

두번째, < 그림1 >의 ③에서 확인할 수는 없지만, 키움증권에서 제공하는 데이터의 형태는 문자형(str)이다. 나중에 문자형을 실수형(float)로 바꾸어줄  것이다. (실수형으로 바꾸어 주어야, 더하거나 빼는 등 사칙연산을 할 수 있다)

 ※ 정수형이 아닌, 실수형으로 바꾸는 이유 : 나스닥은 틱 단위 0.25이다. 소수 둘째자리까지 유효하다. 정수형으로 변환하면 소수가 버림이 되는 현상이 발생하여 숫자에 왜곡이 생긴다.

 

그림1. opc10002의 TR을 이용하여 데이터를 받아온 내역

 

2) OpenAPI-W에 로그인 하는 방법

자동매매의 로그인은 예전에 설명하였다. (https://springcoming.tistory.com/203)

로그인 하는 방법은 위 링크를 참고하면 된다. < 그림2 >에 opc10002 코드를 추가하면서 설명할 것이다. 로그인 관련 정보는 최소화할 예정이다. 로그인 방법은 반드시 숙지하자.

 

그림2. OpenAPI-W에 로그인하는 방법


3. 코드 설명

아래의 < 그림3 >은 < 그림2 >에서 13줄, 27줄~39줄 및 45줄의 코드를 추가하였다.

 

그림3. opc10002를 통해 1분봉 데이터를 받아오는 내용

 

 

1줄~25줄 : 로그인 관련 정보이며, 여기서는 설명을 생략한다.

13줄 : 간단하게 생각하자. 27~32줄의 함수와 35줄~39줄의 함수를 OnRecevieTrData.connect를 통해 서로 연결한다. 여기서 연결한다는 의미는 데이터를 입력/요청하면 데이터를 수신받게 연결해준다는 의미이다.

27줄 : 45줄 함수에서 종목코드(NQZ23) 및 시간단위(1분)을 넣으면 실행되는 함수를 27줄에서 선언한다.

28줄~29줄 : 종목코드(NQZ23) 및 시간단위(1분)의 데이터를 키움증권 서버에 입력(SetInputValue)한다.

30줄 : 28줄~29줄의 데이터를 키움증권 서버에 요청(CommRqData)한다.

 

아래 < 접은 글 >은 SetInputValue 및 CommRqData의 활용 형태에 대해 설명하였다.

 

더보기

※ 여기서 잠깐! 데이터를 요청하는 방법에 대해 알아보자!
< 그림3 >에서 짤리긴 했지만, 28줄~29줄은 아래와 같다. (짤린 부분은 4번(전체코드)에서 확인 가능)

 

1) SetInputValue 1번째
28줄 : self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "종목코드", stock_code_num)
28줄을 하나씩 분석해보자.
① self.kiwoom은 8줄에서 이미 정의하였다. 사용자 pc에 설치된 키움api 레지스터리에 접근하라.(QAxWidget)
② dynamicCall : PyQt5에서 제공하는 함수로, 데이터를 키움서버에 송신/수신해주는 기능을 한다.
                            즉 dynamicCall 이하의 괄호() 안에 있는 내용을 서버에 보내준다는 의미이다.
③ QString         : 문자형(str)을 말한다. "종목코드"는 쌍 따옴표 안에 있으므로 문자형이며,
                             stock_code_num은 45줄에서 던져주는 "NQZ23", 즉 문자형을 말한다.

→ 28줄을 해석해보면, 사용자pc에 설치된 키움api 레지스터리를 통해 키움서버에 접속(①)하여
                                     문자형인 "종목코드"와 문자형인 stock_code_num(="NQZ23")를(③)
                                      키움서버에 입력(SetInputValue)하여 키움서버에 송신(dynamicCall, ②)한다.

 

2) SetInputValue 2번째
29줄 : self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "시간단위", time_unit)
 → 29줄을 해석해보면, 사용자pc에 설치된 키움api 레지스터리를 통해 키움서버에 접속(①)하여
                                      문자형인 "종목코드"와 문자형인 time_unit(="1")를(③)
                                      키움서버에 입력(SetInputValue)하여 키움서버에 송신(dynamicCall, ②)한다.

그림4-1. SetInputValue 활용 형태

 

3) CommRqData 내용
30줄 : self.kiwoom.dynamicCall("CommRqData(QString, QString, QString, QString)",
                                                                             "opc_10002", "opc10002", "", "1002")
 → 30줄을 해석해보면, 사용자pc에 설치된 키움api 레지스터리를 통해 키움서버에 접속(①)하여
                                      문자형인 4개 데이터 형태로 키움서버에 요청한다. (rqname, trcode, prenext, screenNo)
                                      rqname에 따라 36줄에서 출력하는 데이터를 확인하자. (OnReceiveTrData로 연결) 

그림4-2. CommRqData 활용 형태


※ 이 형태(28줄~30줄)는 많이 나온다. 낯설게 느껴지더라도, 구조를 이해했다면 자연스럽게 사용하도록 노력하자.

 

31줄~32줄 : 데이터 수신이 완료될 때까지, 다음코드 실행을 방지한다. 즉, 데이터를 다 받을 때까지 대기(loop)한다.

 

35줄 : 데이터 수신받는 함수를 정의한다.

36줄 : 30줄에서 키움서버에 요청한 내용의 rqname이 "opc_10002"이면,

37줄~38줄 : 1분전 시가 및 1분전 종가를 각각의 변수(self.open_price_ong_ago, self.close_price_one_ago)에 담는다.

 

더보기

※ 37줄의 문장을 분석해보자.

WKOAStudio에서 GetCommData는 4개 데이터(문자형, 문자형, 정수형, 문자형)의 데이터를 취한다.

 

37줄: self.open_price_one_ago=  abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)",

                                                                                                               "opc_10002", "opc10002", 1, "시가").strip()))

 

① self.open_price_one_ago : 1분전 시가를 임의로 정의한다.

② self.kiwoom : 키움증권 OpenAPI-W의 레지스터리에 접근하라.

③ dynamicCall() : 괄호 안의 내용을 키움서버에 요청한다.

④ GetCommData : < 그림4-3 >에서 확인하였듯이 4개 데이터(trcode, record_name, index, item_name)이며,

                                index는 정수형이며, 나머지 3개(trcode, record_name, item_name)는 문자형이다.

⑤ index는 1로 설정하였다. 0은 현재시간을 말하며, 1은 1분전, 2는 2분전을 말한다. 

⑥ 최초로 키움증권에서 데이터를 받아오면 문자형(str)이다. 실수형(float)으로 바꾸어준다.

⑦ 가끔씩 마이너스가 나온다. abs(절대값)을 붙여줘서 양수로 만들자.

그림4-3. GetCommData 활용 형태

 

 

39줄 : 데이터를 변수화 시키는 것이 완료 되었으면 대기(loop 도는 것)를 종료(exit)시킨다.

45줄 : 27줄의 rq_data_opc10002에 "NQZ23" 및 "1" 을 넣어서 실행하라.


4. 전체코드

전체코드는 아래와 같다.

 

더보기
import sys
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

class btl_system():
    def __init__(self):
        self.kiwoom = QAxWidget("KFOPENAPI.KFOpenAPICtrl.1")
        print("로그인 시작!")

        self.kiwoom.dynamicCall("CommConnect(1)")  # CommConnect() : 괄호 안에 자동(1)을 넣는다.
        self.kiwoom.OnEventConnect.connect(self.login_Connect)
        self.kiwoom.OnReceiveTrData.connect(self.trdata_get)

        self.login_event_loop = QEventLoop()
        self.login_event_loop.exec_()

        self.kiwoom.dynamicCall("GetCommonFunc(QString, QString)", "ShowAccountWindow", "")  # 계좌번호 입력창을 띄우는 내부함수

    def login_Connect(self, err_code):
        if err_code == 0:
            print('로그인 성공했습니다!')
        else:
            print('로그인 실패했습니다!')
        self.login_event_loop.exit()

    def rq_data_opc10002(self, stock_code_num, time_unit):  # 분봉 이미지 만들기
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "종목코드", stock_code_num)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "시간단위", time_unit)
        self.kiwoom.dynamicCall("CommRqData(QString, QString, QString, QString)", "opc_10002", "opc10002", "", "1002")
        self.tr_event_loop = QEventLoop()
        self.tr_event_loop.exec_()

    ########## OnReceiveTrData을 통해 수신받은 데이터 함수  ##########
    def trdata_get(self, scrno, rqname, trcode, recordname, prenext):
        if rqname == "opc_10002":
            self.open_price_one_ago = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", 1, "시가").strip()))
            self.close_price_one_ago = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", 1, "현재가").strip()))
            self.tr_event_loop.exit()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    btl = btl_system()

    btl.rq_data_opc10002("NQZ23", "1")

    app.exec_()

5. 마치며

이번 글에서는 1분전 데이터를 가져오는 방법을 알아보았다. 동 내용은 이전 글에서도 써서 크게 어렵지는 않을 것이다. 데이터 입력-요청-연결-수신의 4단계를 기억하여야 하며, 또한 데이터를 어떻게 입력/요청/수신하는 문장 구문도 익숙해지자.

 

다음 글에서는 opw30012(미결제내역 상세조회)을 통해 (진입 후) 평가금액, 진입가격, 현재가격 등을 알아보고, 그 다음 글에서는 opw30009(예수금및증거금현황조회)를 통해 주문가능금액을 구해보자.

 

반응형