[자동 매매 시스템 구축하기] 알고리즘 구축하기 (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)
아 안되잖아요!!!
미처 깜빡하고 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)
'AUTO TRADE > 자동 매매 프로그램' 카테고리의 다른 글
[자동 매매 시스템 구축하기] 알고리즘 구축하기 (6) - 알고리즘 구현하기 ① (0) | 2022.07.21 |
---|---|
[자동 매매 시스템 구축하기] 알고리즘 구축하기 (5) - 알고리즘 파일 생성하기 (0) | 2022.07.20 |
[자동 매매 시스템 구축하기] 알고리즘 구축하기 (3) - 조건검색식 사용하기 ③ (0) | 2022.07.20 |
[자동 매매 시스템 구축하기] 알고리즘 구축하기 (2) - 조건검색식 사용하기 ② (0) | 2022.07.19 |
[자동 매매 시스템 구축하기] 알고리즘 구축하기 (1) - 조건검색식 사용하기 ① (0) | 2022.07.19 |
소중한 공감 감사합니다