주식자동매매 47강. 실시간 자동매매 구현(7), 실시간 주식체결 정보 가져오기(매우 중요)
본문 바로가기

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

주식자동매매 47강. 실시간 자동매매 구현(7), 실시간 주식체결 정보 가져오기(매우 중요)

반응형
반응형

46강에서는 실시간 장운영구분 데이터를 받아왔습니다. 이번 강의는 정말 중요한 부분을 다룰 것입니다. 바로 실사간 자동매매를 위한(매수/매도) 주식체결 정보를 가져오겠습니다.

 

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

1. 복습 : DB에 저장한 후 불어왔던 정보 확인

 43강에서 배웠다싶이 아래와 같은 정보를 DB 데이터에서 가져온거 기억 하시시죠?

 - portfolio_stock_dict에는 종목코드/종목명/현재가/신용비율/매수가/매수수량/익절가/손절가/주문용스크린번호를 입력하였습니다.

포트폴리오에 들어간 값들
포트폴리오에 들어간 값들

 앞으로 실시간 주식체결 정보를 가지고 오면 현재가와 매수가/손절가/익절가와 비교하여 매수/매도가 진행되게 할 것입니다.

 

 KOA Studio를 한번 더 확인해 보겠습니다. 주식을 체결하게 되면 총종목에 따라 총 20개의 데이터를 받아올 수 있습니다. 우리는 20개 중 12개의 데이터만 받아오는 코딩을 할 터인데 우선적으로 주식체결에 대한 개념을 한번 더 잡고 가겠습니다.

 

주식체결 데이터
주식체결 데이터

 

 아래 그림을 보시면 68100, 68200, 68300이 하나의 틱이며, 하나의 틱이 변화할 때 주식체결 데이터가 우리 컴퓨터로 넘어오게 됩니다. 만약 틱이 변하지 않고(계속 68200원에서 거래가 발생, 68200원의 잔량 1594개가 1개씩 소모) 거래가 발생하면, 우리는 주식체결에 대한 데이터를 받을 수 없습니다.

 다시 말씀드리지만 주식체결은 반드시 1개의 틱 정보가 변화할 때입니다.

주식체결의 틱
주식체결의 틱

 

2. 주식체결 데이터 받아오기 코딩

 

 만약 sRealType이 "주식체결"이고 protfolio_stock_dict에 sCode가 들어 있다면 아래 코드를 수행하게 됩니다. 그리고 관련 데이터를 받아올 때는 반드시 GetCommRealData 함수를 사용합니다. 46강에서 말씀드렸지만 self.realdata_slot에는 sCode와 sRealType이 넘어오게 됩니다.

 

주식체결 데이터 받아오기
주식체결 데이터 받아오기

 우선적으로 원하는 fid 번호를 가져온 후 GetCommRealData로 요청만 하시면 주식체결 때마다 원하는 값을 받을 수 있습니다.

 

 - fid1 = self.realType.REALTYPE[sRealType]["체결시간] : 체결시간에 대한 FID 번호를 가져옵니다. 잘 모르시겠다면 45강을 확인해 보시기 바랍니다.

 - a = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid1) : GetCommRealData함수를 이용해 체결 시간에 대한 정보를 받아와 a라는 객체에 저장합니다. 이때, sCode(주식코드번호)와 fid1(체결시간 fid 번호) 반드시 입력해야 합니다.

 

 위와 같은 형식으로 총 12개의 데이터를 받아옵니다. 받아오는 데이터는 아래와 같습니다.

 - 체결시간 : 차 후에 데이터 베스화 할 때 필요하겠죠?

 - 현재가 : 현재가를 이용하여 매수/매도를 수행할 것입니다.

 - 전일대비 : 전일대비 얼마큼 상승/하락했는지에 대한 가격이 출력되 매수/매도 시 또 하나의 지표가 될 수 있습니다.

 - 등락률 : 전일대비 얼만큼 상승/하락했는지에 대한 퍼센티지

 - 최우선 매도호가 : 최우선 매도호가에 매수를 넣게 되면 시장가와 동일하게 바로 매수됩니다.

 - 최우선 매수호가 : 최우선 매수호가에 매도를 넣게 되면 시장가와 동일하게 바로 매도됩니다.

 - 거래량 : 틱에 대한 거래량이므로 그렇게 중요? 한가 싶지만 일단 가져오겠습니다.

 - 누적거래량 : 누적거래량이 10만 이상일 때 또는 100만 이상일 대 매수해라 등의 기술들이 존재합니다.

 - 고가 : 오늘자 가장 높은 가격을 나타내고 있습니다. 저항선 등으로 사용할 수 있습니다.

 - 시가 : 오늘자 시작한 가격을 나타내고 있습니다.

 - 저가 : 오늘자 가장 낮은 가격을 나타내고 있습니다. 지지선 등으로 사용할 수 있습니다.

 - 거래회전율 : 누적거래 회전율로 이정보를 이용하면, 안정적인 급/등락 종목 매수/매도가 가능해집니다.

 

 위의 데이터들을 다 받아 왔으면, 어디서든 사용할 수 있게 저장을 해야겠죠? 그전에 우리가 입력하지 않은 정보들이 아주 가~끔(사용자든 서버의 문제든) 넘어올 때를 대비하여 에러가 날 수 있는 부분을 아래와 같이 해결합니다.

 

 - if sCode not in self.k.portfolio_stock_dict : 만약 portfolio_stock_dict에 넘어온 코드가 없다면, 에러가 발생할 수 있으니 아래와 같이 portfolio_stock_dict에 관련 코드를 이용해 하나의 방을 만들어 놓습니다.

 - self.k.portfolio_stock_dict.update({sCode : {}})

 

portfolio_stock_dict에 데이터 집어 넣기
portfolio_stock_dict에 데이터 집어 넣기

 

 딕셔너리 형태의 포트폴리오에 원하는 값을 넣는 많이 반복하였기에 숙달되었다고 생각합니다. 그래도 하나의 샘플에 대하여 설명드리겠습니다.

 - self.k.portfolio_stock_dict[sCode].update({"체결시간" : a}) : self.k를 이용해 메타 클래스 기반의 싱글턴에 접속 후 싱글턴에 존재하는 portfolio_stock_dict에 저장된 sCode에 "체결시간" : a라는 값을 저장합니다. 나머지도 다 동일합니다.

 

 위의 행위를 마치시면, 틱이 변할 때마다 주식체결 정보가 넘어오게 되고, 12가지의 데이터가 portfolio_stock_dict 에 저장되게 됩니다.

 복습에서 배웠듯이 기존의 portfolio_stock_dict에는  종목코드/종목명/현재가/신용비율/매수가/매수수량/익절가/손절가/주문용스크린번호 입력되어 있었죠? 틱이 변할 때마다 현재가가 업데이트되고 우리는 현재가와 익절가/손절가 등을 이용해 원하는 매수/매도를 다음 강의에서 진행할 것입니다.

 오늘 배웠던 것은 실시간 매수/매도에 매우 중요한 부분이므로 반드시 이해하시고 넘어가시면 되겠습니다.

 

3. 코드 공개

import os                                   # 현재 디렉토리 확인 기능
from PyQt5.QtCore import *                  # 쓰레드 함수를 불러온다.
from kiwoom import Kiwoom                   # 로그인을 위한 클래스
from kiwoomType import *


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

        ################## 키움서버 함수를 사용하기 위해서 kiwoom의 능력을 상속 받는다.
        self.k = Kiwoom()
        ##################

        ################## 사용되는 변수
        account = self.parent.accComboBox.currentText()  # 콤보박스 안에서 가져오는 부분
        self.account_num = account
        # 계좌번호 가져오는 부분은 Qthread_3 분리 시 로그인 후 계좌번호를 가져오는 함수로 교체된다. Lecture_0529.py


        ################# 매수관련 변수
        self.Load_code()         # 매수 종목/금액/수량 가져오기

        ####### 주문 전송 시 필요한 FID 번호
        self.realType = RealType()                # 실시간 FID 번호를 모아두는 곳

        ######################################################################
        ###### 등록된 계좌 전체 해제하기(작동 정지 되었을 때 등록 정보를 다 끊어야 한다.)
        self.k.kiwoom.dynamicCall("SetRealRemove(QString, QString)", ["ALL", "ALL"])
        ######################################################################

        ######################################################################
        ###### 선정된 종목 등록하기 : 키움서버에 리얼 데이터 등록하기

        self.screen_num = 5000

        for code in self.k.portfolio_stock_dict.keys():  # 포트폴리오에 저장된 코드들을 실시간 등록
            fids = self.realType.REALTYPE['주식체결']['체결시간']  # 주식체결에 대한 모든 데이터를 로드할 수 있다.
            self.k.kiwoom.dynamicCall("SetRealReg(QString, QString, QString, QString)", self.screen_num, code, fids, "1")  # 실시간 데이터를 받아오기 위해 각 코드들을 서버에 등록(틱 변화가 있으면 데이터 송신)
            self.screen_num += 1

                                                                                                                                  # print("실시간 등록 : %s, 스크린번호 : %s, FID  번호 : %s" % (code, screen_num, fids))
        print("종목등록 완료")
        print(self.k.portfolio_stock_dict.keys())


        ######################################################################
        ###### 현재 장 상태 알아보기 (장 시작 / 장 마감 등)
        self.screen_start_stop_real = "300"       # 장시 시작 전/후 상태 확인용 스크린 번호
        self.k.kiwoom.dynamicCall("SetRealReg(QString, QString, QString, QString)", self.screen_start_stop_real, '', self.realType.REALTYPE['장시작시간']['장운영구분'], "0")  # 장의 시작인지, 장 외인지등에 대한 정보 수신

        ###### 실시간 슬롯 (데이터를 받아오는 슬롯을 설정한다)
        self.k.kiwoom.OnReceiveRealData.connect(self.realdata_slot)   # 실시간 데이터를 받아오는 곳




        self.k.kiwoom.OnReceiveChejanData.connect(self.chejan_slot)   # (주문접수, 체결통보)=0, (잔고변경) = 1 데이터 전송




    def Load_code(self):

        if os.path.exists("dist/Selected_code.txt"):
            f = open("dist/Selected_code.txt", "r", encoding="utf8")
            lines = f.readlines()  # 여러 종목이 저장되어 있다면 모든 항목을 가져온다.
            screen = 4000
            for line in lines:
                if line != "":                     # 만약에 line이 비어 있지 않다면
                    ls = line.split("\t")  # \t(tap)로 구분을 지어 놓는다.
                    t_code = ls[0]
                    t_name = ls[1]
                    curren_price = ls[2]
                    dept = ls[3]
                    mesu = ls[4]
                    n_o_stock = ls[5]
                    profit = ls[6]
                    loss = ls[7].split("\n")[0]

                    self.k.portfolio_stock_dict.update({t_code: {"종목명": t_name}})
                    self.k.portfolio_stock_dict[t_code].update({"현재가": int(curren_price)})
                    self.k.portfolio_stock_dict[t_code].update({"신용비율": dept})
                    self.k.portfolio_stock_dict[t_code].update({"매수가": int(mesu)})
                    self.k.portfolio_stock_dict[t_code].update({"매수수량": int(n_o_stock)})
                    self.k.portfolio_stock_dict[t_code].update({"익절가": int(profit)})
                    self.k.portfolio_stock_dict[t_code].update({"손절가": int(loss)})
                    self.k.portfolio_stock_dict[t_code].update({"주문용스크린번호": screen})  # 아래 내용을 업데이트
                    screen += 1
            f.close()



    def realdata_slot(self, sCode, sRealType, sRealData):  # 실시간으로 서버에서 데이터들이 날라온다.

        if sRealType == "장시작시간":
            fid = self.realType.REALTYPE[sRealType]['장운영구분']

            # 실시간시세 데이터 수신 이벤트인 OnReceiveRealData() 가 발생될때 실시간데이터를 얻어오는 함수
            value = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid)

            if value == '0':
                print("장 시작 전")

            elif value == '3':
                print("장 시작")

            elif value == '2':
                print("장 종료, 동시호가로 넘어감감")

            elif value == '4':
                print("장 마감했습니다.")




        elif sRealType == "주식체결" and sCode in self.k.portfolio_stock_dict:


            fid1 = self.realType.REALTYPE[sRealType]['체결시간']  # 체결시간은 string으로 나온다. HHMMSS
            a = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid1)

            fid2 = self.realType.REALTYPE[sRealType]['현재가']  # 현재가는 +/-로 나온다.
            b = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid2)
            b = abs(int(b))

            fid3 = self.realType.REALTYPE[sRealType]['전일대비']  # 전달 대비 오르거나/내린 가격
            c = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid3)
            c = abs(int(c))

            fid4 = self.realType.REALTYPE[sRealType]['등락율']  # 전달 대비 오르거나/내린 퍼센테이지
            d = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid4)
            d = float(d)

            fid5 = self.realType.REALTYPE[sRealType]['(최우선)매도호가']  # 매도쪽에 첫번재 부분(시장가)
            e = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid5)
            e = abs(int(e))

            fid6 = self.realType.REALTYPE[sRealType]['(최우선)매수호가']  # 매수쪽에 첫번재 부분(시장가)
            f = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid6)
            f = abs(int(f))

            fid7 = self.realType.REALTYPE[sRealType]['거래량']  # 틱봉의 현재 거래량 (아주 작으 단위)
            g = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid7)
            g = abs(int(g))

            fid8 = self.realType.REALTYPE[sRealType]['누적거래량']
            h = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid8)
            h = abs(int(h))

            fid9 = self.realType.REALTYPE[sRealType]['고가']  # 오늘자 재일 높은 가격
            i = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid9)
            i = abs(int(i))

            fid10 = self.realType.REALTYPE[sRealType]['시가']  # 시가
            j = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid10)
            j = abs(int(j))

            fid11 = self.realType.REALTYPE[sRealType]['저가']  # 전체 재일 낮은 가격
            k = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid11)
            k = abs(int(k))

            fid12 = self.realType.REALTYPE[sRealType]['거래회전율']  # 누적 거래회전율
            l = self.k.kiwoom.dynamicCall("GetCommRealData(QString, int)", sCode, fid12)
            l = abs(float(l))

            if sCode not in self.k.portfolio_stock_dict:           # 만약 서버에 등록된 코드가 포트폴리오에 없다면 코드를 등록
                self.k.portfolio_stock_dict.update({sCode: {}})

            # 포트폴리오 종목코드마다 아래 실시간 데이터를 입력
            self.k.portfolio_stock_dict[sCode].update({"채결시간": a})       # 아래 내용을 업데이트
            self.k.portfolio_stock_dict[sCode].update({"현재가": b})
            self.k.portfolio_stock_dict[sCode].update({"전일대비": c})
            self.k.portfolio_stock_dict[sCode].update({"등락율": d})
            self.k.portfolio_stock_dict[sCode].update({"(최우선)매도호가": e})
            self.k.portfolio_stock_dict[sCode].update({"(최우선)매수호가": f})
            self.k.portfolio_stock_dict[sCode].update({"거래량": g})
            self.k.portfolio_stock_dict[sCode].update({"누적거래량": h})
            self.k.portfolio_stock_dict[sCode].update({"고가": i})
            self.k.portfolio_stock_dict[sCode].update({"시가": j})
            self.k.portfolio_stock_dict[sCode].update({"저가": k})
            self.k.portfolio_stock_dict[sCode].update({"거래회전율": l})
반응형

.link_tit