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

(키움증권 해외선물 OpenAPI-W) 상품별증거금조회 (해선 모든 종목의 위탁증거금, 유지증거금) (opw20004)

봄이오네 2023. 1. 27. 23:15
반응형
목 차
1. 들어가며
2. 사전설명
3. 코드설명
4. 전체코드
5. 마치며

 

1. 들어가며

영웅문G에서 거래가능한 종목은 몇 가지일까?

거래소별로 몇 종목의 거래가 가능한지? 각각의 증거금은 어떻게 되는지?

필자가 지나치게 나스닥, S&P, 엔화, 파운드 등 4종목에만 몰입되어 있는건 아닌지 약간은 의심이 된다.

수익이 날 수 있는 종목을 꾸준히 관찰하고 수익내는 방법에 대한 고민이 부족하지 않았나?

 

먼저, 영웅문G에서 거래가능한 종목은 몇 종목이고, 각각의 증거금은 얼마일까?

그림1-1. 화면번호 0773에서 해외선물의 상품별증거금을 확인할 수 있다.

 

이 글에서는 위의 < 그림1-1 >에서처럼 해외선물의 상품별증거금을 키움증권에서 받아오는 방법을 알아본다.

< 그림1-2 >처럼 거래소별로 거래가능한 종목개수를 알아볼 예정이다.

그림1-2. 영웅문G에서 거래가능 종목개수

 

아래 링크의 종목별 위탁증거금과 유지증거금을 받아오는 것이 목표이다. (단위는 달러)

 

margin_data.xlsx
0.01MB

 

 


2. 사전설명

WKOA-Studio에서 데이터 요청 및 수신하는 방법을 알아보자.

① opw20004(상품별증거금조회)는 품목구분, 적용일자, 해외파생구분, 파생품목코드를 입력(input)하고, 파생품목코드, 품목명 등 6가지를 수신(output)받는다.

② SetInputValue 및 CommRqData 함수를 활용한다.

③ 품목구분은 IDX, 적용일자 20230127, 해외파생구분은 FU, 파생품목코드는 빈칸으로 설정한다.

④ 출력된 결과물이다.

그림2-1. 상품별증거금조회(opw20004)하는 화면

 

< 그림2-2 >는 키움서버에서 받은 종목별 위탁/유지증거금 내역이다.

그림2-2. 엑셀로 받아본 종목별 위탁증거금, 유지증거금 내역 ('23.1.27. 기준)


3. 코드설명

모듈의 임포트 및 로그인 정보 등 중복 정보의 설명은 생략한다. 2-2(해외선물 API) 카테고리를 참고하자.

 

그림3-1. 위탁증거금, 유지증거금 설정

 

1줄~32줄 : 필요모듈 및 로그인 정보에 관한 내용이다.

22줄 : 6개 분야를 설정한다.

IDX:지수, CUR:통화, MTL:금속, ENG:에너지, CMD:농축산물, INT:금리

23줄 : 73줄의 데이터프레임 형태를 만들기 위해, "구분"을 만들어준다.

24줄 : 조회날짜를 설정한다. 사용자는 "조회날짜"만 바꾸어주면 조회가 가능하다.

 

그림3-2. API를 통해 키움서버에 입력/요청/수신받는다.

 

36줄~39줄 : SetInputValue 함수를 이용하여, < 그림2 >의 input의 4가지 데이터를 키움서버에 입력한다.

40줄 : CommRqData 함수를 이용하여,36~39줄의 4가지 데이터를 키움증권 서버에 요청한다.

 

15줄 : 40줄의 CommRqData의 데이터가 키움증권에 요청(opw20004)되면, 15줄의 OnReceiveTrData를 통해 GetCommData 함수와 연결(connect)된다.

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

 

45줄 : 요청받은 rqname가 "opw_20004"이면

46줄 : 받아온 데이터의 총 개수를 카운팅(getrepeat)한다.

 

50줄~55줄 : 6가지 데이터를 받아온다. 위탁/유지증거금은 100으로 나누어야 화면번호 0773의 증거금으로 표기된다.

    * 6가지 수신데이터 : 파생품목코드, 품목명, 해외거래소코드, 통화코드, 위탁증거금, 유지증거금

 

57줄~63줄 : 23줄의 데이터프레임에 각각의 데이터를 추가(append)한다.

 

 

그림3-3. fora문을 활용하여, 품목별 증거금 받는 함수를 실행한다.

 

68줄 : for문을 통해 22줄에서 정의한 품목을 하나씩 추출하여 35줄(rq_data_opw20004)를 실행한다.

70줄 : 판다스 모듈을 통해 데이터프레임에 "품목"을 넣어주기 위해 임의로 세팅하였다.

 

73줄 : 23줄에서 설정한 데이터프레임에 컬럼(columns)을 7가지로 설정한다.

 

76줄 : 데이터를 저장할 데이터 경로를 설정한다. (6줄의 os모듈은 파일의 경로을 확인한다)

78줄~80줄 : 76줄의 경로에 "margin_data.xlsx" 파일이 있으면, 데이터를 추가하고

81줄~83줄 : 76줄의 경로에 "margin_data.xlsx" 파일이 있으면, 파일을 만들고, 데이터를 추가한다.

 

89줄 : 67줄의 함수(margin_money_start)를 실행한다.


4. 전체코드

 

사용자는 24줄의 self.setting_data를 본인이 원하는 날짜로 수정해주고, 파일을 실행해주면 된다.

 

더보기
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.margin_sort = ['IDX', 'CUR', 'MTL', 'ENG', 'CMD', 'INT']   #  IDX:지수, CUR:통화, MTL:금속, ENG:에너지, CMD:농축산물, INT:금리
        self.margin_situation = {'gubun' : [], 'form_code' : [], 'form_name' : [], 'market_code' : [], 'currency_code' : [], 'customer_margin' : [], 'maintenance_margin' : []}
        self.setting_data = "20230127"

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

    ########## 키움서버에 TR 요청하는 함수 모음 ##########
    def rq_data_opw20004(self, form_gubun_1, data_2, futures_gubun_3, form_codes_4):
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "품목구분", form_gubun_1)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "적용일자", data_2)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "해외파생구분", futures_gubun_3)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "파생품목코드", form_codes_4)
        self.kiwoom.dynamicCall("CommRqData(QString, QString, QString, QString)", "opw_20004", "opw20004", "", "2004")
        self.tr_event_loop = QEventLoop()
        self.tr_event_loop.exec_()

    def trdata_get(self, scrno, rqname, trcode, recordname, prenext):
        if rqname == "opw_20004":
            getrepeatcnt = self.kiwoom.dynamicCall("GetRepeatCnt(QString,QString)", trcode, recordname)     # LONG GetRepeatCnt(BSTR sTrCode, BSTR sRecordName)
            print(getrepeatcnt)

            for j in range(getrepeatcnt):
                form_code1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_20004", "opc20004", j, "파생품목코드").strip()
                form_name1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_20004", "opc20004", j, "품목명").strip()
                market_code1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_20004", "opc20004", j, "해외거래소코드").strip()
                currency_code1 = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_20004", "opc20004", j, "통화코드").strip()
                customer_margin1 = int(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_20004", "opc20004", j, "위탁증거금").strip())/100
                maintenance_margin1 = int(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_20004", "opc20004", j, "유지증거금").strip())/100

                self.margin_situation['gubun'].append(self.margin_sort)
                self.margin_situation['form_code'].append(form_code1)
                self.margin_situation['form_name'].append(form_name1)
                self.margin_situation['market_code'].append(market_code1)
                self.margin_situation['currency_code'].append(currency_code1)
                self.margin_situation['customer_margin'].append(customer_margin1)
                self.margin_situation['maintenance_margin'].append(maintenance_margin1)

            self.tr_event_loop.exit()

    def margin_money_start(self):
        for i in btl.margin_sort:
            time.sleep(1)
            self.margin_sort = i
            btl.rq_data_opw20004(i, self.setting_data, "FU", "")

        df1 = pd.DataFrame(self.margin_situation, columns=['gubun', 'form_code', 'form_name', 'market_code', 'currency_code', 'customer_margin', 'maintenance_margin'])
        print(df1)

        dir = r'C:\Users\User\Desktop\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.margin_money_start()

    app.exec_()

 


5. 마치며

주목할 점은 영웅문G에서 CME 거래소로 구분이 되었다고 하더라도, API에서 Gold는 Comex 거래소, Natural Gas 및 Cruel Oil은 NYMWX 거래소로 분류되어 있다는 점은 알고나서 거래소를 정해야 한다. 즉, 골드, 가스, 오일은 API 거래를 할 때는 CME 시장이 아니므로, 거래를 위해서는 별도의 요금을 지불하여야 한다.

 

주요종목의 거래소는 아래 링크에서 확인하자.

 * 거래소별 종목 현황 링크 (새창에서 열기)

 

OpenAPI-W를 통해 영웅문G에서 거래되는 해외선물 90종목의 현재 기준, 위탁/유지증거금을 받아오는 방법을 알아보았다. 판다스 모듈의 엑셀로 보내는 기능은 언제보아도 훌륭해보인다. ^^

 

그간 관심있는 종목의 증거금 파악하는데 급급했던거 같다. 물론 잘 알지도 못하는 종목에 증거금이 낮다는 이유로 진입하는 것도 상당히 문제이지만, 나스닥 등 인기종목에만 함몰되어 있었던 것도 사실이다. 종목을 폭넓게 공부하는 것도 나쁘지 않아보인다. 시간을 가지고 종목들의 특징을 공부하자.

 

 

반응형