2. 해외선물/2-4. 해외선물 API (사용)

(키움증권 해외선물 OpenAPI-W) 패턴 만들기 (5) 패턴 만들기(파이썬)

봄이오네 2023. 1. 18. 08:04
반응형
목 차
1. 들어가며
2. 사전설명
   1) 키움에서 받아오는 데이터는 문자형
   2) 문자형 → 실수형 → 정수형 → 절대값으로 작업 필요
3. 코드설명
4. 전체코드
5. 마치며

 

1. 들어가며

지난 글에서는 패턴의 개념 및 적용하는 방법을 알아보았다.

대단한 개념은 아니다.

 

필자도 고수들처럼 AI를 통한 머신러닝, 3음봉/3양봉 후 진입을 생각해 보았는데, 머신러닝을 위한 GPU 가격이 부담되고, 3음봉/3양봉을 어렵게 구현하더라도 수익이 난다는 100% 확신이 없는 상황에서 쉽게 다른 방법으로 코드를 구현하는 것은 부담이 되는 게 사실이다.

 

이번 글부터는 패턴을 본격적으로 만들어가보고자 한다.

패턴은 앞에서도 설명하였듯이, OHLC에 각각 10,000을 곱해서 부동소수점 문제를 회피하고나서 OHLC 간 사칙연산을 통해 패턴을 만들어줄 것이다.

 

브리티쉬 파운드(6BH23)의 패턴을 만들어보자.

 

※ (정정) 부동소수점 문제 회피 방법 (추가)

 

더보기

※ (정정) 부동소수점 문제를 회피 방법 (엑셀에서 패턴 만들 때 round 함수 추가)
1. 문제점
 ㅇ 부동소수점 문제를 회피하기 위해 10,000을 OHLC에 곱해서 패턴을 만들는 과정에서 문제 발생
   - 파운드를 엑셀에서 계산하는 과정에서 부동소수점 문제가 발생했다.
    * 파이썬은 시가 0.0002 x 10000 을 하면 2이고, 고가 0.0004 x 10000을 하면 4로서, (고가)-(저가) = 2가 나온다.
       문제는 엑셀에서 부동소수점 문제가 발생한다. -_-+
      시가 0.0002 x 10000 을 하면 2이고, 고가 0.0004 x 10000을 하면 4인데, (고가)-(저가) = 1.999...

 ㅇ < 그림1-1 > P9셀에서 부동소수점이 발생하는 것을 확인할 수 있다.
    * 패턴 : 0 -4.999....18 - 3
      → 원래는 0 - 5 - 3으로 나타나야 하는데, 부동소수점 문제가 엑셀에서 발생한 것이다. ㅠㅠ

그림1-1. 파운드의 부동소수점 문제 발생

 

2. 해소 방법
< 그림1-2 >에서처럼, 사칙연산 이후 엑셀의 반올림하는 round 함수를 넣어준다.
설명은 이 글의 본문에서 하겠다. 

그림1-2. round 함수를 적용한 p9셀의 결과물

2. 사전설명

1) 키움에서 받아오는 데이터는 문자형

키움증권에서 제공하는 데이터는 문자형이다.

예를들어 1.25를 키움에서 받았다면, 1.25의 태형은 실수(float)가 아닌 문자형(str)이다.

 

2) 문자형 → 실수형 → 정수형 → 절대값으로 작업 필요

①문자형을 실수형으로 바꾸는 방법은 문자형에 실수형(float)를 붙인다.

②실수형을 사칙연산한 경우, 부동소수점 문제가 발생하므로, 10000을 곱하여 정수화 한다.

    예를 들어, 1.2345에 10000을 곱하면 12345가 되는데 이는 실수형이다. (실수형 x 10000 = 실수형)

   → 실수형을 정수화하는 방법은 실수형 앞에 정수화(int)를 붙이는 것이다.

③WKOA Studio에서 데이터를 받아보면 알겠지만,

    키움증권에서 받는 데이터의 종가가 "마이너스"인 경우를 확인할 수 있다.

    1분전의 종가보다 작아지면 "마이너스"로 표현되는 경우가 있다고 한다.

   → 만약의 경우를 위해 절대값을 붙여 "마이너스"가 나오지 않도록 한다.

    * 참고자료 : 문자형을 절대값으로 수정 링크

 

※ (결론) open = abs (int( float(문자형) x 10000 ) ) 의 형태로 표기할 예정이다.

 

3) 엑셀 round 함수

  • 엑셀 정의 : 설정한 소수점에 반올림
  • 활용 형태 : round ( 셀, 소수점 자리수)
  • 활용 예시 : round ( 1.23, 1) → 소수 첫째자리(1)에서 반올림하므로 1이 된다.

3. 패턴만들기 설명

1) 키움증권에서 제공하는 1분봉 패턴

이 글부터는 pyautogui를 통한 半자동 로그인은 설명하지 않을 예정이다.

어차피... 자동로그인이 되지 않는다면, 굳이 연습할 때 반자동 로그인을 설명할 실익이 적어 보인다.

귀찮더라도, 아이디의 비밀번호 및 계좌비밀번호는 스스로 입력하자.

 

그림2-1. 키움증권 OpenAPI-W에 접속하는 화면

 

1줄~5줄 : 로그인 및 QEventLoop 등을 활용하기 위해 필요 모듈을 임포트한다.

9줄 : 키움증권 OpenAPI-W 관련 레지스트리를 self.kiwoom에 담는다.

12줄~13줄 : 20줄(login_Connect)과 28줄(rq_data_opc10002)를 15~16줄 및 36줄의 결과값을 받아오기 위해 연결한다.

14줄 : 접속을 위한 로그인창의 비밀번호 창을 띄운다.

17줄 : 계좌 비밀번호 입력을 위한 창을 띄운다.

 

그림2-2. 키움증권에 OHLC를 요청하고, 연산하여 패턴을 만드는 화면

 

코드가 약간 짤렸는데, 이 글의 4번(전체코드)에 모두 있으니, 여기서는 참고만 하자.

28줄 : OHLC를 받아오기 위해, 종목/분봉 종류 입력 및 요청을 위해 함수를 선언한다.

29줄 : SetInputValue 함수를 이용하여 종목단위 및 시간단위가 들어갈 데이터를 키움서버에 입력한다.

30줄 : CommRqData 함수를 이용하여 28~29줄에서 키움서버에 입력한 데이터를 키움서버에 요청한다.

32줄 : 나중에 설명하겠지만, 키움측에서는 CommRqData 함수의 1초 당 5회 이상 조회시, OpenAPI 사용제한을 한다.

 

37줄 : 28줄~34줄까지 키움서버에 입력/요청한 데이터는 13줄(onreceive)의 연결을 통해 데이터를 받아온다.

38줄 ~ 53줄 : OHLC를 받아와서 패턴을 만드는 코드이다. 마음편히 쭈욱 훑어만 보자

 

38줄 : for문을 통해 데이터를 뽑아오는데, range(1, 2)는 1분전의 봉을 가져오라는 뜻이다.

           * range(0,1)이면 현재 시간(06:59)의 데이터를 가져오라는 것이다.

           * 현재는 장이 종료되어 있어서, 06:58분이 데이터를 가져온다.

 

39~43줄 : 체결시간 및 OHLC를 키움증권이 제공하는 GetCommData 함수를 통해 받아온다.

           * 참고할 것은 < 그림3 >에서처럼 7개 데이터(현재가, 거래량 ~ 영업일자)를 받아오는데,

              필자는 여기서, 5개 데이터만 사용 예정(체결시간, 현재가, 고가, 저가, 종가)이다.

          * 사용자가 활용 예정인 데이터는 39줄~43줄처럼 받아오면 된다.

 

그림3. WKOA Studio에서 확인한 수신데이터

 

45줄 : 이 글의 첫번째 핵심이다. 패턴을 만들어준다.

          * 여기에서 부동소수점이 발생한다. < 그림2-2 >에서 화면이 짤렸지만, 아래의 4번(전체코드)에서 확인하였듯이, 시가~종가에 10,000을 곱한 것을 확인할 수 있다.

 

50줄~51줄 : 이 글의 두번째 핵심이다.

                     우리가 현재 하고자하는 거래는 선물거래이다. 양방향으로 투자할 수 있는 장점이 있는 거래이다.

                     나중에 설명하겠지만, long / short 으로 동일 패턴을 각각 변수화 시키되,

                     향후 사용자가 만들 패턴에서 구분만 해주면 된다.

 

59줄 : 파운드('23.3월물)의 1분봉을 받기 위해 28줄의 함수를 실행하면 결과는 아래와 같다.

그림4. 2023.1.14일 06:58분 파운드의 패턴이다.


4. 전체 코드

※ 40줄~43줄의 시가~종가를 보면, 줄의 에 10000에 곱해지는 것을 확인하자.

 

import sys
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
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()
        self.login_event_loop.exec_()
        self.kiwoom.dynamicCall("GetCommonFunc(QString, QString)", "ShowAccountWindow", "")  # 계좌번호 입력창을 띄우는 내부함수

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

    ########## 키움서버에 TR 요청하는 함수 모음 ##########
    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", "", "1012")
        time.sleep(0.5)
        self.tr_event_loop = QEventLoop()
        self.tr_event_loop.exec_()

    def trdata_get(self, scrno, rqname, trcode, recordname, prenext):
        if rqname == "opc_10002":
            for i in range(1, 2):
                dealed_time = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "체결시간").strip()
                open = abs(int(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "시가").strip()) * 10000))
                high = abs(int(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "고가").strip()) * 10000))
                low = abs(int(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "저가").strip()) * 10000))
                close = abs(int(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "현재가").strip()) * 10000))

                pattern = str(high - open) + str(low - open) + str(close - open)
                pattern = str(pattern)

                print(f" {dealed_time}의 패턴은 {pattern }이다.")

                self.check_pattern_jongmok_long = pattern
                self.check_pattern_jongmok_short = pattern

                self.tr_event_loop.exit()

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

    btl.rq_data_opc10002("6BH23", "1")  # 1분봉 패턴 받기

    app.exec_()
    
    
# (expected result)
    
# 20230114065800의 패턴은 1-3-1이다.

 


5. 마치며

글이 상당히 길어졌다. 해외선물도 국내주식과 유사한 구조(OHLC)여서, 비교적 수월하게 패턴을 만들 수 있었다.

다만, 소수점 틱단위가 있기 때문에 부동소수점 문제도 발생하고, 조금은 골치 아프다.

 

10,000을 곱해서 끝낼 수 있을 것 같았는데, 엑셀에서 부동소수점 문제가 발생할 줄이야...

다음 시간에는 엑셀에서 패턴 만드는 방법을 알아보자.

반응형