PYTHON/AUTO TRADE SYSTEM

[자동 매매 시스템 구축하기] 알고리즘 구축하기 (3) - 조건검색식 사용하기 ③

  • -

지난 게시글에서 조건검색식을 생성하고, 해당 조건검색식에 의해 집계된 종목의 리스트를 얻어오는 기능까지 구현했다. 이번 게시글에서는 조회된 종목 코드 변수를 가지고 차트 데이터를 조회하고, 해당 차트 데이터를 기반으로 매수가와 매도가를 계산할 알고리즘을 어떻게 구현해야 하는지에 대해 살펴볼 예정이다.

 

 

버튼부터 만들어주자

아직 조건검색식을 사용할 수 있도록 하는 버튼이 존재하지 않는다. GUI 상에서 여러 기능들을 사용할 예정인데, 콤보 박스와 같은 전에는 사용하지 않았던 기능들이 추가될 예정이니 잘 따라오도록 하자. 가장 먼저 구현할 버튼은 서버로부터 조건검색식과 관련된 데이터를 시스템 내에 저장하는   def __getconditionload(self)  를 실행할 버튼이다.

조건검색식 조회 버튼은 pushButton_5라는 객체 이름으로 생성되었으며, def __init__(self) 하단에서 clicked 이벤트를 활용해서 함수와 연결해주면 된다.
※ Line : 19

class tradesystem(QMainWindow, form_class):
    def __init__(self):
        super().__init__()
        self.setupUi(self)  ## GUI 켜기
        self.setWindowTitle("주식 프로그램")  ## 프로그램 화면 이름 설정
        self.condition_list = {'index':[], 'name':[]}

        self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")  ## OpenAPI 시작
        self.kiwoom.dynamicCall("CommConnect()")  ## 로그인 요청

        self.setrealreg = _df.setrealreg()
        print(self.setrealreg)

        """데이터 요청 구간"""
        self.pushButton.clicked.connect(self.request_opt10016)
        self.pushButton_2.clicked.connect(self.request_opt10080)
        self.pushButton_3.clicked.connect(self._pushbtn_3)
        self.pushButton_4.clicked.connect(self._pushbtn_4)
        self.pushButton_5.clicked.connect(self.__getconditionload)

        """이벤트 처리 구간"""
        self.kiwoom.OnReceiveTrData.connect(self.receive_trdata)        ## 데이터 조회 요청 처리 함수
        self.kiwoom.OnEventConnect.connect(self.process_login)          ## 로그인 반환값 처리 함수
        self.kiwoom.OnReceiveRealData.connect(self.receive_realdata)    ## 실시간 데이터 수신 처리 함수
        self.kiwoom.OnReceiveConditionVer.connect(self.OnReceiveConditionVer)
        self.kiwoom.OnReceiveTrCondition.connect(self.OnReceiveTrCondition)
        self.kiwoom.OnReceiveRealCondition.connect(self.OnReceiveRealCondition)

 

 

 

comboBox 사용하기

이제 우리가 조회한 조건검색식의 조건검색식 명을 별도로 입력해줄 칸이 필요한데, 이는 comboBox를 이용해서 처리할 것이다. 콤보박스란 여러 개의 데이터를 리스트화하여 선택할 수 있도록 한 것으로, 조건검색식 리스트를 나타내기에는 이만한 객체가 없다.(comboBox의 객체 이름은 comboBox이다.)

콤보박스는 다양한 메서드를 사용할 수 있는데, 사실 하단부 네 개의 메서드만 알면 된다.

  • self.comboBox.addItem(DATA) : 콤보박스 내에 데이터(DATA)를 추가함
  • self.comboBox.removeItem(index) : 콤보박스 내 index에 해당하는 데이터를 삭제함
  • self.comboBox.currentText() : 콤보박스 내 활성화되어 있는 데이터 란의 텍스트 값을 얻어옴
  • self.comboBox.currentIndex() : 콤보박스 내 활성화되어 있는 데이터 란의 인덱스(index) 값을 얻어옴

그렇다면 여기서 콤보박스 내에 조건검색식의 이름을 입력해주는 기능을 구현할 것인데, 해당 기능은 조건검색식의 이름을 얻어오는 시점에 동작하도록 구현하면 된다. 그럼 현재 조건검색식의 이름 데이터를 얻어오는 지점은 어디일까? 바로 조건검색식 조회 결과로 발생하는   OnReceiveConditionVer   내에서   GetConditionNameList()   함수의 결과값이 담긴   condition_list   변수에 입력되어 있다. 그 시점에서 for문과 try:, except:문을 활용해   self.condition_list   변수 내에 조건검색식 명과 인덱스 번호를 입력해주었는데, self.condition_list 변수 내에 데이터를 입력하는 시점에서 comboBox 내에도 조건검색식 명을 입력하도록 하면 된다.
※ Line : 8

    """OnReceiveConditionVer 이벤트 처리"""
    def OnReceiveConditionVer(self):
        condition_list = self.kiwoom.dynamicCall("GetConditionNameList()").split(";")

        for data in condition_list:
            try:
                a = data.split("^")
                self.comboBox.addItem(a[1])
                self.condition_list['index'].append(str(a[0]))
                self.condition_list['name'].append(str(a[1]))
            except IndexError:
                pass

 

 

 


728x90

 

 

조건검색식이 찾아낸 종목 조회하기

종목을 조회하는 함수는 def __sendcondition(self, scrno, con_name, con_index, int) 함수였는데, 해당 함수를 조금 수정한 후에 버튼과 연결해주도록 하자. 변경점은 함수의 파라미터 중 scrno를 삭제한 후에 "0156"이라는 값을 자동적으로 입력하도록 했으며, 전달할 데이터를 리스트 형태로 전달해주도록 수정한 것이다.
※ Line : 13, 14

    ## 기존 함수
    def __sendcondition(self, scrno, con_name, con_index, int):
        result = self.kiwoom.dynamicCall("SendCondition(QString, QString, int, int)", scrno, con_name, con_index, int)
        ## 요청 이후의 결과 데이터는 OnReceiveTrCondition 또는 OnReceiveRealCondition으로 반환받음
    
        if result == 1:
            print("[조건검색] 조회요청 성공")
        if result != 1:
            print("[조건검색] 조회요청 실패")

    ## 변경 함수
    """SendCondition 함수 실행"""
    def __sendcondition(self, con_name, con_index, int):
        result = self.kiwoom.dynamicCall("SendCondition(QString, QString, int, int)", ["0156", con_name, con_index, int])
        ## 요청 이후의 결과 데이터는 OnReceiveTrCondition 또는 OnReceiveRealCondition으로 반환받음
    
        if result == 1:
            print("[조건검색] 조회요청 성공")
        if result != 1:
            print("[조건검색] 조회요청 실패")

 

이후 [조회]라는 버튼(객체명은 pushButton_6)을 새롭게 생성해서, 그 왼쪽의 comboBox 내에 입력된 조건검색식 명을 기반으로 해서 해당 조건검색식에 의해 집계된 종목 코드 데이터들을 불러오도록 할 것이다. 일단 pushButton_6와 함수를 연결해주도록 하자.
※ Line : 20

class tradesystem(QMainWindow, form_class):
    def __init__(self):
        super().__init__()
        self.setupUi(self)  ## GUI 켜기
        self.setWindowTitle("주식 프로그램")  ## 프로그램 화면 이름 설정
        self.condition_list = {'index':[], 'name':[]}

        self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")  ## OpenAPI 시작
        self.kiwoom.dynamicCall("CommConnect()")  ## 로그인 요청

        self.setrealreg = _df.setrealreg()
        print(self.setrealreg)

        """데이터 요청 구간"""
        self.pushButton.clicked.connect(self.request_opt10016)
        self.pushButton_2.clicked.connect(self.request_opt10080)
        self.pushButton_3.clicked.connect(self._pushbtn_3)
        self.pushButton_4.clicked.connect(self._pushbtn_4)
        self.pushButton_5.clicked.connect(self.__getconditionload)
        self.pushButton_6.clicked.connect(self._pushbtn_6)

        """이벤트 처리 구간"""
        self.kiwoom.OnReceiveTrData.connect(self.receive_trdata)        ## 데이터 조회 요청 처리 함수
        self.kiwoom.OnEventConnect.connect(self.process_login)          ## 로그인 반환값 처리 함수
        self.kiwoom.OnReceiveRealData.connect(self.receive_realdata)    ## 실시간 데이터 수신 처리 함수
        self.kiwoom.OnReceiveConditionVer.connect(self.OnReceiveConditionVer)
        self.kiwoom.OnReceiveTrCondition.connect(self.OnReceiveTrCondition)
        self.kiwoom.OnReceiveRealCondition.connect(self.OnReceiveRealCondition)

 

조건검색식에 의해 집계된 데이터를 확인하기 위해 사용해야 하는 함수는   def __sendcondition(self, con_name, con_index, int)  이며 우리는 사전에 조건검색식 이름을 comboBox 내에 입력했기 때문에 활성화되어 있는 조건검색식 명의 텍스트와 인덱스 번호를 얻어와야 한다. 다만 인덱스 번호는   comboBox.currentIndex()  가 아니라,   self.condition_list   변수 내에 있는   self.condition_list['index']   값을 전달해줘야 한다. 복잡해보이지만, 하나씩 구현해보도록 하자.

 

조건검색식 이름 얻어오기 (Line : 2)

    def _pushbtn_6(self):
        condition_name = self.comboBox.currentText()

 

조건검색식 인덱스 번호 얻어오기(Line : 4, 5)

    def _pushbtn_6(self):
        condition_name = self.comboBox.currentText()

        saved_idx = self.condition_list['name'].index(condition_name)
        condition_idx = self.condition_list['index'][saved_idx]

 

SendCondition 함수 실행하기 (Line : 7)

    def _pushbtn_6(self):
        condition_name = self.comboBox.currentText()
        
        saved_idx = self.condition_list['name'].index(condition_name)
        condition_idx = self.condition_list['index'][saved_idx]
        
        self.__sendcondition(condition_name, condition_idx, 0)

 

이제   def __sendcondition(self, con_name, con_index, int):  를 실행한 이후에는 int 값에 0이 전달되면   OnReceiveTrCondition   이벤트가, 1이 전달되면   OnReceiveRealCondition   이벤트가 발생하게 된다. 우리는 0을 전달해줬기 때문에   OnReceiveTrCondition   이벤트가 발생하게 되고, 이 이벤트의 발생과 연결되어 있는 함수 내에서는   self.code_list  라는 변수 내에 "우리가 요청한 조건검색기에 의해 집계된 종목 리스트"를 입력해서 반환하게 된다.

 

 


728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.