목 차
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
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이다. 소수 둘째자리까지 유효하다. 정수형으로 변환하면 소수가 버림이 되는 현상이 발생하여 숫자에 왜곡이 생긴다.
2) OpenAPI-W에 로그인 하는 방법
자동매매의 로그인은 예전에 설명하였다. (https://springcoming.tistory.com/203)
로그인 하는 방법은 위 링크를 참고하면 된다. < 그림2 >에 opc10002 코드를 추가하면서 설명할 것이다. 로그인 관련 정보는 최소화할 예정이다. 로그인 방법은 반드시 숙지하자.
3. 코드 설명
아래의 < 그림3 >은 < 그림2 >에서 13줄, 27줄~39줄 및 45줄의 코드를 추가하였다.
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, ②)한다.
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로 연결)
※ 이 형태(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(절대값)을 붙여줘서 양수로 만들자.
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(예수금및증거금현황조회)를 통해 주문가능금액을 구해보자.
'2. 해외선물 > 2-1. 해외선물 자동매매 연구' 카테고리의 다른 글
(키움증권 해외선물 자동매매 파이썬) 13. 주문하기(SendOrder) (13) | 2023.10.06 |
---|---|
(키움증권 해외선물 자동매매 파이썬) 12. 주문가능수량 조회 (opw30011) (4) | 2023.10.05 |
(키움증권 해외선물 자동매매 파이썬) 11. 주문가능금액 조회 (opw30009) (4) | 2023.09.30 |
(키움증권 해외선물 자동매매 파이썬) 10. 매도수구분, 진입가격, 청산가격, 평가손익 알아보기(opw30012) (0) | 2023.09.29 |
(키움증권 해외선물 자동매매 파이썬) 8. tr 동작원리 (2) | 2023.09.27 |
(키움증권 해외선물 자동매매 파이썬) 7. 클래스의 변수화(인스턴스) (0) | 2023.09.15 |
(키움증권 해외선물 자동매매 파이썬) 6. self의 활용 (self.kiwoom) (0) | 2023.09.08 |
(키움증권 해외선물 자동매매 파이썬) 5. 자동매매 로그인하기 (0) | 2023.09.07 |