주식자동매매 51강. 실시간 자동매매 구현(11), 실시간 체결 정보 저장 및 GUI에 전시하기
본문 바로가기

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

주식자동매매 51강. 실시간 자동매매 구현(11), 실시간 체결 정보 저장 및 GUI에 전시하기

반응형

 50강에서는 실시간 체결 정보를 받아왔습니다. 받아온 데이터를 어딘가에는 저장 및 전시를 해야겠죠? 이번 강의에서는 싱글턴 스크립트 및 GUI에 관련 정보를 저장/전시하는 코딩을 해보겠습니다.

 

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

1. 실시간 체결 정보 저장

 아래 그림과 같이 메타클레스 싱글턴 스크립트에 self.not_account_stock_dict라는 딕셔너리를 만들어 실시간 체결 정보를 저장할 방을 만듭니다.

싱글턴 스크립트에 특정 변수 저장 객체 만들기
싱글턴 스크립트에 특정 변수 저장 객체 만들기

방을 만들었으면, QThread_3 스크립트로 넘어오셔서 50강에 이어 아래 그림과 같은 코드를 작성합니다.

 

 

 

 

 

실시간 체결 정보 저장하기
실시간 체결 정보 저장하기

 우선 self.not_account_stock_dict에 키 값으로 order_number를 저장합니다. 이전 self.portfolio_stock_dict에서는 키 값으로 종목 코드를 넣어 구분하였는데 체결 정보 구분 값으로는 order_number가 됩니다. 체결될 때마다 order_number가 넘어오니 우선  아래와 같이 self.not_account_stock_dict에 관련 값을 넣도록 합니다.

 - if order_number not in self.k.not_account_stock_dict.keys() :  not_account_stock_dict에 order_number라는 키값이 없으면 키 값을 아래와 같이 만들어 줍니다.

 - self.k.not_account_stock_dict.update({order_number: {}}) : not_account_stock_dict에 order_number라는 키값 아래 {}라는 딕셔너리를 생성합니다. 앞으로 이 {} 딕셔너리에 원하는 값을 넣도록 하겠습니다.

 

 KOA Studio를 기반으로 체결정보는 50강에서 설명드렸듯이  종목코드부터 (최우선) 매도호가까지 가져올 수 있습니다. 자 그러면  저희가 받아온 정보를 하나하나 다 not_account_stock_dict에 저장해야 겠죠?

 - self.k.not_account_stock_dict[order_number].update({"종목코드": sCode}) : not_account_stock_dict에 저장된 order_number에 종목코드를 업데이트합니다.

 위와 동일하게 (최우선)매도호가까지 다 저장하도록 합시다. 앞으로 어디서든 현재 미체결 잔고를 확인하기 위해서는 not_account_stock_dict를 살펴보면 됩니다. 여기까지는 개발자의 시각이고, 이제 누구든 미체결 잔고 내역을 확인할 수 있어야겠죠? 그러기 위해서는 앞서 많이 설명드린 TableWidget을 만들어 넣어 볼까요?

2. GUI 생성 및 관련 정보 저장

 우선 저번에 만들어 놓은 stocklistTableWidget_2 자리에 Tab Widget을 만들어 2개의 탭을 구성합니다. 그리고 currentTabText에 자신이 구분할 수 있는 이름을 적습니다. 저는 계좌 내역과 미체결 잔고라 구분했습니다. 그러면 계좌 내역 안에는 stocklistTableWidget_2을 집어넣고 미체결 잔고에는 새로운 QTableWidget을 집어넣도록 하겠습니다.

Tab Widget 만들기
Tab Widget 만들기

 그리고 아래와 같이 QTableWidget을 삽입합니다. objectName은 not_account라 하였습니다.

QTableWidget을 삽입
QTableWidget을 삽입

 다시 QThread_3로 넘어와 관련 정보들을 QTableWidget에 넣는 코딩을 해 줍니다. 이 부분은 너무 많이 진행하였으니 링크를 걸어 드리겠습니다. 22강 멀티 데이터 QTableWidget에 삽입하기 링크를 확인하세요.

멀티데이터 QTableWidget에 삽입
멀티데이터 QTableWidget에 삽입

 그래도 설명은 간략하게 드리겠습니다.

 - colum_head : 열의 개수를 정하며, 관련 데이터의 뜻을 이해하기 위해 반드시 넣으셔야 됩니다. 대략 6개만 샘플로 넣도록 하겠습니다. 본인이 원하는 값을 넣을 수 있으니 바꾸셔도 전혀 무방합니다.

 - colCount : 열의 개수이니 colum_head의 길이를 구하시면 되겠죠?

 - rowCount : 행의 개수이니 not_account_stock_dict에 들어 있는 종목의 수를 구하시면 되겠죠?

 - setColumCount(colCount) : 열의 개수를 세팅 합니다.

 - setRowCount(rowCount) : 행의 개수를 세팅합니다.

 - setHorizontalHeaderLabels(colum_head) : colum_head를 세팅합니다.

 - for index in range(rowCount) : 행의(종목의) 개수만큼 하나씩 index에 들어갑니다.

 - self.parent.not_account.setItem(index, 0, QTableWidgetItem(str(sCode))) : 우리가 만든 not_account TableWidget에 저장된 값을 삽입니다. index행에 0열, 1열, 2열... 6열까지 원하는 값을 QTableWidgetItem함수를 사용해서 넣도록 합니다.

 

 

 

 

 

3. 요약 및 코드 공개

 이번 강의는 미체결 잔고 내역에 대한 다양한 정보를 싱글턴 기반 스크립트의 not_account_stock_dict에 저장하거나 GUI를 생성하여 관련 값을 삽입하는 것을 배워 보았습니다. 다음 강의에서는 미체결에서 체결되었을 때 관련 정보를 가져와 보겠습니다. 대략 4강 정도만 더하면 기본 편은 끝날 것 같습니다. 이것만 끝나면 여러분들은 날개를 다시고 무엇이든 만드실 수 있을 것입니다. 감사합니다.

반응형

import os                                   # 현재 디렉토리 확인 기능
from PyQt5.QtCore import *                  # 쓰레드 함수를 불러온다.
from kiwoom import Kiwoom                   # 로그인을 위한 클래스
from kiwoomType import *
from PyQt5.QtWidgets import *      #PyQt 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()          # 매수 종목/금액/수량 가져오기
        self.orderitmelist_1 = [] # 중복 매수 금지
        self.orderitmelist_2 = [] # 중복 익절 금지
        self.orderitmelist_3 = [] # 중복 손절 금지
        self.orderitmelist_4 = [] # 중복 재매수 금지

        self.cancel_the_order = []

        ####### 주문 전송 시 필요한 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})


            ###############################################################
            ############# 실시간을 위한 조건문 구성하기 ########################
            ###############################################################


            #1. 매수 알고리즘 가동

            #1차#############################################################################################
            if self.k.portfolio_stock_dict[sCode]["현재가"] <= self.k.portfolio_stock_dict[sCode]["매수가"]:
                if sCode not in self.orderitmelist_1:

                    wa = []
                    wa.append(sCode)

                    if len(wa) > 1:
                        wa.clear()
                        pass
                    else:
                        print("매수 시작 %s" % sCode)

                        self.orderitmelist_1.append(sCode)  # 이 기법을 더이상 사용하지 못하게 하기
                        order_success1 = self.k.kiwoom.dynamicCall("SendOrder(QString, QString, QString ,int, QString, int, int, QString, QString)",
                                                                   ["신규매수", self.k.portfolio_stock_dict[sCode]['주문용스크린번호'], self.account_num, 1, sCode,
                                                                    self.k.portfolio_stock_dict[sCode]["매수수량"], self.k.portfolio_stock_dict[sCode]["현재가"],
                                                                    self.realType.SENDTYPE['거래구분']['지정가'], ""])

                        wf2 = open("dist/mesu_database.txt", "a", encoding="utf8")  # "a" 달아 쓴다. "w" 덮어 쓴다. files라느 파이썬 페키지 볼더를 만든다.
                        wf2.write("%s\t%s\t%s\t%s\n" % ("1매수정보", self.k.portfolio_stock_dict[sCode]["종목명"], b, self.k.portfolio_stock_dict[sCode]["채결시간"]))  # t는 tap을 의미한다.
                        wf2.close()

                        if order_success1 == 0:
                            print("최우선매수호가로 주문 전달 성공")
                        else:
                            print("최우선매수호가로 주문 전달 실패")



            #2. 매도 알고리즘 가동

            #1차 익절 #############################################################################################
            if self.k.portfolio_stock_dict[sCode]["현재가"] >= self.k.portfolio_stock_dict[sCode]["익절가"]:
                if sCode not in self.orderitmelist_2:

                    wa = []
                    wa.append(sCode)

                    if len(wa) > 1:
                        wa.clear()
                        pass
                    else:
                        print("익절 시작 %s" % sCode)

                        self.orderitmelist_2.append(sCode)  # 이 기법을 더이상 사용하지 못하게 하기
                        order_success2 = self.k.kiwoom.dynamicCall("SendOrder(QString, QString, QString ,int, QString, int, int, QString, QString)",
                                                                   ["신규익절", self.k.portfolio_stock_dict[sCode]['주문용스크린번호'], self.account_num, 2, sCode,
                                                                    self.k.portfolio_stock_dict[sCode]["매수수량"], self.k.portfolio_stock_dict[sCode]["현재가"],
                                                                    self.realType.SENDTYPE['거래구분']['지정가'], ""])

                        wf2 = open("dist/mesu_database.txt", "a", encoding="utf8")  # "a" 달아 쓴다. "w" 덮어 쓴다. files라느 파이썬 페키지 볼더를 만든다.
                        wf2.write("%s\t%s\t%s\t%s\n" % ("1익절정보", self.k.portfolio_stock_dict[sCode]["종목명"], b, self.k.portfolio_stock_dict[sCode]["채결시간"]))  # t는 tap을 의미한다.
                        wf2.close()

                        if order_success2 == 0:
                            print("익절가로 주문 전달 성공")
                        else:
                            print("익절가로 주문 전달 실패")

            #1차 손절 #############################################################################################
            if self.k.portfolio_stock_dict[sCode]["현재가"] <= self.k.portfolio_stock_dict[sCode]["손절가"]:
                if sCode not in self.orderitmelist_3:
                    wa = []
                    wa.append(sCode)

                    if len(wa) > 1:
                        wa.clear()
                        pass
                    else:
                        print("손절 시작 %s" % sCode)

                        self.orderitmelist_3.append(sCode)  # 이 기법을 더이상 사용하지 못하게 하기
                        order_success3 = self.k.kiwoom.dynamicCall("SendOrder(QString, QString, QString ,int, QString, int, int, QString, QString)",
                                                                   ["신규손절", self.k.portfolio_stock_dict[sCode]['주문용스크린번호'], self.account_num, 2, sCode,
                                                                    self.k.portfolio_stock_dict[sCode]["매수수량"], self.k.portfolio_stock_dict[sCode]["현재가"],
                                                                    self.realType.SENDTYPE['거래구분']['지정가'], ""])

                        wf2 = open("dist/mesu_database.txt", "a", encoding="utf8")  # "a" 달아 쓴다. "w" 덮어 쓴다. files라느 파이썬 페키지 볼더를 만든다.
                        wf2.write("%s\t%s\t%s\t%s\n" % ("1손절정보", self.k.portfolio_stock_dict[sCode]["종목명"], b, self.k.portfolio_stock_dict[sCode]["채결시간"]))  # t는 tap을 의미한다.
                        wf2.close()

                        if order_success3 == 0:
                            print("손절가로 주문 전달 성공")
                        else:
                            print("손절가로 주문 전달 실패")
            not_meme_list = list(self.k.not_account_stock_dict)  # 체결하지 않은 종목들을 실제 미체결 잔고에서 받아온다.

            #미체결 잔고 매수/매도 취소 #############################################################################################
            if len(self.k.not_account_stock_dict) > 0:

                for order_num in not_meme_list:  # not_meme_listnot_meme_list에는 주문번호가 들어가 있다.

                    code = self.k.not_account_stock_dict[order_num]["종목코드"]
                    meme_price = self.k.not_account_stock_dict[order_num]['주문가격']
                    not_quantity = self.k.not_account_stock_dict[order_num]['미체결수량']
                    order_gubun = self.k.not_account_stock_dict[order_num]['주문구분']

                    ##### 매수에 대한 취소 주문 : 주문가격이 최우선 매수호가보다 작을 경우

                    if order_gubun == "매수" and not_quantity > 0 and meme_price < self.k.portfolio_stock_dict[sCode]["현재가"]:

                        order_success = self.k.kiwoom.dynamicCall(
                            "SendOrder(QString, QString, QString ,int, QString, int, int, QString, QString)",
                            ["매수취소", self.k.portfolio_stock_dict[sCode]['주문용스크린번호'], self.account_num, 3, code, 0, 0,
                             self.realType.SENDTYPE['거래구분']['지정가'], order_num])  # order_num 은 어떤 주문을 취소할 것인가.

                        if order_success == 0:
                            print("%s 매수취소 전달 성공" % code)  # 체결잔고에서  del을 했기 때문에 여기서 하지 않는다.
                            self.cancel_the_order.append(code)  # 차 후 재매수를 위해 필요함
                        else:
                            print("%s 매수취소 전달 실패" % code)

                        wf2 = open("dist/chiso_database.txt", "a", encoding="utf8")  # "a" 달아 쓴다. "w" 덮어 쓴다. files라느 파이썬 페키지 볼더를 만든다.
                        wf2.write("%s\t%s\t%s\t%s\n" % ("매수취소", self.k.portfolio_stock_dict[sCode]["종목명"], not_quantity, self.k.portfolio_stock_dict[sCode]["채결시간"]))  # t는 tap을 의미한다.
                        wf2.close()

                    elif not_quantity == 0:
                        del self.k.not_account_stock_dict[order_num]


                    ##### 매도에 대한 취소 주문 : 주문가격이 최우선매도호가보다 클결우

                    elif order_gubun == "매도" and not_quantity > 0 and self.k.portfolio_stock_dict[sCode]["현재가"] < meme_price:

                        order_success = self.k.kiwoom.dynamicCall(
                            "SendOrder(QString, QString, QString ,int, QString, int, int, QString, QString)",
                            ["매도취소", self.k.portfolio_stock_dict[sCode]['주문용스크린번호'], self.account_num, 4, code, 0, 0,
                             self.realType.SENDTYPE['거래구분']['지정가'], order_num])  # order_num 은 어떤 주문을 취소할 것인가.

                        wf2 = open("dist/chiso_database.txt", "a",
                                   encoding="utf8")  # "a" 달아 쓴다. "w" 덮어 쓴다. files라느 파이썬 페키지 볼더를 만든다.
                        wf2.write("%s\t%s\t%s\t%s\n" % ("매도취소", self.k.portfolio_stock_dict[sCode]["종목명"], not_quantity,
                                                        self.k.portfolio_stock_dict[sCode]["채결시간"]))  # t는 tap을 의미한다.
                        wf2.close()

                        if order_success == 0:
                            print("%s 매도취소 전달 성공" % code)  # 체결잔고에서  del을 했기 때문에 여기서 하지 않는다.
                            self.cancel_the_order.append(code)  # 차 후 재매수를 위해 필요함

                        else:
                            print("%s 매도취소 전달 실패" % code)

                    elif not_quantity == 0:
                        del self.k.not_account_stock_dict[order_num]



            ########################
            # 5. 재 매수 알고리즘 : 현재가가 매수 되지 못하였을 경우를 대비하여 재 매수 알고리즘 가동
            ########################
            elif sCode in self.cancel_the_order:
                # 재매수#############################################################################################
                if self.k.portfolio_stock_dict[sCode]["현재가"] <= self.k.portfolio_stock_dict[sCode]["매수가"]:
                    if sCode not in self.orderitmelist_4:
                        wa = []
                        wa.append(sCode)

                        if len(wa) > 1:
                            wa.clear()
                            pass
                        else:
                            print("재매수 시작 %s" % sCode)

                            self.orderitmelist_4.append(sCode)  # 이 기법을 더이상 사용하지 못하게 하기
                            order_success3 = self.k.kiwoom.dynamicCall(
                                "SendOrder(QString, QString, QString ,int, QString, int, int, QString, QString)",
                                ["신규매수", self.k.portfolio_stock_dict[sCode]['주문용스크린번호'], self.account_num, 1, sCode,
                                 self.k.portfolio_stock_dict[sCode]["매수수량"], self.k.portfolio_stock_dict[sCode]["현재가"],
                                 self.realType.SENDTYPE['거래구분']['지정가'], ""])

                            wf2 = open("dist/mesu_database.txt", "a",
                                       encoding="utf8")  # "a" 달아 쓴다. "w" 덮어 쓴다. files라느 파이썬 페키지 볼더를 만든다.
                            wf2.write("%s\t%s\t%s\t%s\n" % ("재매수정보", self.k.portfolio_stock_dict[sCode]["종목명"], b,
                                                            self.k.portfolio_stock_dict[sCode][
                                                                "채결시간"]))  # t는 tap을 의미한다.
                            wf2.close()
                            if order_success3 == 0:
                                print("재매수 주문 전달 성공")
                            else:
                                print("재매수 주문 전달 실패")



    def chejan_slot(self, sGubun, nItemCnt, sFIdList):   # 주문전송 후 주문접수, 체결통보, 잔고통보를 수신

        if sGubun == "0":
            print("매수/매도 중입니다. 미체결 잔고 업데이트")
        else:
            print("미체결잔고 해결로 실제 잔고 업데이트")

        if int(sGubun) == 0:   # 주문전송 후 미체결 되었을 때 아래와 같은 연산을 해 준다.
            account_num = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['계좌번호'])
            sCode = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['종목코드'])[1:]  # [A203042]
            stock_name = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['종목명'])
            stock_name = stock_name.strip()  # 혹시라도 공백이 있을 까봐
            origin_order_number = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['원주문번호'])  # 원주문번호가 없으면 0000000이다
            order_number = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문번호'])
            order_status = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문상태'])  # 접수/확인/체결 정보
            order_quan = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문수량'])
            order_quan = int(order_quan)
            order_price = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문가격'])
            order_price = int(order_price)
            not_chegual_quan = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['미체결수량'])
            not_chegual_quan = int(not_chegual_quan)
            order_gubun = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문구분'])  # 정정 등, 부호가 나오기 때문에 잡아줘야 된다.
            order_gubun = order_gubun.lstrip('+').lstrip('-')
            order_gubun = order_gubun.strip()
            chegual_time_str = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문/체결시간'])  # '151028'
            chegual_price = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['체결가'])

            if chegual_price == '':
                chegual_price = 0  # 숫자로 할당
            else:
                chegual_price = int(chegual_price)

            chegual_quantity = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['체결량'])

            if chegual_quantity == '':
                chegual_quantity = 0
            else:
                chegual_quantity = int(chegual_quantity)

            current_price = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['현재가'])
            current_price = abs(int(current_price))
            first_sell_price = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['(최우선)매도호가'])
            first_sell_price = abs(int(first_sell_price))
            first_buy_price = self.k.kiwoom.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['(최우선)매수호가'])
            first_buy_price = abs(int(first_buy_price))

            # 새로운 주문의 미체결 주문번호(order_number)가 미체결잔고에 없을 경우 아래와 같이 미체결 잔고를 업데이트 한다.
            if order_number not in self.k.not_account_stock_dict.keys():
                self.k.not_account_stock_dict.update({order_number: {}})

            self.k.not_account_stock_dict[order_number].update({"종목코드": sCode})
            self.k.not_account_stock_dict[order_number].update({"종목명": stock_name})
            self.k.not_account_stock_dict[order_number].update({"주문번호": order_number})
            self.k.not_account_stock_dict[order_number].update({"주문상태": order_status})
            self.k.not_account_stock_dict[order_number].update({"주문수량": order_quan})
            self.k.not_account_stock_dict[order_number].update({"주문가격": order_price})
            self.k.not_account_stock_dict[order_number].update({"주문구분": order_gubun})
            self.k.not_account_stock_dict[order_number].update({"미체결수량": not_chegual_quan})
            self.k.not_account_stock_dict[order_number].update({"체결량": chegual_quantity})
            self.k.not_account_stock_dict[order_number].update({"원주문번호": origin_order_number})
            self.k.not_account_stock_dict[order_number].update({"주문/체결시간": chegual_time_str})
            self.k.not_account_stock_dict[order_number].update({"체결가": chegual_price})
            self.k.not_account_stock_dict[order_number].update({"현재가": current_price})
            self.k.not_account_stock_dict[order_number].update({"(최우선)매도호가": first_sell_price})
            self.k.not_account_stock_dict[order_number].update({"(최우선)매수호가": first_buy_price})

            column_head = ["종목코드", "종목명", "주문번호", "주문상태", "주문수량", "주문가격", "미체결수량"]
            colCount = len(column_head)
            rowCount = (len(self.k.not_account_stock_dict))
            self.parent.not_account.setColumnCount(colCount)                 # 행 갯수
            self.parent.not_account.setRowCount(rowCount)                    # 열 갯수 (종목 수)
            self.parent.not_account.setHorizontalHeaderLabels(column_head)   # 행의 이름 삽입

            for index in range(rowCount):
                self.parent.not_account.setItem(index, 0, QTableWidgetItem(str(sCode)))
                self.parent.not_account.setItem(index, 1, QTableWidgetItem(str(stock_name)))
                self.parent.not_account.setItem(index, 2, QTableWidgetItem(str(format(order_number))))
                self.parent.not_account.setItem(index, 3, QTableWidgetItem(str(format(order_status))))
                self.parent.not_account.setItem(index, 4, QTableWidgetItem(str(format(order_quan, ","))))
                self.parent.not_account.setItem(index, 5, QTableWidgetItem(str(format(order_price, ","))))
                self.parent.not_account.setItem(index, 6, QTableWidgetItem(str(format(not_chegual_quan, ","))))

            print("미체결잔고 종목 추가 %s 수량 %s" % (self.k.not_account_stock_dict[order_number]["종목명"], self.k.not_account_stock_dict[order_number]["미체결수량"]))
반응형

.link_tit