2. 해외선물/2-1. 해외선물 자동매매 연구

(키움증권 해외선물 자동매매 파이썬) 15. 보조지표 구하기 (볼린저밴드, MACD, 스토캐스틱)

봄이오네 2023. 10. 22. 08:03
반응형

 

목 차
1. 들어가며
2. 코드설명
   1) 볼린저밴드
   2) MACD
   3) 스토캐스틱
3. 전체코드
4. 마치며

 

 

1. 들어가며

지난 글에서는 RSI 지표의 코드 작성에 대해 알아보았다. 필자는 개인적으로 rsi 보조지표를 선호하는 편이다. 그래서 구체적으로 작성했던 것 같다.

 

이번 글에서는 예전에 설명했던 보조지표들에 대해 간략히 설명할 예정이다. 코드의 상세한 설명은 링크를 걸어둔다.

사실, 보조지표의 설명을 다시 해야하나... 상당히 고민했다. 지난 글의 rsi처럼 새로운 내용이 추가되는 게 아닌데, 중복된 설명은 글을 쓰는 필자도 그렇고, 글을 읽는 사용자도 집중력이 떨어질 수 밖에 없을 것 같다.

 

그래서, 중복된 내용은 링크를 걸고, 보조지표를 실시하는 "코드"를 공유(4. 전체코드)하는 차원에서 이번 글을 마무리하려고 한다.

 


2. 코드설명

1) 볼린저밴드

20일(분)의 종가 이동평균에 표준편차를 더하거나 빼서 주가의 위치를 알려주는 보조지표이다. 주로 표준편차 (2- α) 인 95.5%의 신뢰구간을 활용한다. (볼린저밴드 설명 : https://springcoming.tistory.com/169)

 

2) macd

MACD는 이동평균수렴발산(Moving Average Convergence Divergence)이며 단기 이동평균선과 장기 이동평균선이 서로 가까워지거나(수렴) 멀어지는(발산) 원리를 활용한다. (macd 설명 : https://springcoming.tistory.com/194)

 

3) 스토캐스틱

주식/선물을 하면서 활용하는 보조지표 중 하나로 스토캐스틱이 있다. 일정 기간 동안 최고가 및 최저가 사이에서 현재가격의 위치를 백분율로 알려주는 지표이다. (스토캐스틱 설명 : https://springcoming.tistory.com/210)

 

그림. 볼린저밴드, macd, 스톡캐스트 등 보조지표에 대한 내용

 


3. 전체 코드

아래 < 접은글 >의 코드를 실행하려면, 시세조회 이용료($185)를 지불하여야 한다.

81줄~83줄 실행코드241줄~661줄(+420줄)  보조지표를 받는 코드가 추가되었다.

 

더보기
import sys
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import numpy

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", "")  # 계좌번호 입력창을 띄우는 내부함수

        ##### rsi의 현재 1분 데이터의 au/ad 구하기 #####
        self.price_rsi_total = []           # 158~163줄 : 1분봉들의 종가데이터를 담는 리스트 모음
        self.close_price_rsi_change = []    # 164~167줄 : 기준값(au/ad)를 세팅하기 위해, 최근 15개 값을 담는 리스트
        self.close_price_third = []         # 168~179줄 : 기준값 15개의 각 종가들의 차이 모음 리스트

        self.early_au1 = []                 # 175~179줄 : 음수를 0으로 표시
        self.early_ad1 = []                 # 175~179줄 : 양수를 0으로 표시

        self.rsi_total_list = []            # 214~235줄 : 각각의 rsi를 담는 리스트 모음

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

    ########## 키움서버에 TR 요청하는 함수 모음 ##########
    def rq_data_opc10002(self, stock_code_num, time_unit):  # 1분봉 받기
        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_()

    def rq_data_opw30009(self, deposit_num1, password_2, password_enter3):  # 주문가능금액, 실현손익, 미실현손익
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "계좌번호", deposit_num1)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "비밀번호", password_2)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "비밀번호입력매체", password_enter3)
        self.kiwoom.dynamicCall("CommRqData(QString, QString, QString, QString)", "opw_30009", "opw30009", "", "3009")
        self.tr_event_loop = QEventLoop()
        self.tr_event_loop.exec_()

    def rq_data_opw30011(self, deposit_num1, password_2, password_enter3, futures_code4, sell_buy_gubunm5, order_type6, order_price7):  # 주문가능수량
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "계좌번호", deposit_num1)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "비밀번호", password_2)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "비밀번호입력매체", password_enter3)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "종목코드", futures_code4)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "매도수구분", sell_buy_gubunm5)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "해외주문유형", order_type6)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "주문표시가격", order_price7)  # "시장가"로 주문할 경우, 함수 실행시 빈칸("")으로 요청
        self.kiwoom.dynamicCall("CommRqData(QString, QString, QString,QString)", "opw_30011", "opw30011", "", "3011")
        self.tr_event_loop = QEventLoop()
        self.tr_event_loop.exec_()

    def rq_data_opw30012(self, deposit_num1, password_2, password_enter3):  # 계좌 현재가, 매도수구분, 보유수량, 매입단가, 계좌현재가, 평가손익
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "계좌번호", deposit_num1)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "비밀번호", password_2)
        self.kiwoom.dynamicCall("SetInputValue(QString,QString)", "비밀번호입력매체", password_enter3)
        self.kiwoom.dynamicCall("CommRqData(QString, QString, QString, QString)", "opw_30012", "opw30012", "", "3012")
        self.tr_event_loop = QEventLoop()
        self.tr_event_loop.exec_()

    ########## OnReceiveTrData을 통해 수신받은 데이터 함수  ##########
    def trdata_get(self, scrno, rqname, trcode, recordname, prenext):
        if rqname == "opc_10002":
            getrepeatcnt = self.kiwoom.dynamicCall("GetRepeatCnt(QString,QString)", trcode, recordname)
            self.getrepeatcnt = getrepeatcnt

            self.tr_event_loop.exit()
            btl.rsi_searching()
            btl.bollinger_searching()
            btl.macd_searching()

        elif rqname == "opw_30009":  # 주문가능금액, 실현손익, 미실현손익
            orderable_money = float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30009", "opw30009", 0, "주문가능금액").strip())
            withdrawal_money = float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30009", "opw30009", 0, "인출가능금액").strip())
            realized_pl = float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30009", "opw30009", 0, "선물청산손익").strip())
            unrealized_pl = int(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30009", "opw30009", 0, "선물평가손익").strip())

            self.orderable_money = orderable_money / 100
            self.withdrawal_money = withdrawal_money / 100
            self.realized_pl = realized_pl / 100
            self.unrealized_pl = unrealized_pl / 100

            print(self.orderable_money)

            self.tr_event_loop.exit()

        elif rqname == "opw_30011":  # 주문가능수량
            orderable_qty = int(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30011", "opw30011", 0, "주문가능수량").strip())
            liquidable_qty = int(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30011", "opw30011", 0, "청산가능수량").strip())
            orderable_money_30011 = float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30011", "opw30011", 0, "주문가능금액").strip())
            currency_code = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30011", "opw30011", 0, "통화코드").strip()

            self.orderable_qty = orderable_qty
            self.liquidable_qty = liquidable_qty
            self.orderable_money_30011 = orderable_money_30011 / 100
            self.currency_code = currency_code

            self.tr_event_loop.exit()

        elif rqname == "opw_30012":  # 계좌 현재가, 매도수구분, 보유수량, 매입단가, 계좌현재가, 평가손익
            stock_code_d = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30012", "opw30012", 0, "종목코드").strip()
            sell_buy_gubun_d = self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30012", "opw30012", 0, "매도수구분").strip()
            my_qty_d = int(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30012", "opw30012", 0, "수량").strip())
            my_price_d = float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30012", "opw30012", 0, "매입가격").strip())
            current_price_d = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30012", "opw30012", 0, "현재가격").strip()))
            estimate_pl_d = int(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opw_30012", "opw30012", 0, "평가손익").strip())

            self.stock_code_d = stock_code_d
            self.sell_buy_gubun_d = sell_buy_gubun_d
            self.my_qty_d = my_qty_d
            self.my_price_d_30012 = my_price_d
            self.current_price_d_30012 = current_price_d
            self.estimate_pl_d_30012 = estimate_pl_d / 100

            self.tr_event_loop.exit()

    ########## 주문요청하는 함수 (키움 OPENApi-w에서 제공) ##########
    def sendorder_func(self, rqname, scr, acc, ordertype, futures_code, qty, futures_price, s_stop, hogagb, orgno):
        self.kiwoom.dynamicCall("SendOrder(Qstring, Qstring, Qstring, int, Qstring, int, Qstring, Qstring, Qstring, Qstring)",
                                [rqname, scr, acc, ordertype, futures_code, qty, futures_price, s_stop, hogagb, orgno])

    """
        1) BSTR sRQName,
        2) BSTR sScreenNo,
        3) BSTR sAccNo,
        4) LONG nOrderType, *주문유형(1: 신규매도, 2: 신규매수, 3: 매도취소, 4: 매수취소, 5: 매도정정, 6: 매수정정)
        5) BSTR sCode,
        6) LONG nQty,
        7) BSTR sPrice,
        8) BSTR sStop,      * stop 단가
        9) BSTR sHogaGb,    * 거래구분(1: 시장가, 2: 지정가, 3: STOP, 4: STOP LIMIT)
        10) BSTR sOrgOrderNo)
            *(예시)  ## openApi.SendOrder("RQ_1", "1000", "5077000072", 1, "6AZ20", / 1, "0.7900", "0",        "2",  "");       // 지정가 매도
                       openApi.SendOrder("RQ_1", "1000", "5077000072", 1, "6AZ20", / 1, "0",      "0",        "1",  "");       // 시장가 매도
                    ## openApi.SendOrder("RQ_1", "1000", "5077000072", 1, "6AZ20", / 1, "0",       "0.7900", "3", "");       // STOP 매도
                    ## openApi.SendOrder("RQ_1", "1000", "5077000072", 1, "6AZ20", / 1, "0.7850", "0.8000",   "4", "");       // STOP LIMIT 매도
                    ## openApi.SendOrder("RQ_1", "1000", "5077000072", 5, "6AZ20", / 1, "0.7850", "0",       "2", "500060"); // 정정 매도
                    ## openApi.SendOrder("RQ_1", "1000", "5077000072", 3, "6AZ20", / 1, "0",     "0",       "2", "500060"); // 취소 매도
    """

    def rsi_searching(self):
        for i in range(self.getrepeatcnt):  # 현재가 → 오래된 값으로 출력된다.
            self.current_price_rsi = float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "현재가").strip())
            self.price_rsi_total.append(self.current_price_rsi)

        self.price_rsi_total_final = self.price_rsi_total[::-1]
        self.price_rsi_total = []

        for i in range(0, 15):
            current_price_recent = self.price_rsi_total_final[i]
            self.close_price_rsi_change.append(current_price_recent)

        for j in range(len(self.close_price_rsi_change) - 1):
            self.close_price_second = self.close_price_rsi_change[j + 1] - self.close_price_rsi_change[j]
            self.close_price_third.append(self.close_price_second)

        self.close_price_rsi_change = []

        print("68줄")

        for i in self.close_price_third:  # 음수를 0으로 표시
            if i <= 0:
                i = 0
                self.early_au1.append(i)
            else:
                self.early_au1.append(i)

        for j in self.close_price_third:  # 양수를 0으로 표시
            if j >= 0:
                j = 0
                self.early_ad1.append(j)
            else:
                self.early_ad1.append(j)

        self.au7 = sum(self.early_au1) / len(self.early_au1)
        self.ad7 = sum(self.early_ad1) / len(self.early_ad1)
        self.ad7 = abs(self.ad7)

        self.early_au1 = []  # 초기화
        self.early_ad1 = []  # 초기화
        del self.close_price_third[:]  # 향후 사용하지 않을 분봉 리스트는 초기화(삭제)하여 메모리 효율화 추진

        for k in range(1, self.getrepeatcnt-1):
            curren_price_rsi_1 = self.price_rsi_total_final[k]
            curren_price_rsi_2 = self.price_rsi_total_final[k+1]
            current_price_rsi_3 = curren_price_rsi_2 - curren_price_rsi_1

            if current_price_rsi_3 >= 0:
                positive_price = current_price_rsi_3
                negative_price = 0
            else:
                positive_price = 0
                negative_price = abs(current_price_rsi_3)

            self.au8 = (self.au7 * 13 + positive_price) / 14
            self.ad8 = (self.ad7 * 13 + negative_price) / 14

            rs2 = self.au8 / self.ad8

            self.rsi_second = rs2 / (1 + rs2) * 100
            self.current_rsi = round(self.rsi_second, 2)

            self.rsi_total_list.append(self.current_rsi)

            self.au7 = self.au8
            self.ad7 = self.ad8

        self.price_rsi_total_final = []

        self.rsi_total_list = self.rsi_total_list[::-1]

        self.current_rsi_0 = self.rsi_total_list[0]     # 현재시간
        self.current_rsi_1 = self.rsi_total_list[1]     # 1분전

        print(self.current_rsi_0)
        print(self.current_rsi_1)

        self.rsi_total_list_2_35_minute = []        # 2분전 ~ 35분전
        for i in range(2, 36):
            self.rsi_total_list_2_35_minute.append(self.rsi_total_list[i])

        self.rsi_max_2_35_minute_point = max(self.rsi_total_list_2_35_minute)
        self.rsi_max_2_35_minute_position = self.rsi_total_list_2_35_minute.index(self.rsi_max_2_35_minute_point)

        self.rsi_min_2_35_minute_point = min(self.rsi_total_list_2_35_minute)
        self.rsi_min_2_35_minute_position = self.rsi_total_list_2_35_minute.index(self.rsi_min_2_35_minute_point)

    def bollinger_searching(self):
        self.close_price2 = []
        for i in range(0, 20):
            close_price1 = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "현재가").strip()))

            self.close_price2.append(close_price1)

        self.close_price3 = numpy.mean(self.close_price2) + numpy.std(self.close_price2) * 2
        self.close_price4 = numpy.mean(self.close_price2) - numpy.std(self.close_price2) * 2

        self.bollinger_upper_line = float(round(self.close_price3, 2))
        self.bollinger_lower_line = float(round(self.close_price4, 2))

        self.close_price2 = []  # 2번째 종목 조회할 때,1종목의 데이터가 들어있어서 누적되는 현상 발생 (초기화 시켜줌)

    def macd_searching(self):

        ##### macd의 현재 1분 데이터의 au/ad 구하기 #####
        self.macd_minute_bong_couning = 100  # macd를 구하기 위해 받아올 일봉 갯수
        self.price_macd_total = []  # 56~86줄 : 1분봉들의 종가데이터를 담는 리스트 모음
        self.macd_12_26_total = []  # macd 시그널을 구하기 위한 리스트 선언

        self.ema_var_12 = 2 / (12 + 1)
        self.ema_var_26 = 2 / (26 + 1)
        self.signal_var_9 = 2 / (9 + 1)

        for i in range(self.macd_minute_bong_couning):  # 현재가 → 오래된 값으로 출력된다.
            self.current_price_macd = float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "현재가").strip())
            self.price_macd_total.append(self.current_price_macd)

        self.price_macd_total_final = self.price_macd_total[::-1]

        ### ema_12, ema_26 지수이동평균 구하기 ###
        for i in range(self.macd_minute_bong_couning):
            if i == 0:
                pass

            elif i == 1:
                self.ema_12_first = (self.price_macd_total_final[1] * self.ema_var_12) + (self.price_macd_total_final[0] * (1 - self.ema_var_12))
                self.ema_12_second = self.ema_12_first

                self.ema_26_first = (self.price_macd_total_final[1] * self.ema_var_26) + (self.price_macd_total_final[0] * (1 - self.ema_var_26))
                self.ema_26_second = self.ema_26_first

            elif i >= 2:
                self.ema_12_third = self.ema_12_second
                self.ema_12_forth = self.price_macd_total_final[i]
                self.ema_12_final = (self.ema_12_forth * self.ema_var_12) + (self.ema_12_third * (1 - self.ema_var_12))
                self.ema_12_second = self.ema_12_final

                self.ema_26_third = self.ema_26_second
                self.ema_26_forth = self.price_macd_total_final[i]
                self.ema_26_final = (self.ema_26_forth * self.ema_var_26) + (self.ema_26_third * (1 - self.ema_var_26))
                self.ema_26_second = self.ema_26_final

                # self.macd_12_26 = round(self.ema_12_final - self.ema_26_final, 2)   # 소수 셋째 자리에서 반올림 (소수 둘째 자리까지 출력)
                self.macd_12_26 = self.ema_12_final - self.ema_26_final           # 반올림없이 값 출력
                self.macd_12_26_total.append(self.macd_12_26)

                if i == self.macd_minute_bong_couning - 7:
                    self.macd_12_26_6_mintue_ago = self.macd_12_26
                elif i == self.macd_minute_bong_couning - 6:
                    self.macd_12_26_5_mintue_ago = self.macd_12_26
                elif i == self.macd_minute_bong_couning - 5:
                    self.macd_12_26_4_mintue_ago = self.macd_12_26
                elif i == self.macd_minute_bong_couning - 4:
                    self.macd_12_26_3_mintue_ago = self.macd_12_26
                elif i == self.macd_minute_bong_couning - 3:
                    self.macd_12_26_2_mintue_ago = self.macd_12_26
                elif i == self.macd_minute_bong_couning - 2:
                    self.macd_12_26_1_mintue_ago = self.macd_12_26
                elif i == self.macd_minute_bong_couning - 1:
                    self.macd_12_26_current = self.macd_12_26

        ### macd_signal 구하기 ###
        self.macd_12_26_counting = len(self.macd_12_26_total)
        print(self.macd_12_26_counting)

        for i in range(self.macd_12_26_counting):
            if i == 0:
                pass

            if i == 1:
                self.macd_signal_first = (self.macd_12_26_total[1] * self.signal_var_9) + (self.macd_12_26_total[0] * (1 - self.signal_var_9))
                self.macd_signal_second = self.macd_signal_first

            elif i >= 2:
                self.macd_signal_third = self.macd_signal_second
                self.macd_signal_forth = self.macd_12_26_total[i]
                self.macd_signal_final = (self.macd_signal_forth * self.signal_var_9) + (self.macd_signal_third * (1 - self.signal_var_9))
                # self.macd_signal_final = round(self.macd_signal_final, 2)    # 소수 셋째 자리에서 반올림 (소수 둘째 자리까지 출력)

                self.macd_signal_second = self.macd_signal_final

                if i == self.macd_12_26_counting - 7:
                    self.macd_signal_final_6_mintue_ago = self.macd_signal_final
                elif i == self.macd_12_26_counting - 6:
                    self.macd_signal_final_5_mintue_ago = self.macd_signal_final
                elif i == self.macd_12_26_counting - 5:
                    self.macd_signal_final_4_mintue_ago = self.macd_signal_final
                elif i == self.macd_12_26_counting - 4:
                    self.macd_signal_final_3_mintue_ago = self.macd_signal_final
                elif i == self.macd_12_26_counting - 3:
                    self.macd_signal_final_2_mintue_ago = self.macd_signal_final
                elif i == self.macd_12_26_counting - 2:
                    self.macd_signal_final_1_mintue_ago = self.macd_signal_final
                elif i == self.macd_12_26_counting - 1:
                    self.macd_signal_final_current = self.macd_signal_final

        self.price_macd_total = []
        self.price_macd_total_final = []
        self.macd_12_26_total = []

        ### macd_oscillators 구하기 ###
        self.macd_Oscillator_6_mintue_ago = self.macd_12_26_6_mintue_ago - self.macd_signal_final_6_mintue_ago
        self.macd_Oscillator_5_mintue_ago = self.macd_12_26_5_mintue_ago - self.macd_signal_final_5_mintue_ago
        self.macd_Oscillator_4_mintue_ago = self.macd_12_26_4_mintue_ago - self.macd_signal_final_4_mintue_ago
        self.macd_Oscillator_3_mintue_ago = self.macd_12_26_3_mintue_ago - self.macd_signal_final_3_mintue_ago
        self.macd_Oscillator_2_mintue_ago = self.macd_12_26_2_mintue_ago - self.macd_signal_final_2_mintue_ago
        self.macd_Oscillator_1_mintue_ago = self.macd_12_26_1_mintue_ago - self.macd_signal_final_1_mintue_ago
        self.macd_Oscillator_final_current = self.macd_12_26_current - self.macd_signal_final

        self.macd_Oscillator_2_mintue_ago = round(self.macd_12_26_2_mintue_ago - self.macd_signal_final_2_mintue_ago, 2)
        self.macd_Oscillator_1_mintue_ago = round(self.macd_12_26_1_mintue_ago - self.macd_signal_final_1_mintue_ago, 2)
        self.macd_Oscillator_final_current = round(self.macd_12_26_current - self.macd_signal_final, 2)

        print(self.macd_12_26_2_mintue_ago)
        print(self.macd_signal_final_2_mintue_ago)
        print(self.macd_Oscillator_2_mintue_ago)
        print("\n")
        print(self.macd_12_26_1_mintue_ago)
        print(self.macd_signal_final_1_mintue_ago)
        print(self.macd_Oscillator_1_mintue_ago)
        print("\n")
        print(self.macd_12_26_current)
        print(self.macd_signal_final_current)
        print(self.macd_Oscillator_final_current)

    def stochastic_searching(self):
        ### 스토캐스틱 지표 #####
        self.nq_max_price_list = []
        self.nq_min_price_list = []

        self.stc_fast_d_list = []

        self.stc_slow_k_list_close_min = []
        self.stc_slow_k_list_max_min = []

        self.stc_slow_d_list_row = []
        self.stc_slow_d_list = []

        self.stc_slow_k_forth_list = []

        self.stc_fast_k_weighting = 2 / (3 + 1)
        self.stc_slow_d_weighting = 2 / (5 + 1)
        self.stc_oscillator_d_weighting = 2 / (26+1)
        self.stc_oscillator_d_9_weighting = 2 / (9+1)

        self.stc_slow_oscillator_k_26_close_min_list = []
        self.stc_slow_oscillator_k_26_max_min_list = []

        self.stc_slow_oscillator_final = []
        ######################################################

        ########## 스토캐스틱 패스트 %K, %D ##########
        for i in range(0, 50):  # 현재 분의 STC_패스트 K, D 구하기
            for j in range(i, i + 5):
                self.close_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "현재가").strip()))
                max_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", j, "고가").strip()))
                min_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", j, "저가").strip()))

                self.nq_max_price_list.append(max_price_row_data)
                self.nq_min_price_list.append(min_price_row_data)

            self.close_price_first = self.close_price_row_data
            self.max_price_first = max(self.nq_max_price_list)
            self.min_price_first = min(self.nq_min_price_list)

            self.nq_max_price_list = []
            self.nq_min_price_list = []

            self.stc_fast_k_first = (self.close_price_first - self.min_price_first) / (self.max_price_first - self.min_price_first) * 100
            self.stc_fast_k_first = round(self.stc_fast_k_first, 2)  # 소수 셋째자리에서 반올림

            self.stc_fast_d_list.append(self.stc_fast_k_first)

        self.stc_fast_d_list_final = self.stc_fast_d_list[::-1]
        self.stc_fast_k = self.stc_fast_d_list_final[29]

        self.stc_fast_d_list = []

        for i in range(len(self.stc_fast_d_list_final)):
            if i == 0:
                self.stc_fast_d_first = self.stc_fast_d_list_final[i]
            elif i >= 1:
                self.stc_fast_d_second = (self.stc_fast_d_list_final[i] * self.stc_fast_k_weighting) + (self.stc_fast_d_first * (1 - self.stc_fast_k_weighting))
                self.stc_fast_d_first = self.stc_fast_d_second
                if i == 49:
                    self.stc_fast_d_0_ago = round(self.stc_fast_d_first, 2)  # 현재시간
                elif i == 48:
                    self.stc_fast_d_1_ago = round(self.stc_fast_d_first, 2)  # 1분전
                elif i == 47:
                    self.stc_fast_d_2_ago = round(self.stc_fast_d_first, 2)  # 2분전
                elif i == 46:
                    self.stc_fast_d_3_ago = round(self.stc_fast_d_first, 2)  # 3분전
                elif i == 45:
                    self.stc_fast_d_4_ago = round(self.stc_fast_d_first, 2)  # 4분전
                elif i == 44:
                    self.stc_fast_d_5_ago = round(self.stc_fast_d_first, 2)  # 5분전

        self.stc_fast_d_list_final = []

        self.stc_fast_k = round(self.stc_fast_k, 2)
        self.stc_fast_d = round(self.stc_fast_d_second, 2)

        # print(self.stc_fast_k)
        # print(self.stc_fast_d)

        ########## 스토캐스틱 슬로우 %K, %D ##########
        for i in range(0, 50):
            for j in range(i, i+5):  # 현재 분의 STC_슬로우 K, D 구하기 ///       stc_slow_k = ∑(현재가 - 최대값) / ∑(최대값 - 최소값)
                for k in range(j, j + 12):
                    self.close_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", j, "현재가").strip()))
                    max_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", k, "고가").strip()))
                    min_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", k, "저가").strip()))

                    self.nq_max_price_list.append(max_price_row_data)
                    self.nq_min_price_list.append(min_price_row_data)

                self.close_price_first = self.close_price_row_data
                self.max_price_first = max(self.nq_max_price_list)
                self.min_price_first = min(self.nq_min_price_list)

                self.nq_max_price_list = []
                self.nq_min_price_list = []

                self.price_first_close_min = self.close_price_first - self.min_price_first
                self.price_first_max_min = self.max_price_first - self.min_price_first

                self.stc_slow_k_list_close_min.append(self.price_first_close_min)
                self.stc_slow_k_list_max_min.append(self.price_first_max_min)

            self.stc_slow_k_first = sum(self.stc_slow_k_list_close_min)
            self.stc_slow_k_second = sum(self.stc_slow_k_list_max_min)

            self.stc_slow_k_list_close_min = []
            self.stc_slow_k_list_max_min = []

            self.stc_slow_k_third = self.stc_slow_k_first / self.stc_slow_k_second * 100
            self.stc_slow_k_third = round(self.stc_slow_k_third, 2)

            self.stc_slow_k_forth_list.append(self.stc_slow_k_third)
            if i == 0:
                self.stc_slow_k = self.stc_slow_k_forth_list[0]
            elif i == 1:
                self.stc_slow_k_1_ago = self.stc_slow_k_forth_list[1]

        self.stc_slow_d_list = self.stc_slow_k_forth_list[::-1]
        self.stc_slow_k_forth_list = []

        for i in range(0, 50):
            if i == 0:
                self.stc_slow_d_first = self.stc_slow_d_list[i]
            elif i >= 1:
                self.stc_slow_d_second = (self.stc_slow_d_list[i] * self.stc_slow_d_weighting) + (self.stc_slow_d_first * (1 - self.stc_slow_d_weighting))
                self.stc_slow_d_first = self.stc_slow_d_second
                if i == 49:
                    self.stc_slow_d_0_ago = round(self.stc_slow_d_first, 2)   # 현재시간
                elif i == 48:
                    self.stc_slow_d_1_ago = round(self.stc_slow_d_first, 2)   # 1분전
                elif i == 47:
                    self.stc_slow_d_2_ago = round(self.stc_slow_d_first, 2)   # 2분전
                elif i == 46:
                    self.stc_slow_d_3_ago = round(self.stc_slow_d_first, 2)   # 3분전
                elif i == 45:
                    self.stc_slow_d_4_ago = round(self.stc_slow_d_first, 2)   # 4분전
                elif i == 44:
                    self.stc_slow_d_5_ago = round(self.stc_slow_d_first, 2)   # 5분전

        self.stc_slow_d = round(self.stc_slow_d_first, 2)
        self.stc_slow_d_list = []

        # print(self.stc_slow_k)
        # print(self.stc_slow_d)

        ########## 스토캐스틱 오실레이터 ##########

        ### 오실레이터_fast_%D 구하기 ###
        for i in range(0, 150):  # 현재 분의 STC_오실레이터 구하기
            for j in range(i, i + 12):
                self.close_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", i, "현재가").strip()))
                max_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", j, "고가").strip()))
                min_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", j, "저가").strip()))

                self.nq_max_price_list.append(max_price_row_data)
                self.nq_min_price_list.append(min_price_row_data)

            self.close_price_first = self.close_price_row_data
            self.max_price_first = max(self.nq_max_price_list)
            self.min_price_first = min(self.nq_min_price_list)

            self.nq_max_price_list = []
            self.nq_min_price_list = []

            self.stc_fast_k_first = (self.close_price_first - self.min_price_first) / (self.max_price_first - self.min_price_first) * 100
            self.stc_fast_k_first = round(self.stc_fast_k_first, 2)  # 소수 셋째자리에서 반올림

            self.stc_fast_d_list.append(self.stc_fast_k_first)

        self.stc_fast_d_list_final = self.stc_fast_d_list[::-1]

        self.stc_fast_d_list = []

        for i in range(len(self.stc_fast_d_list_final)):
            if i == 0:
                self.stc_oscillator_d_first = self.stc_fast_d_list_final[i]
            elif i >= 1:
                self.stc_oscillator_d_second = (self.stc_fast_d_list_final[i] * self.stc_oscillator_d_weighting) + (self.stc_oscillator_d_first * (1 - self.stc_oscillator_d_weighting))
                self.stc_oscillator_d_first = self.stc_oscillator_d_second
                if i == 149:
                    self.stc_oscillator_fast_d_0_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 148:
                    self.stc_oscillator_fast_d_1_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 147:
                    self.stc_oscillator_fast_d_2_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 146:
                    self.stc_oscillator_fast_d_3_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 145:
                    self.stc_oscillator_fast_d_4_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 144:
                    self.stc_oscillator_fast_d_5_ago = round(self.stc_oscillator_d_first, 2)

        self.stc_fast_d_list_final = []

        self.stc_oscillator_fast_d = round(self.stc_oscillator_d_first, 2)      # 현재시간의 오실레이터_fast_d
        # print(self.stc_oscillator_fast_d)

        ### 오실레이터_slow_%D 구하기 ###
        for i in range(0, 150):
            for j in range(i, i+26):  # 현재 분의 STC_슬로우 K, D 구하기 ///       stc_slow_k = ∑(현재가 - 최대값) / ∑(최대값 - 최소값)
                for k in range(j, j + 12):
                    self.close_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", j, "현재가").strip()))
                    max_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", k, "고가").strip()))
                    min_price_row_data = abs(float(self.kiwoom.dynamicCall("GetCommData(QString,QString,int,QString)", "opc_10002", "opc10002", k, "저가").strip()))

                    self.nq_max_price_list.append(max_price_row_data)
                    self.nq_min_price_list.append(min_price_row_data)

                self.close_price_first = self.close_price_row_data
                self.max_price_first = max(self.nq_max_price_list)
                self.min_price_first = min(self.nq_min_price_list)

                self.nq_max_price_list = []
                self.nq_min_price_list = []

                self.price_first_close_min = self.close_price_first - self.min_price_first
                self.price_first_max_min = self.max_price_first - self.min_price_first

                self.stc_slow_k_list_close_min.append(self.price_first_close_min)
                self.stc_slow_k_list_max_min.append(self.price_first_max_min)

                self.stc_slow_k_first = sum(self.stc_slow_k_list_close_min)
                self.stc_slow_k_second = sum(self.stc_slow_k_list_max_min)

                self.stc_slow_k_list_close_min = []
                self.stc_slow_k_list_max_min = []

                self.stc_slow_oscillator_k_26_close_min_list.append(self.stc_slow_k_first)
                self.stc_slow_oscillator_k_26_max_min_list.append(self.stc_slow_k_second)

            self.stc_slow_oscillator_k_26_close_min_list = self.stc_slow_oscillator_k_26_close_min_list[::-1]
            self.stc_slow_oscillator_k_26_max_min_list = self.stc_slow_oscillator_k_26_max_min_list[::-1]

            self.stc_slow_oscillator_k_26_close_min = sum(self.stc_slow_oscillator_k_26_close_min_list)
            self.stc_slow_oscillator_k_26_max_min = sum(self.stc_slow_oscillator_k_26_max_min_list)

            self.stc_slow_oscillator_k_26_close_min_list = []
            self.stc_slow_oscillator_k_26_max_min_list = []

            self.stc_slow_oscillator_k_26 = self.stc_slow_oscillator_k_26_close_min / self.stc_slow_oscillator_k_26_max_min * 100
            self.stc_slow_oscillator_k_26 = round(self.stc_slow_oscillator_k_26, 2)

            self.stc_slow_oscillator_final.append(self.stc_slow_oscillator_k_26)

        self.stc_slow_oscillator_final = self.stc_slow_oscillator_final[::-1]

        for i in range(0, 150):
            if i == 0:
                self.stc_oscillator_d_first = self.stc_slow_oscillator_final[i]
            elif i >= 1:
                self.stc_oscillator_d_second = (self.stc_slow_oscillator_final[i] * self.stc_oscillator_d_9_weighting) + (self.stc_oscillator_d_first * (1 - self.stc_oscillator_d_9_weighting))
                self.stc_oscillator_d_first = self.stc_oscillator_d_second
                if i == 149:
                    self.stc_oscillator_slow_d_0_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 148:
                    self.stc_oscillator_slow_d_1_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 147:
                    self.stc_oscillator_slow_d_2_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 146:
                    self.stc_oscillator_slow_d_3_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 145:
                    self.stc_oscillator_slow_d_4_ago = round(self.stc_oscillator_d_first, 2)
                elif i == 144:
                    self.stc_oscillator_slow_d_5_ago = round(self.stc_oscillator_d_first, 2)

        self.stc_slow_oscillator_k = self.stc_slow_oscillator_final[99]     # 현재시간의 오실레이터_slow_k
        self.stc_slow_oscillator_final = []

        self.stc_oscillator_slow_d = round(self.stc_oscillator_d_first, 2)
        # print(self.stc_oscillator_slow_d)

        self.stc_oscillator_current = self.stc_oscillator_fast_d - self.stc_oscillator_slow_d       # 200줄, 262줄
        self.stc_oscillator_current = round(self.stc_oscillator_current, 2)      # 현재시간의 오실레이터_slow_d   ///  # 부동소수점 문제로 소수 셋째자리에서 반올림
        # print(self.stc_oscillator_current)

        self.stc_oscillator_0_ago = round(self.stc_oscillator_fast_d_0_ago - self.stc_oscillator_slow_d_0_ago, 2)
        self.stc_oscillator_1_ago = round(self.stc_oscillator_fast_d_1_ago - self.stc_oscillator_slow_d_1_ago, 2)
        self.stc_oscillator_2_ago = round(self.stc_oscillator_fast_d_2_ago - self.stc_oscillator_slow_d_2_ago, 2)
        self.stc_oscillator_3_ago = round(self.stc_oscillator_fast_d_3_ago - self.stc_oscillator_slow_d_3_ago, 2)
        self.stc_oscillator_4_ago = round(self.stc_oscillator_fast_d_4_ago - self.stc_oscillator_slow_d_4_ago, 2)
        self.stc_oscillator_5_ago = round(self.stc_oscillator_fast_d_5_ago - self.stc_oscillator_slow_d_5_ago, 2)

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

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

    app.exec_()

 


4. 마치며

볼린저밴드, macd, 스토캐스틱에 대한 설명을 끝으로 보조지표에 대한 설명을 마무리하려고 한다. 앞에서도 이야기했지만, 보조지표에 대해 구체적 설명을 해야하나... 수없이 고민을 했다. 그래서 한동안 글을 쓸 의욕이 떨어진 것도 사실이다. 그래도 자동매매 시스템에 대해 고민하고 있는 사용자들이 많을텐데, 이렇게 간략하게라도 언급을 해야 할 것 같다.

 

이번 글에서 400줄 이상이 추가되었다. 링크된 설명들을 천천히 읽어보면서, 보조지표가 만들어지는 원리 및 활용방법 등에 대해 제대로 숙지하자.

 

다음 글부터는 현재시간 알아보기, 시간별로 다른 코드 적용 등 시간 관리에 대해 알아보자.

 

반응형