주식자동매매 34강. 자동매매 종목 선정(3),현재가/신용비율 (opt10001, 주식기본정보요청)
본문 바로가기

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

주식자동매매 34강. 자동매매 종목 선정(3),현재가/신용비율 (opt10001, 주식기본정보요청)

반응형

33강에서는 입력 종목의 코드 번호와 종목 명을 Table Widget에 입력하는 법을 알아보겠습니다. 이번 강의에서는 opt10001을 통해 종목의 현재가 및 신용비율을 가져오도록 하겠습니다.

 

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

1.KOA Studio, opt10001 : 주식기본정보요청

 opt10001은 종목코드만 입력한다면 다양한 싱글 데이터를 받을 수 있습니다. 대표적으로 주식의 재무정보, 거래정보 등을 얻을 수 있죠. 여기서 우리는 종목의 현재가 및 신용비율을 받아오도록 하겠습니다.

opt10001 : 주식기본정보요청
opt10001 : 주식기본정보요청

 33강에서 설명드린 부분을 연장해서 계속 설명드리겠습니다. 아래 코드를 보시면

  - self.getItemInfo라는 opt10001을 실행하는 함수를 만들었고 이때, opt10001 명령을 보내기 위한 코드 번호 self.new_code도 같이 보내줍니다.

getItemInfo 함수 만들기
getItemInfo 함수 만들기

 

 - def getItemInfo(self, new_code) : getItemInfo라는 함수를 만들었으며, self.new_code에 입력된 코드번호를 new_code라는 지역 변수를 이용해 받아 옵니다.

 그리고 아래 KOA Studio를 살펴보면 SetInputValue로 명령을 세팅하고 CommRqData로 관련 내용을 서버로 전송합니다.

 - self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", new_code) : self.k를 이용해 메타 클래스에 접속(절대 언어) 후 kiwoom.dynamicCall을 이용해 명령을 전송할 준비를 합니다. 다음으로 SetInputValue를 하는데 입력되는 값이 QString으로 되어 있죠. QString은 숫자 외 모든 문자를 인식하게끔 하는 것이고 두 개의 QString에 종목코드와 new_code를 입력합니다.

 - self.k.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "주식기본정보요청", "opt10001", 0, "100") : 나머진 위와 동일하고 CommRqData로 키움 서버로 명령을 전송하는데 차 후에 Tr_slot에서 받을 RQName은 "주식기본정보요청" 이고 Open API에서 조회할 함수 이름은 "opt10001"입니다. 연속 조회는 아니기에 0이며, 화면번호는 "100"을 입력합니다. 

Open API, opt10001
Open API, opt10001

 위의 과정을 거치면 원하는 주식 코드에 대하여 주식기본정보요청하는 모든 행위는 마무리되었습니다. 이제 서버로 전송한 요청에 대한 결과를 받아와야겠죠?

 

2. 주식기본정보요청 받아오기 :  trdata_slot 만들기

 

 - 만약 sTrCode가 opt10001이고, sRQName이 "주식기본정보요청"이면 아래 문구를 수행합니다.

trdata_slot 만들기
trdata_slot 만들기

 - 다양한 데이터를 가져올 때는 GetCommData 함수를 사용합니다. 이때 필요한 정보는 sTrCode, sRQName, 연속조회여부, 원하는 값입니다. 현재가를 가져오기 위해 아래와 같은 코딩을 합니다.

 - currentPrice = abs(int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "현재가") : 위에서 설명하였듯이 현재가만 입력하면 currentPrice에 현재가를 입력합니다. 이때 int를 사용하여 현재가를 문자에서 숫자로 치환 후 혹시 +,-를 없애기 위해 절댓값(abs)을 취합니다.

 그리고 신용이 얼마나 있는지 확인하기 위해 원하는 값에 신용비율만 적으면 됩니다. 이때 strip()이라는 함수를 사용하는데  [               +3000] 이런 식으로 출력되는 값을 [+30000]으로 바꿔 공백을 없애 줍니다.

 - 다음으로 현재 buylast를 검색 후 행을 개수를 파악합니다.

 - row_count = self.buylast.rowCount()

 - 자 그러면 우리는 현재가와 신용비율 값을 모두 얻었습니다. 33강에서 만든 QTable Widget의 2열과 3열에 원하는 값을 넣도록 하겠습니다. 하나만 예를 들어보죠.

 - self.buylast.setItem(row_count - 1, 2, QTableWidgetItem(str(currentPrice))) :  row_count - 1이 아주 중요한데 -1을 해주는 이유는 앞서 buylast를 2행으로 만들어 줬습니다(1행 : 종목코드/종목명/현재가/신용비율, 2행 : 각 행 이름에 대응하는 값). 이때 setItem을 사용하여 특정 값을 입력할 때 1행은 무시되어 실제 개수보다 1개 적은 1행에 입력되게 해야 합니다. 

 - 1행 : 종목 코드 종목명 현재가 신용 비율

   2행 :   32132     삼성     4561     +300         실제 buylast는 2행이나 입력 시에는 <------ 여기가 1행입니다.

 혹시 이해가 어려우시면 차 후에 업로드되는 유튜브를 확인하시기 바랍니다. 

3. 주식기본정보요청 받아오기 코드 공개

 주식 기본정보 요처를 받아와서 입력되면 아래와 같은 GUI 화면이 최종적으로 생성 됩니다. 다음강의에서는 종목 삭제를 배워보도록 하겠습니다.

GUI 화면
GUI 화면

 아래는 메인 스크립트에 작성된 코드입니다.

반응형
import sys                        # system specific parameters and functions : 파이썬 스크립트 관리
from PyQt5.QtWidgets import *     # GUI의 그래픽적 요소를 제어       하단의 terminal 선택, activate py37_32,  pip install pyqt5,   전부다 y
from PyQt5 import uic             # ui 파일을 가져오기위한 함수
from PyQt5.QtCore import *        # eventloop/스레드를 사용 할 수 있는 함수 가져옴.

################# 부가 기능 수행(일꾼) #####################################
from kiwoom import Kiwoom          # 키움증권 함수/공용 방 (싱글턴)
from Qthread_1 import Thread1      # 계좌평가잔고내역 가져오기
from Qthread_2 import Thread2      # 계좌 관리

#=================== 프로그램 실행 프로그램 =========================#

form_class = uic.loadUiType("ALBA.ui")[0]             # 만들어 놓은 ui 불러오기

class Login_Machnine(QMainWindow, QWidget, form_class):       # QMainWindow : PyQt5에서 윈도우 생성시 필요한 함수

    def __init__(self, *args, **kwargs):                      # Main class의 self를 초기화 한다.

        print("Login Machine 실행합니다.")
        super(Login_Machnine, self).__init__(*args, **kwargs)
        form_class.__init__(self)                            # 상속 받은 from_class를 실행하기 위한 초기값(초기화)
        self.setUI()                                         # UI 초기값 셋업 반드시 필요

        ### 초기 셋팅
        self.label_11.setText(str("총매입금액"))
        self.label_12.setText(str("총평가금액"))
        self.label_13.setText(str("추정예탁자산"))
        self.label_14.setText(str("총평가손익금액"))
        self.label_15.setText(str("총수익률(%)"))


        #### 기타 함수
        self.login_event_loop = QEventLoop()  # 이때 QEventLoop()는 block 기능을 가지고 있다.

        ####키움증권 로그인 하기
        self.k = Kiwoom()                     # Kiwoom()을 실행하며 상속 받는다. Kiwoom()은 전지적인 아이다.
        self.set_signal_slot()                # 키움로그인을 위한 명령어 전송 시 받는 공간을 미리 생성한다.
        self.signal_login_commConnect()

        #####이벤트 생성 및 진행
        self.call_account.clicked.connect(self.c_acc)         # 계좌정보가져오기
        self.acc_manage.clicked.connect(self.a_manage)         # 계좌정보가져오기

        ################# 부가기능 1 : 종목선택하기 새로운 종목 추가 및 삭제
        self.k.kiwoom.OnReceiveTrData.connect(self.trdata_slot)           # 키움서버 데이터 받는 곳
        self.additmelast.clicked.connect(self.searchItem2)                # 종목 추가
        ####################

    def searchItem2(self):            # 종목추가시 사용됨.
        itemName = self.searchItemTextEdit2.toPlainText()
        if itemName != "":
            for code in self.k.All_Stock_Code.keys():  # 포트폴리오에 저장된 코드들을 실시간 등록
                # 주식체결 정보 가져오기(틱 데이터) : 현재가, 전일대비, 등락률, 매도호가, 매수호가, 거래량, 누적거래량, 고가, 시가, 저가
                if itemName == self.k.All_Stock_Code[code]['종목명']:
                    self.new_code = code

        column_head = ["종목코드", "종목명", "현재가", "신용비율"]
        colCount = len(column_head)
        row_count = self.buylast.rowCount()

        self.buylast.setColumnCount(colCount)  # 행 갯수
        self.buylast.setRowCount(row_count+1)  # colum_haed가 한 행을 잡아 먹는다. 실제 입력 되는 값은 1행 부터이다.
        self.buylast.setHorizontalHeaderLabels(column_head)  # 행의 이름 삽입

        self.buylast.setItem(row_count, 0, QTableWidgetItem(str(self.new_code))) # 실제 입력값은 1행부터이나 0부터 들어가야 된다.
        self.buylast.setItem(row_count, 1, QTableWidgetItem(str(itemName)))

        self.getItemInfo(self.new_code)



    def getItemInfo(self, new_code):
        self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", new_code)
        self.k.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "주식기본정보요청", "opt10001", 0, "100")

    def setUI(self):
        self.setupUi(self)                # UI 초기값 셋업

    def set_signal_slot(self):
        self.k.kiwoom.OnEventConnect.connect(self.login_slot)  # 내가 알고 있는 login_slot에다가 특정 값을 던져 준다.

    def signal_login_commConnect(self):
        self.k.kiwoom.dynamicCall("CommConnect()")  # 네트워크적 서버 응용프로그램에 데이터를 전송할 수 있게 만든 함수
        self.login_event_loop.exec_()  # 로그인이 완료될 때까지 계속 반복됨. 꺼지지 않음.

    def login_slot(self, errCode):
        if errCode == 0:
            print("로그인 성공")
            self.statusbar.showMessage("로그인 성공")
            self.get_account_info()                    # 로그인시 계좌정보 가져오기

        elif errCode == 100:
            print("사용자 정보교환 실패")
        elif errCode == 101:
            print("서버접속 실패")
        elif errCode == 102:
            print("버전처리 실패")
        self.login_event_loop.exit()  # 로그인이 완료되면 로그인 창을 닫는다.

    def get_account_info(self):
        account_list = self.k.kiwoom.dynamicCall("GetLoginInfo(String)", "ACCNO")

        for n in account_list.split(';'):
            self.accComboBox.addItem(n)

    def c_acc(self):
        print("선택 계좌 정보 가져오기")
        ##### 1번 일꾼 실행
        h1 = Thread1(self)
        h1.start()

    def a_manage(self):
        print("계좌 관리")
        h2 = Thread2(self)
        h2.start()

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

        if sTrCode == "opt10001":
            if sRQName == "주식기본정보요청":
                currentPrice = abs(int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "현재가")))
                D_R = (self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "신용비율")).strip()
                row_count = self.buylast.rowCount()
                self.buylast.setItem(row_count - 1, 2, QTableWidgetItem(str(currentPrice)))
                self.buylast.setItem(row_count - 1, 3, QTableWidgetItem(str(D_R)))



if __name__=='__main__':             # import된 것들을 실행시키지 않고 __main__에서 실행하는 것만 실행 시킨다.
                                     # 즉 import된 다른 함수의 코드를 이 화면에서 실행시키지 않겠다는 의미이다.

    app = QApplication(sys.argv)     # PyQt5로 실행할 파일명을 자동으로 설정, PyQt5에서 자동으로 프로그램 실행
    CH = Login_Machnine()            # Main 클래스 myApp으로 인스턴스화
    CH.show()                        # myApp에 있는 ui를 실행한다.
    app.exec_()                      # 이벤트 루프
반응형

.link_tit