PYTHON/AUTO TRADE SYSTEM

[자동 매매 시스템 구축하기] 알고리즘 구축하기 (4) - 차트 데이터 요청하기

  • -

지난 게시글에서 조건검색기에 따른 종목 코드 리스트를 반환하도록 했으니, 이번 게시글에서는 self.code_list 변수 내에 입력되어 있는 종목코드를 기반으로 차트 데이터를 조회하도록 하는 기능을 구현해보자.

 

 

차트 데이터 조회 버튼 구현하기

현재 구현한 기능은 아래와 같은 3개이다.

  • [조건식 조회] (pushButton_5) → 서버에 저장되어 있는 조건검색식 리스트를 사용자 컴퓨터에 저장함
  • [콤보박스] (comboBox) → 조건검색식 정보를 comboBox 내에 차례차례 입력함
  • [조회] (pushButton_6) → comboBox 내 활성화된 조건검색식에 따라 집계된 종목코드를 조회함(self.code_list 생성)

이제 객체 이름을 pushButton_7로 하는 차트 데이터 조회 버튼을 생성한 후에, 이벤트로 연결해보도록 하자.


※ Line : 21

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.pushButton_7.clicked.connect(self._pushbtn_7)

        """이벤트 처리 구간"""
        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)

 

 

self.code_list 활용하기

이제 pushButton_7, 차트 조회 버튼을 누르면 self.code_list 변수를 호출해서 조건검색식에 의해 집계된 종목코드를 하나씩 조회하도록 하는 함수를 구현하면 된다. 주의해야 할 점이 있다면, 반드시 ①조건식 조회, ②조건식 설정, ③조회 버튼을 클릭하여 self.code_list가 생성된 후에 ④차트 조회 버튼을 눌러야 한다는 것이다.

앞전 세 단계가 이루어지지 않은 상태에서 차트 조회 버튼을 누르게 되면 self.code_list 변수가 생성되지 않았기 때문에 오류가 발생할 수 있다. 이 오류는 맨 마지막에 처리하는 것으로 하고, 지금은 self.code_list 변수를 대상으로 반복문을 통해 해당 조건검색식에 의해 집계된 종목 코드를 확인하는 정도만 구현하자.
※ Line : 3, 4

    def _pushbtn_7(self):

        for item_code in self.code_list:
            print(item_code)

 

 

item_code로 차트 데이터 조회하기

혹시 이전에 우리가 차트 데이터를 조회하기 위해 하나의 캡슐로 생성했던 함수가 기억나는가? 분봉 데이터를 조회하기 위해 생성했었는데, 이름은   def request_opt10080(self)  이다. 하지만 이 함수의 경우에는 별도의 파라미터를 지정하지 않았기 때문에, 사전에 입력해둔 종목코드 값인 "005930"에 대해서만 조회할 수 있도록 구현되어 있다. 그렇기 때문에 종목코드를 얻어서 차트 데이터를 조회할 수 있도록 함수를 조금 수정해주도록 하자.

수정하는 부분은 함수의 파라미터로 종목코드와 몇분봉을 조회할 것인지와 같은 틱 범위를 추가하고, 함수 내 코드에서도 기존에 입력되어 있던 "005930"이나 "30"을 각각 파라미터 인자로 대체하는 것이다.
※ Line : 2~5, 13~14, 23, 25

    """opt10080 : 분봉차트조회요청"""
    def request_opt10080(self, item_code, tick):
        self.chart_data = {'time':[], 'now':[], 'open':[], 'high':[], 'low':[]}
        self.__setinputvalue("종목코드", item_code)
        self.__setinputvalue("틱범위", tick)
        self.__setinputvalue("수정주가구분", "1")
        self.__commrqdata("분봉차트조회요청", "opt10080", 0, "0600")
        self.event_loop = QEventLoop()
        self.event_loop.exec_()
        time.sleep(0.5)

        while self.remained_data == True:
            self.__setinputvalue("종목코드", item_code)
            self.__setinputvalue("틱범위", tick)
            self.__setinputvalue("수정주가구분", "1")
            self.__commrqdata("분봉차트조회요청", "opt10080", 2, "0600")
            self.event_loop = QEventLoop()
            self.event_loop.exec_()
            time.sleep(0.5)

        chart_data = pd.DataFrame(self.chart_data, columns=['time', 'now', 'open', 'high', 'low'])
        print(chart_data)
        chart_data.to_sql(name="s005930", con=manage_db.engine_5min, index=False, if_exists='replace')
        print("차트데이터 저장이 완료되었습니다.")
        return chart_data

 

그 후 다시 돌아와서 for문 내에서   item_code   별로   def request_opt10080()  함수를 실행하도록 하면 된다.
※ Line : 4

    def _pushbtn_7(self):

        for item_code in self.code_list:
            min5_chart_data = self.request_opt10080(item_code, 5)

 

마지막으로, print()문을 활용해서 얻어온 차트 데이터를 출력해서 차트 데이터가 정상적으로 출력되는지 확인해보자.
※ Line : 11~13

    def _pushbtn_7(self):

        for item_code in self.code_list:
            min5_chart_data = self.request_opt10080(item_code, 5)
            print(min5_chart_data)

 

 

 


728x90

 

 

아 안되잖아요!!!

미처 깜빡하고   self.code_list   변수 데이터를 가공하지 못했다...!(통상적으로 데이터 전처리가 되지 않았다고 한다.) 조건검색식에 따른 데이터 요청 결과로 반환되는 codelist 변수는 종목 코드를 ';'를 기준으로 하여 전달해주는데, 이 ';'를 기준으로 종목 코드를 나눠주는 작업을 수행해야 한다. 그래서 for문을 쓸 수 있게 된다.

  • [처리 전] codelist : "005930;066570;000020"
  • [처리 후] codelist : ['005930', '066570', '000020']

이렇게 ';'를 기준으로 나누는 방법은 .split() 메서드를 사용하면 되는데, 메서드 내 파라미터로 분리하고자 하는 기준이 되는 문자열을 전달해주면 된다. 이 경우, .split(";")을 사용하면 되는 것이다.
※ Line : 3

    """OnReceiveTrCondition 이벤트 처리"""
    def OnReceiveTrCondition(self, scrno, codelist, con_name, con_index, next):
        self.code_list = codelist.split(";")

 

 

이제 다시 프로그램을 실행해서 ①조건식 조회 → ②조건식 선택 → ③조회 → ④차트 조회의 순으로 작업을 진행하면 아래와 같이 정상적으로 차트 데이터가 출력되는 점을 확인할 수 있다.

                 time     now    open    high     low
0      20220720153000  +15040  +15040  +15040  +15040
1      20220720151500  +15045  +15050  +15070  +15045
2      20220720151000  +15045  +15060  +15065  +15045
3      20220720150500  +15065  +15065  +15080  +15060
4      20220720150000  +15065  +15045  +15075  +15030
...               ...     ...     ...     ...     ...
20264  20210701092000  -29055  -29090  -29115  -29050
20265  20210701091500  -29085  -29090  -29100  -29055
20266  20210701091000  -29085  -29050  -29110  -29025
20267  20210701090500  -29055  -29115  -29145  -29045
20268  20210701090000  -29120  -29280  -29285  -29115

 

 

빈 데이터프레임도 출력되는데요?

이는 앞서 살펴봤던 codelist 변수를 ';'를 기준으로 데이터를 나누는 과정에 있어서 발생하는 문제로 인한 것이다. 예를 들어 codelist 값이 '005930;066570;'이라고 가정했을 때, 이를 .split(";")을 사용하게 되면 ['005930', '066570']이 아니라 ['005930', '066570', '']와 같이 맨 뒤에 비어 있는 칸이 하나가 더 입력된다.

따라서 이 부분은 차트 데이터를 요청하는 def _pushbtn_7 함수 내에서 item_code가 빈 데이터인지 아닌지를 구분하는 코드를 추가하면 해결할 수 있다.
※ Line : 4

    def _pushbtn_7(self):

        for item_code in self.code_list:
            if item_code != "":
                min5_chart_data = self.request_opt10080(item_code, 5)
                print(min5_chart_data)

 

 


728x90
반응형
Contents

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

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