주식자동매매 29강. 계좌관리하기 (6), opt10045 결과를 이용한 계좌 위험도 판단하기
본문 바로가기

주식 자동매매 강의/기초반(모든 코딩의 뿌리)

주식자동매매 29강. 계좌관리하기 (6), opt10045 결과를 이용한 계좌 위험도 판단하기

반응형

28강에서 opt10045 주문 전송 결과에 대하여 싱글데이터와 멀티데이터를 받아왔습니다. 멀티데이터 중 하나인 기관일별순매수량과 외국인일별순매수량 데이터를 분석하여 계좌 위험도를 판단해 보겠습니다.

[유튜브 강의, 링크]와 같이 보시면 많은 도움이 되실 겁니다.

1. 계좌위험도 판단 함수 만들기

아래 그림과 같이 28강에 연속으로 self.kigwan_meme_dong2() 함수를 실행시키는 문구를 코딩하였습니다. 그리고 함수안에 self.calcul2_data(기관일별순매매수량)과 self.calcul2_data3(외국인일별순매매수량)을 할당하여 두 정보를 가지고 계좌 위험도를 판단해 보겠습니다.

 

계좌위험도 판단 함수 만들기
계좌위험도 판단 함수 만들기

그리고 self.detail_account_info_event_loop.exit() 문구가 코딩되어 있는데 위의 계좌위험도 판단 함수가 종료되면 앞서 주문시 정의 했던 exec_를 종료해주는 역할을 합니다. 키움으로 전송된 명령이 다 수행되면 exec__를 종료하여 다음 코드가 진행되게 해야 겠죠?

2. 계좌위험도 판단 함수 코딩하기

계좌위험도 판단 함수 만들때 self.kigwan_meme_dong2(self.calcul2_data, self.calcul2_data3)를 할당해 주었기 때문에 def kigwan_meme_dong2() 함수에서는 def kigwan_meme_dong2(self, a, c)로 할당 받습니다.
a = self.calcul2_data, b = self.calcul2_data3라 생각하시면 됩니다. 그러면 우리는 10일치의 데이터가 있으나 저 같은 경우 4일치 데이터만 사용해서 계좌 위험도를 판단하기 위해 아래와 같이 코딩하였습니다. (1)을 참고하십시요.
- a = a[0:4]
- c = c[0:4]
- 파이썬의 경우 c[0:4]를 넣게되면 0, 1, 2, 3이 출력됩니다. 파이썬의 법칙이니 이해하시고 외우시면 될 것 같습니다.

계좌위험도 판단 함수 코딩하기
계좌위험도 판단 함수 코딩하기

위험도를 어떻게 판단했는지 알아 볼까요? 상당히 직관적으로 코딩하였습니다. (2)를 확인하십시요.
- 만약 4일치의 기관/외국인일별순매매수량이 음수(즉 전부 팔았을 때는)면 손절하라고 코딩하였습니다.
- 기관일별순매매수량이 [-3000, -2000, -5000, -4000] 이면 a[0] ~ a[3]까지 모두 0보다 작게 됩니다.
- 외국인일별순매매수량이 [-3000, -2000, -5000, -4000] 이면 a[0] ~ a[3]까지 모두 0보다 작게 됩니다.
- 이러한 조건이 맞춰지면 self.k.acc_portfolio의 현재 선택된 종목의 코드번호를 입력 후 "위험도": "손절" 이라고 저장되게 하였습니다.

if a[0] < 0 and a[1] < 0 and a[2] < 0 and a[3] < 0 and c[0] < 0 and c[1] < 0 and c[2] < 0 and c[3] < 0:
    self.k.acc_portfolio[self.code_in_all].update({"위험도": "손절"})

- 아래는 동일하게 코딩하시면 됩니다.
- 만약 3일치 기관/외국인일별순매매수량이 음수(즉 전부 팔았을 때는)면 주의라고 코딩하였습니다.
- 만약 2일치 기관/외국인일별순매매수량이 음수(즉 전부 팔았을 때는)면 관심이라고 코딩하였습니다.
- 그 외의 경우 (1일치 또는 0일치)에서는 위험도가 낮음이라고 코딩하였습니다.

다음 강의에서는 저장된 위험도 판단 데이터를 GUI에 입력하도록 하겠습니다. 이번강의는 정말 중요합니다. 여러분들은 다양한 데이터를 이렇게 응용해서 코딩하셔야 됩니다. 물론 이 데이터 만으로 손절 등을 판당하지는 않습니다. 더욱 많은 데이터들이 필요하죠. 우선적으로 이것만 이해하셔도 많은 발전이 있는 것입니다. 감사합니다.

반응형
from PyQt5.QtCore import *           # eventloop/스레드를 사용 할 수 있는 함수 가져옴.
from kiwoom import Kiwoom            # 로그인을 위한 클래스
from PyQt5.QtWidgets import *        # PyQt import
from PyQt5.QtTest import *           # 시간관련 함수
from datetime import datetime, timedelta    # 특정 일자를 조회


class Thread2(QThread):
    def __init__(self, parent):     # 부모의 윈도우 창을 가져올 수 있다.
        super().__init__(parent)    # 부모의 윈도우 창을 초기화 한다.
        self.parent = parent        # 부모의 윈도우를 사용하기 위한 조건

        ################## 키움서버 함수를 사용하기 위해서 kiwoom의 능력을 상속 받는다.
        self.k = Kiwoom()
        ################## 사용되는 변수
        self.Find_down_Screen = "1200"  # 계좌평가잔고내역을 받기위한 스크린
        self.code_in_all = None  # 1600개 코드 중 1개 코드, 쌓이지 않고 계속 갱신

        ###### 슬롯
        self.k.kiwoom.OnReceiveTrData.connect(self.trdata_slot)  # 내가 알고 있는 Tr 슬롯에다 특정 값을 던져 준다.

        ###### EventLoop
        self.detail_account_info_event_loop = QEventLoop()  # 계좌 이벤트루프

        ###### 기관외국인 평균가 가져오기
        self.C_K_F_class()


    def C_K_F_class(self):

        code_list = []

        for code in self.k.acc_portfolio.keys():
            code_list.append(code)

        print("계좌 종목 개수 %s" % (code_list))

        #self.parent.progressBar5.setMaximum(len(code_list) - 1) /차 후 설명 드리겠습니다.

        for idx, code in enumerate(code_list):
            #self.parent.progressBar5.setValue(idx) / 차 후 설명드리겠습니다.

            QTest.qWait(1000)

            self.k.kiwoom.dynamicCall("DisconnectRealData(QString)", self.Find_down_Screen)  # 해당 스크린을 끊고 다시 시작

            self.code_in_all = code  # 종목코드 선언 (중간에 코드 정보 받아오기 위해서)
            print("%s / %s : 종목 검사 중 코드이름 : %s." % (idx + 1, len(code_list), self.code_in_all))

            date_today = datetime.today().strftime("%Y%m%d")
            date_prev = datetime.today() - timedelta(10)  # 넉넉히 10일전의 데이터를 받아온다. 또는 20일이상 데이터도 필요
            date_prev = date_prev.strftime("%Y%m%d")

            self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", code)
            self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "시작일자", date_prev)
            self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종료일자", date_today)
            self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "기관추정단가구분", "1")
            self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "외인추정단가구분", "1")
            self.k.kiwoom.dynamicCall("CommRqData(String, String, int, String)", "종목별기관매매추이요청2", "opt10045", "0", self.Find_down_Screen)
            self.detail_account_info_event_loop.exec_()

    def kigwan_meme_dong2(self, a, c):  # a. 기관일별순매수량, b. 종가/기관/외국인 평균가, c. 외국인일별순매수량, d. 등락률

        a = a[0:4]
        c = c[0:4]
        print(a)
        # a = sum(a, [])
        # c = sum(c, [])



        if a[0] < 0 and a[1] < 0 and a[2] < 0 and a[3] < 0 and c[0] < 0 and c[1] < 0 and c[2] < 0 and c[3] < 0:
            self.k.acc_portfolio[self.code_in_all].update({"위험도": "손절"})

        elif a[0] < 0 and a[1] < 0 and a[2] < 0 and c[0] < 0 and c[1] < 0 and c[2] < 0:
            self.k.acc_portfolio[self.code_in_all].update({"위험도": "주의"})

        elif a[0] < 0 and a[1] < 0 and c[0] < 0 and c[1] < 0:
            self.k.acc_portfolio[self.code_in_all].update({"위험도": "관심"})

        else:
            self.k.acc_portfolio[self.code_in_all].update({"위험도": "낮음"})


    def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):

        if sRQName == "종목별기관매매추이요청2":

            cnt2 = self.k.kiwoom.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)  # 10일치 이상을 하려면 이부분에 10일치 이상데이터 필요

            self.calcul2_data = []
            self.calcul2_data2 = []
            self.calcul2_data3 = []
            self.calcul2_data4 = []

            for i in range(cnt2):  #

                Kigwan_meme = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, i, "기관일별순매매수량"))
                Kigwan_meme_ave = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "기관추정평균가"))
                Forgin_meme = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, i, "외인일별순매매수량"))
                Forgin_meme_ave = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "외인추정평균가"))
                percentage = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, i, "등락율"))
                Jongga = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, i, "종가"))

                self.calcul2_data.append(int(Kigwan_meme.strip()))
                self.calcul2_data2.append(abs(int(Jongga.strip())))
                self.calcul2_data2.append(abs(int(Kigwan_meme_ave.strip())))
                self.calcul2_data2.append(abs(int(Forgin_meme_ave.strip())))
                self.calcul2_data3.append(int(Forgin_meme.strip()))
                self.calcul2_data4.append(float(percentage.strip()))

                # 여기까지 code의 기관일별순매수량, 외국인일별순매수량, 기관/외국인 평균가, 등락률 정보가 나온다.
                # self.kigwan_meme_dong2(self.calcul2_data, self.calcul2_data2[0:3], self.calcul2_data3, self.calcul2_data4)

            self.kigwan_meme_dong2(self.calcul2_data, self.calcul2_data3)

            self.detail_account_info_event_loop.exit()

 

반응형

.link_tit