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

(키움증권 해외선물 OpenAPI-W) 일목균형표 구하기 (2) 일목균형표 값 구하기(전환선, 기준선, 후행스팬, 선행스팬1, 선행스팬2)

봄이오네 2023. 12. 15. 08:07
반응형

 

목 차
1. 들어가며
2. 사전설명
3. 코드설명
4. 전체코드
5. 마치며

 
 

1. 들어가며

지난글에서는 일목균형표의 개념 및 산출식에 대해 알아보았다. 개념은 인터넷 검색으로 좋은 설명이 많으니 찾아보면 될 것같고, 산출식은 선행스팬1 및 선행스팬2를 잘 이해하는 것이 필요하다.
 
이번글에서는 일목균형표를 구하는 방법에 대해 알아보자. 필자는 현재가격의 선행스팬1 및 선행스팬2에는 관심이 없다. 확인하고 진입해도 늦지 않다고 생각한다. 그래서 1분전의 봉 기준으로 일목균형표의 구성요소(전환선, 기준선, 선행1, 선행2)에 대해 설명할 것이다.
 


2. 사전설명

일목균형표의 구성요소는 전환선, 기준선, 후행스팬, 선행1, 선행2의 5가지로 이루어진다. 필자는 이글에서 후행스팬을 제외한 4가지(전환, 기준, 선행1, 선행2)에 대해 설명할 것이다.
 

  • 전환선 : 9일(분) 간의 (과거 최고값 + 과거 최저값) / 2
  • 기준선 : 26일(분) 간의 (과거 최고가 + 과거 최저가) / 2
  • 후행스팬 : 현재가격 기준 26일 전의 종가 위치를 표기
  • 선행스팬1 : (당일 전환선 + 당일 기준선) / 2이며, 이 결과를 26일 앞에 기록
  • 선행스팬2 : (52일간 최고가 + 52일간 최저가) /2이며, 이 결과를 26일 앞에 기록

주의할 점이 있다. 이전 글에서도 설명하였지만, 선행스팬1은 키움측 자체적으로 구하고 있다.

  • (일반적인      설명) 선행스팬1 : (당일 전환선 + 당일 기준선) / 2이며, 이 결과를 26일 앞에 기록
  • (키움측 자체 산출) 선행스팬1 : (단기 9일전 최대값 및 최소값 + 중기 26일 최대값 및 최소값) / 4

결과는 비슷한데, 키움측 자체 산출식을 별도로 구성해야 하는 약간의 불편함이 있다.
 
참고로, 일목균형표에 적용된 기간은 단기(shortperiod) 9일(분), 중기(midperiod) 26일(분), 장기(longperiod) 52일(분)이다.
 

그림1. 키움증권의 일목균형표에 적용된 선행스팬1의 수식

 


3. 코드설명

※ 로그인, 활용모듈 등 중복된 내용의 설명은 생략한다. < 그림 >에서 짤린 부분은 아래의 4번(전체코드)에서 확인가능하다.
 

그림2-1. 로그인 및 활용모듈에 대한 내용

 
1줄~30줄 : 로그인 및 활용모듈에 대한 내용이며, 여기서는 설명을 생략한다.
21줄~22줄 : 전환선(48줄~49줄), 기준선(74줄~75줄), 선행스팬1(92줄~93줄), 선행스팬2(126줄~127)줄에서 활용할 리스트를 미리 선언한다.
 

그림2-2. 전환선을 구한다.

 
33줄~38줄 : 146줄에서 종목코드(MNQH24) 및 분봉(1분) 2개를 담은 명령어(146줄)가 실행되면, 명령어를 받는 함수를 선언한다.
 
44줄~67줄 : 여기서부터는 구체적으로 설명한다. 1분전의 기준선을 구한다.
44줄 : 1분전의 전환선은 1분전~9분전의 최고값 및 최저값을 for문으로 받아온다.
48줄~49줄 : 21줄~22줄에서 선언한 리스트에 1분전~9분전의 최고값, 최저값을 리스트에 각각 담는다.
 
51줄~55줄 : 참고용으로 1분전 종가 및 시가를 구한다. (굳이 여기에서 작성할 필요는 없지만, 구하는 값이 정확한지 확인이 필요해서 1분전의 종가 및 시가 구하는 코드를 넣었다)
 
57줄~58줄 : 리스트 내 최고값 및 최저값을 구한다.
60줄 : 1분전의 전환선을 구한다.
66줄~67줄 : 전환선을 구했으므로, 리스트를 초기화한다.
 

그림2-3. 기준선 및 선행스팬1을 구한다.

 
70줄 : 1분전 기준선은 1분전~26분전의 최고값 및 최저값을 합산후 2로 나눈다.
71줄~82줄 : 1분전~26분전의 최고값 및 죄저값을 구하고 80줄에서 2로 나누어서 전환선을 구한다.
84줄~85줄 : 전환선을 구했으므로, 리스트를 초기화한다.
 
88줄 : 이글의 첫번째 핵심이다. 개념을 확실히 이해했다면, 코드가 쉽게 이해될 것이다.
키움측 자체 선행스팬1을 구하려면, 단기9의 최고값 및 최저값, 중기26의 최고값 및 최저값을 각각 구해야 한다.
현재가격의 선행스팬1은 26분전에 산출된다.
89줄~99줄 : 26분전 기준으로 26분전~34분전(9분 동안, 단기)의 전환선을 구한다.
 

그림2-4. 선행스팬2를 구한다.

 
101줄~112줄 : 26분전 기준으로 26분전~51분전(26분 동안, 중기)의 기준선을 구한다.
 
114줄 : 키움측 자체 선행스팬1을 구하기 위해 (단기 최고값 + 단기 최저값 + 중기 최고값 + 중기 최저값)을 구한다.
115줄 : 114줄의 값을 4로 나누어서 선행스팬1을 구한다.
 
122줄~135줄 : 26분전~78분전(52분 동안, 장기)의 선행스팬2를 구한다.
 

그림2-5. 1분봉 데이터 받는 함수(33줄)를 실행한다.

 
146줄 : 종목코드(MNQH24) 및 분봉 종류(1분)의 변수를 담아서 33줄의 함수를 실행한다.
 


4. 전체코드

※ 아래 < 접은글 > 코드를 실행하려면 키움증권에 $185달러의 시세조회 이용료를 지불하여야 한다.
 

더보기
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.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.kiwoom.dynamicCall("GetCommonFunc(QString, QString)", "ShowAccountWindow", "")  # 계좌번호 입력창을 띄우는 내부함수

        ########## 일목균형목 기준값의 최대값/최소값 ##########
        self.ilmok_stand_max = []
        self.ilmok_stand_min = []

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

    ########## 키움서버에 TR 요청하는 함수 모음 (키움 OPENApi-w에서 제공) ##########
    def rq_data_opc10002(self, stock_code_num, time_unit):  # 패턴 받기 (QEventLoop 는 생략, 1분 정도 버벅거림) (221229)
        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")
        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, 10):
                high_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "고가").strip()))
                low_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "저가").strip()))

                self.ilmok_stand_max.append(high_price)
                self.ilmok_stand_min.append(low_price)

            open_price_one_ago = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", 1, "시가").strip()))
            close_price_one_ago = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", 1, "현재가").strip()))

            self.open_price_one_ago = open_price_one_ago
            self.close_price_one_ago = close_price_one_ago

            self.ilmok_conversion_line_max_price = max(self.ilmok_stand_max)
            self.ilmok_conversion_line_min_price = min(self.ilmok_stand_min)

            self.ilmok_conversion_price = round((self.ilmok_conversion_line_max_price + self.ilmok_conversion_line_min_price) / 2, 2)

            print(self.open_price_one_ago)
            print(self.close_price_one_ago)
            print(self.ilmok_conversion_price)

            self.ilmok_stand_max = []
            self.ilmok_stand_min = []

            ### 1분전 기준선 ###
            for i in range(1, 27):
                high_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "고가").strip()))
                low_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "저가").strip()))

                self.ilmok_stand_max.append(high_price)
                self.ilmok_stand_min.append(low_price)

            self.ilmok_stand_line_max_price = max(self.ilmok_stand_max)
            self.ilmok_stand_line_min_price = min(self.ilmok_stand_min)

            self.ilmok_stand_price = round((self.ilmok_stand_line_max_price + self.ilmok_stand_line_min_price) / 2, 2)

            print(self.ilmok_stand_price)

            self.ilmok_stand_max = []
            self.ilmok_stand_min = []

            ### 선행스팬1 ### Leading Span A        9/26/52
            for i in range(26, 35):      # 1~10에서 25분전으로 기재 :
                high_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "고가").strip()))
                low_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "저가").strip()))

                self.ilmok_stand_max.append(high_price)
                self.ilmok_stand_min.append(low_price)

            self.ilmok_conversion_line_1_max_price = max(self.ilmok_stand_max)
            self.ilmok_conversion_line_1_min_price = min(self.ilmok_stand_min)

            self.ilmok_stand_max = []
            self.ilmok_stand_min = []

            for i in range(26, 52):
                high_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "고가").strip()))
                low_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "저가").strip()))

                self.ilmok_stand_max.append(high_price)
                self.ilmok_stand_min.append(low_price)

            self.ilmok_stand_line_1_max_price = max(self.ilmok_stand_max)
            self.ilmok_stand_line_1_min_price = min(self.ilmok_stand_min)

            self.ilmok_stand_max = []
            self.ilmok_stand_min = []

            self.ilmok_leading_1_sum_4 = self.ilmok_conversion_line_1_max_price + self.ilmok_conversion_line_1_min_price + self.ilmok_stand_line_1_max_price + self.ilmok_stand_line_1_min_price
            self.ilmok_leading_span_1 = round(self.ilmok_leading_1_sum_4 / 4, 2)

            print("#######################")
            print(self.ilmok_leading_span_1)
            print("#######################")

            ### 선행스팬2 ### Leading Span B
            for i in range(26, 79):      # 1~53에서 현재의 선행스팬2는 25분전 앞에 더함 (26~79)
                high_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "고가").strip()))
                low_price = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "저가").strip()))

                self.ilmok_stand_max.append(high_price)
                self.ilmok_stand_min.append(low_price)

            self.ilmok_leading_span_2_max_price = max(self.ilmok_stand_max)
            self.ilmok_leading_span_2_min_price = min(self.ilmok_stand_min)

            self.ilmok_leading_span_2 = round((self.ilmok_leading_span_2_max_price + self.ilmok_leading_span_2_min_price) / 2, 2)

            self.ilmok_stand_max = []
            self.ilmok_stand_min = []

            print(self.ilmok_leading_span_2)
            print("#######################")

            self.tr_event_loop.exit()

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

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

    app.exec_()

 


5. 마치며

일목균형목 구성요소를 산출하는 방법을 알아보았다. 선행스팬1 및 선행스팬2 개념을 이해하는데 상당히 어렵게 느껴졌지만, 선행스팬1 및 선행스팬2의 개념을 이해했다면 26분전에 비해 현재가격의 위치(위에 있는지, 아래에 있는지)를 가늠한후 투자할 수 있을 것이다.

반응형