2. 해외선물/2-5. 해외선물 API (기타)

(키움증권 해외선물 OpenAPI-W) 상품별명세및요약조회(opw50004)

봄이오네 2023. 2. 3. 08:04
반응형

 

1. 들어가며

이전 글에서는 거래소에 등록된 해외선물 종목의 위탁증거금과 유지증거금을 알아보았다.

사실 필자가 알고싶은건 틱단위, 틱가치, 위탁증거금, 유지증거금 4가지였다.

WKOA Studio에서 이것저것 클릭하다보니... 우연히(?) 발견하였다. 영웅문G에서는 화면번호는 0771이고, WKOA Studio에서는 opw50004에서 상품별 틱가치 등을 확인할 수 있다.

 

이번 글에서는 영웅문G에서 거래가능한 해외선물의 지수, 통화, 금리 등의 틱단위, 틱가치, 증거금 등을 받아오는 방법에 대해 알아보자.

 

아래 첨부파일은 4번(전체코드)를 실행했을 때 받을 수 있는 엑셀 파일이다.

tik_margin_data.xlsx
0.01MB

 

 

그림1-1. 영웅문G의 화면번호 0771에서 해외선옵 상품명세요약 화면

 

그림1-2. opw50004를 통해 받아온 데이터 화면

 

2. 사전 설명

WKOA Studio에서 입력과 출력된 내용을 확인할 수 있다. 입력해야될 내용은 의외로... 없다. WKOA Studio에 접속/로그인하고 나서, opw50004를 클릭하고 "조회"를 누르면, 그림2의 내용이 출력(output)된다.

 

품목구분은 6가지(지수, 통화, 금속, 에너지, 농축산물, 금리)이다. 다만, 코드에서 for문을 통해 데이터를 수신받을 때는 지수(IDX), 통화(CUR), 금속(MTL) 등을 순차적으로 넣어서 for문을 돌린다.

 

그림2. WKOA Studio의 opw50004(상품별명세및요약조회)에서 틱단위, 틱가치 등을 확인할 수 있다.

 

3. 코드 설명

임포트한 모듈 및 로그인 등 이전 글들에서 언급한 내용은 지면이 길어지는 관계로 여기에서는 생략한다.

그림3-1. 필요모듈 및 로그인 관련 내용

 

1줄~33줄 : 임포트한 모듈 및 로그인 관련 내용에 대한 설명이며, 내용 중복이므로 여기에서는 설명을 생략한다.

22줄 : 거래소에서 받고싶은 품목(지수, 통화, 금속 등)의 모음이며, 75줄의 for문에서 하나씩 추출해서 키움서버에 틱단위, 틱가치, 증거금 등을 요청/수신받는다.

23줄 : 60줄~70줄을 통해 받아온 데이터를 23줄의 self.tik_margin_situation에 넣는다.

 

그림3-2. 입력/요청/수신받는 데이터 내역

 

35줄~39줄 : 키움서버에 데이터를 입력/요청하는 내용이다.

44줄~58줄 : 키움서버에서 데이터를 수신받는다.

60줄~70줄 : 44줄~58줄에서 받아온 데이터를 23줄의 self.tik_margin_situation의 딕셔너리에 넣는다.

 

그림3-3. 데이터를 수신받아 엑셀파일에 저장하는 화면

 

75줄 : 22줄의 self.tik_margin_sort에 들어있는 품목들을 for문을 통해,

78줄 : "for문의 품목, FU(선물), 빈칸"을 넣어 35줄의 rq_data_opw50004함수를 실행한다.

80줄 : 23줄의 self.tik_margin_situation을 엑셀에 넣기 위해 판다스 모듈을 이용하여 DataFrame 형태로 만든다.

83줄~90줄 : 83줄의 경로에 "tik_margin_data.xlsx" 파일이 있으면 85줄 실행, 없으면 89줄 실행

96줄 : 74줄 tik_margin_start 함수를 실행한다.

 

4. 전체 코드

 

더보기
import sys
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import pandas as pd
import os
import time

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

        self.kiwoom.OnEventConnect.connect(self.login_Connect)
        self.kiwoom.OnReceiveTrData.connect(self.trdata_get)

        self.kiwoom.dynamicCall("CommConnect(1)")  # CommConnect() : 괄호 안에 자동(1)을 넣는다.
        self.login_event_loop = QEventLoop()  # from PyQt5.QtCore import * : qtcore가 임포트되어야 함
        self.login_event_loop.exec_()

        ##### 위탁증거금, 유지증거금 관련 #####
        self.tik_margin_sort = ['IDX', 'CUR', 'MTL', 'ENG', 'CMD', 'OPT', 'INT']   #  IDX:지수, CUR:통화, MTL:금속, ENG:에너지, CMD:농축산물, OPT:해외옵션, INT:금리
        self.tik_margin_situation = {'gubun' : [], 'form_code' : [], 'form_name' : [], 'market_code' : [], 'currency_code' : [],
                                     'trading_start_time' : [], 'trading_end_time':[], 'tik_unit':[], 'tik_value':[], 'customer_margin' : [], 'maintenance_margin' : []}

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

    ########## 키움서버에 TR 요청하는 함수 모음 ##########
    def rq_data_opw50004(self, form_gubun_1, futures_gubun_2, form_codes_3):
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "품목구분", form_gubun_1)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "해외파생구분", futures_gubun_2)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "파생품목코드", form_codes_3)
        self.kiwoom.dynamicCall("CommRqData(QString, QString, QString, QString)", "opw_50004", "opw50004", "", "5004")
        self.tr_event_loop = QEventLoop()
        self.tr_event_loop.exec_()

    def trdata_get(self, scrno, rqname, trcode, recordname, prenext):
        if rqname == "opw_50004":
            getrepeatcnt = self.kiwoom.dynamicCall("GetRepeatCnt(QString,QString)", trcode, recordname)
            print(getrepeatcnt)

            for j in range(getrepeatcnt):
                form_code1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_50004", "opc50004", j, "파생품목코드").strip()
                market_code1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_50004", "opc50004", j, "해외거래소코드").strip()
                form_name1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_50004", "opc50004", j, "파생품목명").strip()
                currency_code1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_20004", "opc20004", j, "통화코드").strip()
                trading_start_time1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_50004", "opc50004", j, "파생시장시작시각").strip()
                trading_end_time1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_50004", "opc50004", j, "파생시장종료시각").strip()
                tik_unit1 = float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_50004", "opc50004", j, "틱단위수").strip())
                tik_value1 = float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_50004", "opc50004", j, "틱가치").strip())/1000
                customer_margin1 = int(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_50004", "opc50004", j, "위탁증거금").strip())/100
                maintenance_margin1 = int(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_50004", "opc50004", j, "유지증거금").strip())/100

                self.tik_margin_situation['gubun'].append(self.tik_margin_sort)
                self.tik_margin_situation['form_code'].append(form_code1)
                self.tik_margin_situation['market_code'].append(market_code1)
                self.tik_margin_situation['form_name'].append(form_name1)
                self.tik_margin_situation['currency_code'].append(currency_code1)
                self.tik_margin_situation['trading_start_time'].append(trading_start_time1)
                self.tik_margin_situation['trading_end_time'].append(trading_end_time1)
                self.tik_margin_situation['tik_unit'].append(tik_unit1)
                self.tik_margin_situation['tik_value'].append(tik_value1)
                self.tik_margin_situation['customer_margin'].append(customer_margin1)
                self.tik_margin_situation['maintenance_margin'].append(maintenance_margin1)

            self.tr_event_loop.exit()

    def tik_margin_start(self):
        for i in self.tik_margin_sort:
            time.sleep(1)
            self.tik_margin_sort = i
            btl.rq_data_opw50004(i, "FU", "")

        df1 = pd.DataFrame(self.tik_margin_situation, columns=['gubun', 'form_code', 'form_name', 'market_code', 'currency_code', 'trading_start_time', 'trading_end_time', 'tik_unit', 'tik_value', 'customer_margin', 'maintenance_margin'])
        print(df1)

        dir = r'C:\Users\User\Desktop\tik_margin_data.xlsx'  # 경로 설정

        if os.path.exists(dir):
            with pd.ExcelWriter(dir, mode='a', engine='openpyxl', if_sheet_exists='overlay') as writer:
                df1.to_excel(writer, header=False, index=False, sheet_name='sheet1', startrow=writer.sheets['sheet1'].max_row)
        else:
            with pd.ExcelWriter(dir, mode='w', engine='openpyxl') as writer:
                df1.to_excel(writer, index=False, sheet_name='sheet1')

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

    btl.tik_margin_start()

    app.exec_()

 


5. 마치며

거래를 하는 동안 몇번 사용할거 같지는 않다. 다만, 거래소 및 종목을 선택을 해야하는 경우, 틱단위/틱가치/증거금 등 투자자 본인의 투자금을 고려할 때 필요할 것으로 보인다.

 

필자도 의외로 나스닥이나 천연가스 등에 지나치게 몰입되어 있었던 것 같다.

증거금 등은 시장상황에 따라 얼마든지 변경될 수 있으니, 필요할 때마다 한번씩 실행해주어서 증거금 등을 체크하자.

 

 

반응형