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

(키움증권 해외선물 자동매매 파이썬) 17. 시간별 다른 코드 적용하기

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

 

목 차
1. 들어가며
2. 사전설명
   1) 현재시간 출력
   2) 일정시간 코드 실행
   3) 시간 구분하는 방법
3. 코드설명
   1) 현재시간 출력하기
   2) 시간 구분하기
4. 전체코드
5. 마치며

 

1. 들어가며

지난 글에서는 "현재시간" 출력하는 방법을 알아보았다. 파이썬의 datetime 라이브러리를 활용하였고, 생각보다 코드가 간단하다는 것을 느꼈다.

 

이번 글에서는 시간별 다른 코드 적용하는 방법을 알아볼 것이다. 제목이 부담스러울 정도로 거창하긴 한데, "시간대별 다른 코드 적용"하는 코드도 간단하니, 부담없이 알아보도록 하자.

 


2. 사전설명

시간별로 다른 코드(알고리즘)을 적용하기 위해 우리가 알아야 할 3가지는 첫번째 현재시간 출력이며, 두번째는 일정시간마다 코드 실행, 마지막으로 "다른 시간"을 구분하는 코드를 구현할 수 있어야 한다.

 

1) 현재시간 출력

지난 글에서 설명하였으므로 여기서는 간단하게 설명한다. 자동매매에서 시간을 활용하려면, 당연히 현재시간을 출력할 줄 알아야 한다. 코드는 아래와 같다.

from datetime import datetime

def time_update():
    date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print(date_time)

time_update()

 

2) 일정시간 코드 실행

일정시간마다 코드를 실행하는 방법은 여러가지 있겠지만, 필자는 while 방법을 활용하고 있다. 예전에는 threading.Timer을 활용하여 실행하였다.

 ※ threading와 time을 이용하여 일정시간마다 반복 실행하기 : https://springcoming.tistory.com/22

 

threading.Timer를 사용하니 편하긴 했다. threading 명령어는 파이썬의 GIL을 회피하기 위해 공부했는데, 어쩌다가 Timer까지 알게되어서 코드에 적용하였다.

 

다만, threading.Timer는 "코드의 완료" 여부와는 상관없이 무조건 일정시간마다 진행되어서 필자의 자동매매에서 제외하였다. 지금은 while ~ time.sleep(초)를 활용하여 코드를 만들고 있다.

 

개인의 취향의 차이이다. threading.Timer를 이용해도 얼마든지 해외선물 자동매매를 만들어 볼 수도 있다고 생각한다.

 

3) 시간 구분하는 방법

"시간 구분"이 글의 핵심이다. 시간 구분은 무엇을 의미할까? 사람마다 다르겠지만, 필자는 미국장 개장(2230~0500)시간과 개장하지 않은 시간으로 나누고 있다. 서머타임 기준, 해선장은 0700~0600시까지 구분된다고 생각하고 글을 쓸 예정이다.

 

필자가 구현할 시간은 총 3가지로 이루어진다. (필자의 지극히 개인적인 시간 구분이다)

  • 07:00 ~ 22:30 : 미국장 개장하지 않은 거래시간이며, 거래량이 비교적 적음
  • 22:30 ~ 05:00 : 미국장 개장시간이며, 거래량이 많음
  • 05:00 ~ 06:00 : 미국장 끝난 시간이며, 거래량 비교적 적음

 


3. 코드설명

1) 현재시간 출력하기

지난 글에서 설명한 대로 현재시간을 출력해보자. 현재시간은 00:41분이다.

현재시간을 출력하는 코드는 아래와 같다.

from datetime import datetime

########## 시간별 패턴 구분을 위한 구분 함수 ###########
def time_pattern_gubun():
    now_time1 = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print(now_time1)
    now_time1 = now_time1[11:16]
    now_time2_t = now_time1[0:2]  # 시간 단위를 문자형으로 추출
    now_time3_m = now_time1[3:5]  # 분 단위를 문자형으로 추출

    now_time3 = now_time2_t + now_time3_m  # 분/초 단위를 하나로 붙임(문자형+문자형)
    now_time4 = int(now_time3)  # 문자형을 숫자형으로 변환
    now_time4 = now_time4  # 전역변수로 pl_check1에서 활용
    print(now_time1)

time_pattern_gubun()


### (expected result)
### 2023-10-22 00:41:33
### 00:41

 

1줄 : datetime의 라이브러리에서 datetime 명령어를 임포트한다.

4줄 : 현재시간을 출력하기 위해 함수를 선언한다.

5줄 : 연월일 시간분초를 now_time1 변수에 넣는다.

7줄 : 문자형인 now_time1변수(2022-10-22 00:41:33)의 11자리~16자리를 추출한다. 대괄호의 16자리의 콜론(:)은 포함되지 않는다.

 

8~9줄 : 7줄에서 뽑은 문자형(00:41) 중 시간(00시)과 분(41분)을 추출한다.

 

11줄 : 여기서 상당히 헤맸다. 이유는? 8줄과 9줄에서 받은 시간과 분의 태형(type)이 헷갈렸다. 00:41분에서 추출한 숫자는 모양만 숫자일뿐, 태형은 문자형(str)이다. 문자형과 문자형을 나란히 쓰기 위해 플러스(+)를 써준다.

 

※ 아래 < 접은글 >은 시간과 분의 태형(type)에 대한 내용이다.

 

더보기
from datetime import datetime

def time_pattern_gubun():
    now_time1 = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    now_time1 = now_time1[11:16]
    now_time2_t = now_time1[0:2]  # 시간 단위를 문자형으로 추출
    now_time3_m = now_time1[3:5]  # 분 단위를 문자형으로 추출

    print(now_time2_t)
    print(type(now_time2_t))

    print(now_time3_m)
    print(type(now_time3_m))

time_pattern_gubun()


### (expected result)
### 00
### <class 'str'>
### 56
### <class 'str'>

 

12줄 : 11줄에서 시간과 분의 문자형을 나란히 써준 결과('00' + '41' = '0041')를 숫자형(int)으로 바꾸어준다.

13줄 : 자동매매 코드에 써주기 위해 now_time4 앞에 self를 써준다. 여기서는 설명의 간략함을 위해 self를 생략하였다.

 

※ 현재시간이 00:41분일 때, 위의 코드를 실행하면 숫자형 41이 나온다는 것을 알 수 있다.

 

2) 시간 구분하기

예를 들어보자. 현재시간이 01:05분일 때, 위 코드로 실행하면 결과는 어떻게 될까? 문자형 01 + 문자형 05분이 더해진다. 결과값은 105가 된다. 이유는? 숫자로 0105는 존재할 수 없다. 105만 존재할 뿐이다.

 

24시간을 저렇게 나타낼 수 있다면, 어떤 결과를 생각할 수 있을까? 필자가 앞에서 설명하였듯이, 필자의 시간 구분은 3가지(0700~2230, 2230~0500, 0500~0600)으로 이루어진다고 했다. 이것을 숫자형 700~2230, 2230~500, 500~600으로 표기할 수 있다.

 

아래 코드는 5초마다 현재시간을 체크하여 시간대 별로 적용될 코드를 출력한다. 참고로 현재시간은 2023년 10월 22일 01:16분이다.

 

from datetime import datetime
import time

########## 시간별 패턴 구분을 위한 구분 함수 ###########
def time_pattern_gubun():
    now_time1 = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    now_time1 = now_time1[11:16]
    now_time2_t = now_time1[0:2]  # 시간 단위를 문자형으로 추출
    now_time3_m = now_time1[3:5]  # 분 단위를 문자형으로 추출

    now_time3 = now_time2_t + now_time3_m  # 분/초 단위를 하나로 붙임(문자형+문자형)
    now_time4 = int(now_time3)  # 문자형을 숫자형으로 변환

    if 700 <= now_time4 < 2230:
        print("700~2230 시간입니다")
    elif 500 <= now_time4 <= 600:
        print("500~600 시간입니다")
    else:
        print("2230~500 미국장 개장시간입니다.")

while True:
    time_pattern_gubun()
    time.sleep(5)
    

### (expected result)
### 2230~500 미국장 개장시간입니다.
### 2230~500 미국장 개장시간입니다.
### 2230~500 미국장 개장시간입니다.

 

여기서는 14줄~23줄을 설명할 것이다. 14~18줄을 확인해보자.

현재시간은 01:16분이다. 바로 위의 코드를 실행하면 12줄(int형)에 따라 숫자형 116이 출력된다.

14줄~18줄 중 18줄이 실행된다. 그래서 "2230~500 미국장 개장시간입니다"가 출력된다.

※ 여기서 잠깐! 2230~500을 else로 처리한 이유는?
14줄(700~2230) 및 16줄(500~600)은 논리상 부등호 표기가 가능하다.
그런데, 2230 < 현재시간 < 500이 논리적으로 맞을까? 2230 < 500은 논리적으로 맞지 않는다. 2230 > 500이 되어야 제대로된 수학적 표기일 것이다.

 


4. 전체코드

전체코드는 아래 < 접은글 >과 같다. 670줄~678줄이 추가되었다.

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

 

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

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) + 2       # 2를 더한 이유 : 순서가 0부터 시작한다. (2분전~35분까지를 알고 싶음, 2분전에 해당하는 숫자는 for(2, 36)에서 "2"는 0이므로, 0+2를 통해 "2분"을 나타냄)

        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) + 2

    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)

    ########## 시간 현행화 ###########
    def time_update(self):
        self.date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        self.traded_date = self.date_time[0:10]
        self.traded_time = self.date_time[11:19]

    ########## 시간별 패턴 구분을 위한 구분 함수 ###########
    def time_pattern_gubun(self):
        now_time1 = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        now_time1 = now_time1[11:16]
        now_time2_t = now_time1[0:2]  # 시간 단위를 문자형으로 추출
        now_time3_m = now_time1[3:5]  # 분 단위를 문자형으로 추출

        self.now_time3 = now_time2_t + now_time3_m  # 분/초 단위를 하나로 붙임(문자형+문자형)
        now_time4 = int(self.now_time3)  # 문자형을 숫자형으로 변환

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

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

    app.exec_()

 


5. 마치며

시간별 적용되는 코드를 달리하는 방법을 알아보았다. 지금은 이런 방법이 있다는 것만 알아두면 될 것 같다. 향후 알고리즘을 적용할 때 이 글(시간별 적용코드 구분)을 다시 설명할 예정이다.

 

다음 글에서는 진입과 청산을 시도하는 방법을 알아보자.

 

반응형