본문 바로가기

글/코딩

[python][자동매매] 강의가 끝나고, 머릿속 정리 3. 계좌정보 불러오기 + Tr Data 불러오기

반응형

아직... 한참남았는데, 생각보다 분량이 많다 ㅠ

얼른 가보자...!

 

    def get_account_info(self):
        self.account_list = self.dynamicCall("GetLoginInfo(String)","ACCNO")
        self.account_num = self.account_list.split(';')[0]
        print("계좌 번호 : %s" % self.account_num)

    def detail_account_info(self):
        print("예수금을 요청하는 부분")
        self.dynamicCall("SetInputValue(String, String)","계좌번호",self.account_num)
        self.dynamicCall("SetInputValue(String, String)","비밀번호","0000")
        self.dynamicCall("SetInputValue(String, String)","비밀번호입력매체구분","00")
        self.dynamicCall("SetInputValue(String, String)","조회구분","2")
        self.dynamicCall("CommRqData(String, String, int, String)","예수금상세현황요청","opw00001","0",self.screen_my_info)
        # event loop : 명령을 처리하는 동안 다른 작업을 가능하게 하는 것, 병렬화
        self.detail_account_info_event_loop = QEventLoop() # 아랫줄과 함께, 2set는 명령마다 대기를 위해서 들어가야함
        self.detail_account_info_event_loop.exec_() #_exec()랑은 최신버전 차이

    def detail_account_mystock(self, sPrevNext="0"):
        print("계좌평가 잔고내역 요청")
        self.dynamicCall("SetInputValue(String, String)","계좌번호",self.account_num)
        self.dynamicCall("SetInputValue(String, String)","비밀번호","0000")
        self.dynamicCall("SetInputValue(String, String)","비밀번호입력매체구분","00")
        self.dynamicCall("SetInputValue(String, String)","조회구분","2")
        self.dynamicCall("CommRqData(String, String, int, String)","계좌평가잔고내역요청","opw00018",sPrevNext,self.screen_my_info)

#        self.detail_account_info_event_loop_2=QEventLoop()
        self.detail_account_info_event_loop.exec_()

    def not_concluded_account(self, sPrevNext="0"):
        print("미체결요청")
        self.dynamicCall("SetInputValue(QString, QString)","계좌번호",self.account_num)
        self.dynamicCall("SetInputValue(QString, QString)","체결구분","1")
        self.dynamicCall("SetInputValue(QString, QString)", "매매구분", "0")
        self.dynamicCall("CommRqData(String, String, int, String)","실시간미체결요청","opt10075",sPrevNext,self.screen_my_info)

        self.detail_account_info_event_loop.exec_()

Account 관련 함수들은 한번에 모아봤다.

 

get_account_info(self) 함수는 계좌번호를 가져온다.

계좌번호를 받아오고, 초기에 생성한 self.account_num 변수에 반환해주는 역할을 한다.

detail_account_info(self) 함수에서는 예수금을 가져온다.

CommRqData를 통해 data를 요청하는데, 이 data 수신을 대기하기위해 뒤에 event loop를 걸어준다.

detail_account_mystock(self, sPrevNext="0")함수는 계좌평가 잔고내력을 불러온다.

이 때, 함수의 인자인 PrevNext는 연속 조회 여부를 결정한다. (2이면 연속조회)

 not_concluded_account(self, sPrevNext="0") 함수는 미체결 요청 내역을 가져온다.
체결되지 않은 매매내력을 확인하는 함수이다.

 

 


사실 이런 자질구레한 함수 나열은 크게 중요하지 않다.

Tr data를 불러오는 여기부터는 좀 어려운 내용이었고, 실제로 많이 중요했는데 천천히 복기해봐야겠다.

 

def trdata_slot(self, sScrNo,  sRQName, sTrCode, sRecordName,sPrevNext):
    '''
    tr 요청을 받는 구역. Slot임!
    :param sScrNo: 스크린번호
    :param sRQName: 내가 요청했을 때 지은 이름
    :param sTrCode: 요청 id, tr코드
    :param sRecordName: 사용안함
    :param sPrevNext: 다음 페이지가 있는지
    :return:
    '''

    if sRQName == "예수금상세현황요청":
        deposit=self.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "예수금")
        print("예수금 %s" % deposit)
        print("예수금 형변환%s" % int(deposit))

        self.use_money=int(deposit)*self.use_money_percent #일부분만 사용하는 코드
        self.use_money=self.use_money/4



        ok_deposit=self.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "출금가능금액")
        print("출금가능금액  %s" % ok_deposit)
        print("출금가능금액 형변환 %s" % int(ok_deposit))

        self.detail_account_info_event_loop.exit()  # 도중에 빠짐

    elif sRQName == "계좌평가잔고내역요청":
        print("1")
        total_buy_money=self.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "총매입금액")
        total_buy_money_result = int(total_buy_money)

        print("총매입금액 %s" % total_buy_money_result)

        total_profit_loss_rate = self.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "총수익률(%)")
        total_profit_loss_rate_result=float(total_profit_loss_rate)

        print("총수익률(%%) %s" % total_profit_loss_rate_result)



        rows=self.dynamicCall("GetRepeatCnt(QString, QString)",sTrCode, sRQName) #GetRepeatCnt : 멀티데이터 조회 용도
        cnt=0
        for i in range(rows):
            code=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목번호")
            code=code.strip()[1:]
            code_name=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목명")
            stock_quantity=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "보유수량")
            buy_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매입가")
            learn_rate = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "수익률(%)")
            current_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가")
            total_chegual_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매입금액")
            possible_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매매가능수량")

            if code in self.account_stock_dict:
                pass
            else:
                self.account_stock_dict.update({code:{}})

            code_name=code_name.strip()
            stock_quantity=int(stock_quantity.strip())
            buy_price = int(buy_price.strip())
            learn_rate = float(learn_rate.strip())
            current_price = int(current_price.strip())
            total_chegual_price = int(total_chegual_price.strip())
            possible_quantity = int(possible_quantity.strip())

            self.account_stock_dict[code].update({"종목명":code_name})
            self.account_stock_dict[code].update({"보유수량":stock_quantity})
            self.account_stock_dict[code].update({"매입가":buy_price})
            self.account_stock_dict[code].update({"수익률(%)":learn_rate})
            self.account_stock_dict[code].update({"현재가":current_price})
            self.account_stock_dict[code].update({"매입금액":total_chegual_price})
            self.account_stock_dict[code].update({"매매가능수량":possible_quantity})

            cnt += 1

        print("계좌에 가지고 있는 종목 %s"% self.account_stock_dict)
        print("계좌 보유종목 카운트 %s"%cnt)

        if sPrevNext=="2":
            self.detail_account_mystock(sPrevNext="2")
        else:
            self.detail_account_info_event_loop.exit()

    elif sRQName == "실시간미체결요청":

        rows = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)  # GetRepeatCnt : 멀티데이터 조회 용도

        for i in range(rows):

            code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목코드")
            code_name=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목명")
            order_no=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "주문번호")
            order_status=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "주문상태")
            order_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "주문수량")
            order_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "주문가격")
            order_gubun = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "주문구분")
            not_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "미체결수량")
            ok_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "체결량")

            code=code.strip()
            code_name=code_name.strip()
            order_no=int(order_no.strip())
            order_status=int(order_status.strip())
            order_quantity = int(order_quantity.strip())
            order_price = float(order_price.strip())
            order_gubun = order_gubun.strip().lstrip('+').lstrip('-')
            not_quantity = int(not_quantity.strip())
            ok_quantity = int(ok_quantity.strip())

            if order_no in self.not_account_stock_dict:
                pass
            else:
                self.not_account_stock_dict[order_no]={}
            self.not_account_stock_dict[order_no].update({"종목코드":code})
            self.not_account_stock_dict[order_no].update({"종목명":code_name})
            self.not_account_stock_dict[order_no].update({"주문번호":order_no})
            self.not_account_stock_dict[order_no].update({"주문상태":order_status})
            self.not_account_stock_dict[order_no].update({"주문수량":order_quantity})
            self.not_account_stock_dict[order_no].update({"주문가격":order_price})
            self.not_account_stock_dict[order_no].update({"주문구분":order_gubun})
            self.not_account_stock_dict[order_no].update({"미체결수량":not_quantity})
            self.not_account_stock_dict[order_no].update({"체결량":ok_quantity})

            print("미체결 종목 :%s"%self.not_account_stock_dict[order_no])

        self.detail_account_info_event_loop.exit()
    elif sRQName=="주식일봉차트조회":
        #print("일봉데이터 요청")
        code=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "종목코드")
        code = code.strip()
        print("%s 일봉데이터 요청" % code)

        cnt=self.dynamicCall("GetRepeatCnt(QString, QString)",sTrCode,sRQName)
        print("데이터 일수 %s" % cnt)
        #data=self.dynamicCall("GetCommDataEx(QString, QString)", sTrCode,sRQName)
        #[['','현재가','거래량','거래대금','날짜','시가','고가','저가,''],['','현재가','거래량','거래대금','날짜','시가','고가','저가,''],...]]
        #600일치 데이터인 것 확인

        for i in range(cnt):

            data=[]

            current_price=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가")
            value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"거래량")
            trading_value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"거래대금")
            date = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"일자")
            start_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"시가")
            high_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"고가")
            low_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"저가")

            data.append("")
            data.append(current_price.strip())
            data.append(value.strip())
            data.append(trading_value.strip())
            data.append(date.strip())
            data.append(start_price.strip())
            data.append(high_price.strip())
            data.append(low_price.strip())
            data.append("")



            self.calcul_data.append(data.copy()) #위에 만들어줘야 하는 list

        if sPrevNext =="2":
            print(sPrevNext)
           # self.day_kiwoom_db(code=code, sPrevNext=sPrevNext) #재귀함수에서 오류나는것같음
        else:
            print("총 일 수%s" %len(self.calcul_data))
            #self.logging.logger.debug("총 일수 %s"% len(self.calcul_data))
            #120이평선을 그릴 만큼의 data가 있는지 check 필요
            pass_success = False
            if self.calcul_data == None or len(self.calcul_data)<120:
                pass_success=False
                print("check1")
            else:
                #120일 이상이면
                total_price=0
                for value in self.calcul_data[:120]: #[D,D-1,...,D-120]
                    total_price += int(value[1])

                moving_average_price=total_price/120

                #오늘 주가 120일 이평선에 걸쳐있는지 확인
                bottom_stock_price=False
                check_price=None

                if int(self.calcul_data[0][7]) <= moving_average_price and moving_average_price <= int(self.calcul_data[0][6]): #[0] : 오늘 [7] : 저가
                    print("오늘 주가 120이평선에 걸쳐있는 것 확인")
                    bottom_stock_price=True
                    check_price=int(self.calcul_data[0][6])

                #과거의 일봉들이 120일 이평선보다 밑에 있는지 확인,
                #그렇게 확인을 하다가 일봉이 120일 이평선보다 위에 있으면 계산 진행
                prev_price=None #과거의 일봉 저가

                if bottom_stock_price == True:
                    moving_average_price_prev=0
                    price_top_moving=False
                    idx=1
                    while True:
                        if len(self.calcul_data[idx:])<120:#최근부터 하루씩 거슬러올라가며 120일치 계속 있는지 확인
                            print("120일치 없음")
                            break
                        total_price=0
                        for value in self.calcul_data[idx:120+idx]:
                            total_price+=int(value[1])
                        moving_average_price_prev=total_price/120

                        if moving_average_price_prev <= int(self.calcul_data[idx][6]) and idx <= 20: # 20일정도는 아래여야되지않겠냐? 강의자가 만든거라함
                            print("20일동안 주가가 120일 이평선과 같거나 위에 있으면 조건 통과 못 함")
                            price_top_moving=False
                            break

                        elif int(self.calcul_data[idx][7]) > moving_average_price_prev and idx >20:
                            print("120일 이평선 위에 있는 일봉 확인 됨")
                            price_top_moving=True
                            prev_price=int(self.calcul_data[idx][7])
                            break
                        idx += 1


                    #해당부분 이평선이 가장 최근 일자의 이평선 가격보다 낮은지 확인
                    if price_top_moving == True:
                        if moving_average_price > moving_average_price_prev and check_price > prev_price:
                            print("포착된 이평선의 가격이 오늘자(최근일자) 이평선 가격보다 낮은 것 확인됨")
                            print("포착된 부분의 일봉 저가가 오늘자 일봉의 고가보다 낮은지 확인됨")
                            pass_success=True
            pass_success=True #삭제해야됨
            if pass_success==True:
                print("조건부 통과됨")
                code_nm = self.dynamicCall("GetMasterCodeName(QString)", code)
                f=open("files/condition_stock.txt","a",encoding="utf8")
                f.write("%s\t%s\t%s\n"%(code, code_nm, self.calcul_data[0][1]))
                f.close()

            elif pass_success == False:
                print("조건부 통과 못함")


            self.calcul_data.clear() #함수 초기화

            self.calculator_event_loop.exit()

        #print("cc")
        #rows=self.dynamicCall("GetCommData(QString,QString,int,QString)",sTrCode,sRQName)
        #print(rows) #None 오류 이것

        if sPrevNext=="2":
            self.day_kiwoom_db(code=code,sPrevNext=sPrevNext)
        else:
            self.calculator_event_loop.exit()

 

...양이 너무많다.

보기좋게 좀 줄여서 보자. 

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

    if sRQName == "예수금상세현황요청":
        deposit=self.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "예수금")
        self.use_money=int(deposit)*self.use_money_percent #일부분만 사용하는 코드
        self.use_money=self.use_money/4
        ok_deposit=self.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "출금가능금액")
        self.detail_account_info_event_loop.exit()  # 도중에 빠짐

    elif sRQName == "계좌평가잔고내역요청":
        total_buy_money=self.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "총매입금액")
        total_buy_money_result = int(total_buy_money)
        total_profit_loss_rate = self.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "총수익률(%)")
        total_profit_loss_rate_result=float(total_profit_loss_rate)
        rows=self.dynamicCall("GetRepeatCnt(QString, QString)",sTrCode, sRQName) #GetRepeatCnt : 멀티데이터 조회 용도
        cnt=0
        for i in range(rows):
            code=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목번호")
            code=code.strip()[1:]
            code_name=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목명")
			...
            possible_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매매가능수량")
            if code in self.account_stock_dict:
                pass
            else:
                self.account_stock_dict.update({code:{}})
            code_name=code_name.strip()
            stock_quantity=int(stock_quantity.strip())
            ...
            possible_quantity = int(possible_quantity.strip())
            self.account_stock_dict[code].update({"종목명":code_name})
            ...
            self.account_stock_dict[code].update({"매매가능수량":possible_quantity})
            cnt += 1
        if sPrevNext=="2":
            self.detail_account_mystock(sPrevNext="2")
        else:
            self.detail_account_info_event_loop.exit()

    elif sRQName == "실시간미체결요청":
        rows = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)  # GetRepeatCnt : 멀티데이터 조회 용도
        for i in range(rows):
            code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목코드")
            ...
            ok_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "체결량")

            code=code.strip()
            ...
            ok_quantity = int(ok_quantity.strip())

            if order_no in self.not_account_stock_dict:
                pass
            else:
                self.not_account_stock_dict[order_no]={}
            self.not_account_stock_dict[order_no].update({"종목코드":code})
            ...
            self.not_account_stock_dict[order_no].update({"체결량":ok_quantity})
        self.detail_account_info_event_loop.exit()
    elif sRQName=="주식일봉차트조회":
        code=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "종목코드")
        code = code.strip()
        cnt=self.dynamicCall("GetRepeatCnt(QString, QString)",sTrCode,sRQName)
        for i in range(cnt):
            data=[]
            current_price=self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가")
            ...
            low_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"저가")
            data.append("")
          	...
            data.append("")
            self.calcul_data.append(data.copy())
        if sPrevNext =="2":
            print(sPrevNext)
           # self.day_kiwoom_db(code=code, sPrevNext=sPrevNext)
        else:
            pass_success = False
            if self.calcul_data == None or len(self.calcul_data)<120:
                pass_success=False
                print("check1")
            else:
                total_price=0
                for value in self.calcul_data[:120]: #[D,D-1,...,D-120]
                    total_price += int(value[1])
                moving_average_price=total_price/120
                bottom_stock_price=False
                check_price=None
               [조건부]
            if pass_success==True:
                print("조건부 통과됨")
                code_nm = self.dynamicCall("GetMasterCodeName(QString)", code)
                f=open("files/condition_stock.txt","a",encoding="utf8")
                f.write("%s\t%s\t%s\n"%(code, code_nm, self.calcul_data[0][1]))
                f.close()

            elif pass_success == False:
                print("조건부 통과 못함")
            self.calcul_data.clear() #함수 초기화
            self.calculator_event_loop.exit()

        if sPrevNext=="2":
            self.day_kiwoom_db(code=code,sPrevNext=sPrevNext)
        else:
            self.calculator_event_loop.exit()

 

위의 trdata_slot(self, sScrNo,  sRQName, sTrCode, sRecordName,sPrevNext) 는 결국 우리가 요청하는 Request에 따라 요청을 받아오는 Slot이다.

sRQName의 인자로 예수금상세현황요청 / 계좌평가잔고내역요청 / 실시간미체결요청 / 주식일봉차트조회 등의 요청명을 받아서, 그 요청대로 호출하고 응답을 기다리는 slot이다.

호출한 뒤의 행동이 있기에 호출할때 사용된 event loop를 종료하는 event_loop.exit()로 각 명령이 마무리되며,

가장 중요한부분은... 주식일봉차트조회를 호출받아 실행하는 전략 구동부다. 

해당 부분의 전략을 수정해가면서 코드를 사용할 수 있는것이다!

 

 

 

반응형