대신증권 CYBOS PLUS 프로그램 구현 (18) - 전종목 차트 데이터 저장하기 ①
프로그램 구현 목표
- 전체 종목 차트 데이터 저장하는 버튼과 함수 만들고 연결하기
- 전체 종목 조회한 후 반복문으로 분봉 차트 데이터 조회하기
- 일봉 및 주봉 차트 데이터도 조회하기
전체 종목 차트 데이터 저장하는 버튼과 함수 만들고 연결하기
이제 GUI 파일을 열어서 버튼 하나 생성하는 것은 어렵지 않을 것이다. 아래와 같이 버튼을 하나 생성해주도록 하자.
이제 전체 종목 차트 데이터를 저장할 함수를 생성하고, 초기화 함수에서 버튼 객체와 함수를 연결해주도록 하자.
※ Line: 33 ~ 36
## Boss.py ##
import win32com.client
from pywinauto import application
import con_mysql
from COM import CpSysDib
from COM import CpUtil
from COM import CpTrade
from COM import DsCbo1
import time
from threading import Thread
## GUI ##
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from gui import qt_gui
main_ui = uic.loadUiType("main.ui")[0]
class cybos(QMainWindow, main_ui):
def __init__(self):
super().__init__()
self.setupUi(self)
self._open_cybosplus() ## 자동 로그인 함수
self._load_account() ## 계좌 조회 함수
self._load_DB() ## 데이터베이스 조회 함수
## GUI 관련 이벤트 처리 ##
self.pushButton.clicked.connect(self._GetStockListByMarket)
self.pushButton_2.clicked.connect(self._day_range)
self.pushButton_3.clicked.connect(self._len_chart)
self.comboBox_2.currentIndexChanged.connect(lambda: qt_gui.etc(self).comboBox_2_CIC())
self.pushButton_4.clicked.connect(self._save_all_chart)
def _save_all_chart(self):
pass
전체 종목 조회한 후 반복문으로 분봉 차트 데이터 조회하기
코스피와 코스닥 시장에 상장되어 있는 모든 종목 코드를 조회하는 함수는 이전에 작성해두었다.(`def _GetStockListByMarket`) 그렇다면 이제 이 함수를 활용하여 종목코드 목록을 받아와야 하는데, 이 함수를 자세히 보면 알겠지만 종목코드 목록을 `return`해주는 기능이 없기 때문에 종목코드를 조회하더라도 사용할 수가 없었다. 따라서 종목코드를 조회했으면 그 코드를 반환하도록 수정해보자.
※ Line: 10, 15
## Boss.py ##
def _GetStockListByMarket(self):
"""전체 종목코드 조회 함수"""
if self.comboBox.currentIndex() == 0:
kospi = CpUtil.CpCodeMgr()._GetStockListByMarket(1)
kosdaq = CpUtil.CpCodeMgr()._GetStockListByMarket(2)
itemcode_list = kospi + kosdaq
print(f"코스피:{len(kospi)} / 코스닥:{len(kosdaq)} / 전체:{len(itemcode_list)}")
print(f"종목코드:{itemcode_list}")
return itemcode_list
else:
market_kind = self.comboBox.currentIndex()
itemcode_list = CpUtil.CpCodeMgr()._GetStockListByMarket(market_kind_code=market_kind)
print(f"[요청한 데이터:{market_kind}] 종목코드:{itemcode_list}")
return itemcode_list
이제 다시 전종목 차트 데이터 조회 함수로 돌아와서 아래와 같이 종목코드를 얻어오도록 하자.
※ Line: 4
## Boss.py ##
def _save_all_chart(self):
"""전종목 차트 데이터 조회 후 저장하는 함수"""
all_code = self._GetStockListByMarket()
그 후에 `all_code` 안에 담겨 있는 모든 주식 종목을 대상으로 반복문을 통해 하나씩 조회하면서 차트 데이터를 조회하는 함수에 하나씩 전달해주면 되는데, 이 역시 `for`문을 통해 간단하게 생성할 수 있다. 아래의 코드와 같이 반복문을 추가한 후에, 프로그램을 실행시켜서 앞서 생성한 [전종목 차트 데이터 저장] 버튼을 클릭해보면 모든 종목의 종목코드를 하나씩 출력하는 것을 확인할 수 있다.
※ Line: 6, 7
## Boss.py ##
def _save_all_chart(self):
"""전종목 차트 데이터 조회 후 저장하는 함수"""
all_code = self._GetStockListByMarket()
for item_code in all_code:
print(item_code)
▶ 실행 결과 확인하기
[인자값:1] 종목코드 목록:('A000020' (이하 생략)
[인자값:2] 종목코드 목록:('A000250' (이하 생략)
코스피:2245 / 코스닥:1753 / 전체:3998
종목코드:('A000020', 'A000040', 'A000050', (이하 생략)
A000020
A000040
A000050
( 중략 )
A950190
A950200
A950220
이제 시장에 상장되어 있는 모든 종목코드를 대상으로 하나씩 조회하는 기능까지는 모두 구현했으니 이제 그 종목코드들을 가지고 차트 데이터를 조회하고 저장하도록 하면 된다. 하지만 지난 게시글에서 우리는 일봉 차트 데이터는 `save_gubun`를 인자로 전달받아 차트 데이터를 저장할지 말지를 결정할 수 있도록 하는 기능을 구현해두었는데, 분봉 차트 데이터는 그 기능을 구현하지 않았다. 따라서 분봉 차트 데이터를 일봉 차트 데이터와 같이 `save_gubun` 데이터를 전달받아 저장 여부를 판단할 수 있도록 하고, 저장해야 하는 경우(`save_gubun` 값이 True인 경우)에는 각각의 데이터베이스에 차트 데이터를 저장하도록 하는 기능을 추가하도록 하자.
※ Line: 3 ~ 4, 79 ~ 87
## CpSysDib.py ##
def chart_MT(self, item_code, request, quantity, cycle, save_gubun):
if not type(save_gubun) == bool:
return False
_df = {'date':[], 'hour':[], 'dhour':[], 'open':[], 'high':[], 'low':[], 'close':[], 'vol':[], 'tvol':[]}
self.stockchart.SetInputValue(0, item_code)
self.stockchart.SetInputValue(1, ord("2"))
self.stockchart.SetInputValue(4, quantity)
self.stockchart.SetInputValue(5, [0, 1, 2, 3, 4, 5, 8, 9])
self.stockchart.SetInputValue(6, ord(f"{request}")) ## 차트 구분("m", "T")
self.stockchart.SetInputValue(7, cycle) ## 분틱 주기(1, 3, 5, 10, 15 등등)
self.stockchart.SetInputValue(8, ord("0")) ## 갭 보정 여부(0: 보정 X, 1: 보정 O)
self.stockchart.SetInputValue(9, ord("0")) ## 수정주가 여부(0: 수정 X, 1: 수정 O)
self.stockchart.SetInputValue(10, ord("1")) ## 거래량 구분
self.stockchart.SetInputValue(11, ord("N")) ## 조기 적용 여부
self.handlers.set_instance(self.stockchart, "chart_MT")
self.stockchart.BlockRequest() ## 데이터 요청
len_fild = self.stockchart.GetHeaderValue(1) ## 요청한 필드 개수
array_fild = self.stockchart.GetHeaderValue(2) ## 팔드 배열
len_data = self.stockchart.GetHeaderValue(3) ## 데이터 개수 확인
# print(f"필드 개수:{len_fild}({array_fild}), 데이터 개수:{len_data}")
for index in range(len_data):
date = self.stockchart.GetDataValue(0, index) ## 0: 날짜, index: 인덱스 번호
hour = self.stockchart.GetDataValue(1, index) ## 1: 시간, index: 인덱스 번호
open = self.stockchart.GetDataValue(2, index) ## 2: 시가, index: 인덱스 번호
high = self.stockchart.GetDataValue(3, index) ## 3: 고가, index: 인덱스 번호
low = self.stockchart.GetDataValue(4, index) ## 4: 저가, index: 인덱스 번호
close = self.stockchart.GetDataValue(5, index) ## 5: 종가, index: 인덱스 번호
vol = self.stockchart.GetDataValue(6, index) ## 8: 거래량, index: 인덱스 번호
tvol = self.stockchart.GetDataValue(7, index) ## 9: 거래대금, index: 인덱스 번호
# print(f"[{date} {hour}] 시:{open}, 고:{high}, 저:{low}, 종:{close}, 거래:{vol}, 대금:{tvol}")
_df['date'].append(str(date))
_df['hour'].append(str(hour))
_df['dhour'].append(f"{str(date)}{str(hour)}")
_df['open'].append(open)
_df['high'].append(high)
_df['low'].append(low)
_df['close'].append(close)
_df['vol'].append(vol)
_df['tvol'].append(tvol)
while True:
if len(_df['date']) <= quantity: ## 아직 다 회신받지 못한 경우
if self.stockchart.Continue == 1: ## 추가 작업 수행
self.handlers.set_instance(self.stockchart, "chart_MT")
self.stockchart.BlockRequest() ## 데이터 요청
len_fild = self.stockchart.GetHeaderValue(1) ## 요청한 필드 개수
array_fild = self.stockchart.GetHeaderValue(2) ## 팔드 배열
len_data = self.stockchart.GetHeaderValue(3) ## 데이터 개수 확인
# print(f"필드 개수:{len_fild}({array_fild}), 데이터 개수:{len_data}")
for index in range(len_data):
date = self.stockchart.GetDataValue(0, index) ## 0: 날짜, index: 인덱스 번호
hour = self.stockchart.GetDataValue(1, index) ## 1: 시간, index: 인덱스 번호
open = self.stockchart.GetDataValue(2, index) ## 2: 시가, index: 인덱스 번호
high = self.stockchart.GetDataValue(3, index) ## 3: 고가, index: 인덱스 번호
low = self.stockchart.GetDataValue(4, index) ## 4: 저가, index: 인덱스 번호
close = self.stockchart.GetDataValue(5, index) ## 5: 종가, index: 인덱스 번호
vol = self.stockchart.GetDataValue(6, index) ## 8: 거래량, index: 인덱스 번호
tvol = self.stockchart.GetDataValue(7, index) ## 9: 거래대금, index: 인덱스 번호
# print(f"[{date} {hour}] 시:{open}, 고:{high}, 저:{low}, 종:{close}, 거래:{vol}, 대금:{tvol}")
_df['date'].append(str(date))
_df['hour'].append(str(hour))
_df['dhour'].append(f"{str(date)}{str(hour)}")
_df['open'].append(open)
_df['high'].append(high)
_df['low'].append(low)
_df['close'].append(close)
_df['vol'].append(vol)
_df['tvol'].append(tvol)
else: ## 데이터 조회 종료
break
else: ## 데이터 조회 종료(모두 회신받음)
break
chart_data = pd.DataFrame(_df, columns=['date', 'hour', 'dhour', 'open', 'high', 'low', 'close', 'vol', 'tvol']).iloc[:quantity]
if save_gubun: ## 이는 if save_gubun == True: 구문을 요약한 것이다.
if request == "m": ## 분봉 차트 저장
con_mysql.manage_db()._save_table(db_name=f'min{cycle}_data', table_name=f'{item_code.lower()}', table_data=chart_data)
elif request == "T": ## 틱봉 차트 저장
con_mysql.manage_db()._save_table(db_name=f'tick{cycle}_data', table_name=f'{item_code.lower()}', table_data=chart_data)
return chart_data
이 함수의 마지막 부분에서 차트 데이터를 저장하는 부분을 보면 `db_name`의 인자로 f'min{cycle}_data'를 전달하도록 하고 있는데, 이 부분이 바로 데이터베이스 이름이 된다. 여기서 `cycle`의 경우에는 분봉과 틱봉의 주기를 의미하는 것으로 3분봉을 조회할 경우에는 `cycle` 값은 3이 되고, 5분봉을 조회할 경우에는 5가 된다. 따라서 3분봉 데이터를 조회할 때에는 `db_name`의 인자로 전달하는 데이터베이스 이름은 자연스럽게 'min3_data'가 되고, 5분봉 데이터를 존재할 때에는 'min5_data'가 된다. 즉, 3분봉 데이터는 자동으로 'min3_data' 데이터베이스로 저장되고 5분봉 데이터는 자동으로 'min5_data' 데이터베이스로 저장된다는 것이다.
이제 다시 Boss.py 파일로 돌아와서, 분봉 차트 데이터를 먼저 조회하고 저장하도록 해보자. 아래의 코드 중 Line 4 부분을 보면 `data_len` 변수 값으로 1,000,000이라는 값을 넣어두었는데, 이 값은 차트 데이터를 조회할 때 전달할 '데이터 조회 개수'에 해당한다. 이 값은 특정 값보다 크게 설정하기만 하면 그보다 큰 값은 아무 의미가 없는게, 이미 우리는 차트 데이터 조회 함수 내부에서 "서버로부터 회신받을 데이터가 없으면 데이터 조회를 멈추도록 하는 기능"을 구현해두었기 때문이다. 다시 말해, 1,000,000이라는 값은 단순히 서버로부터 회신해줄 수 있는 모든 데이터를 회신하라는 의미를 갖는다고 보면 된다. 그 아래에 있는 `for` 구문의 내용은 아래의 코드를 잠고하도록 하자.
※ Line: 4, 7 ~ 11
def _save_all_chart(self):
"""전종목 차트 데이터 조회 후 저장하는 함수"""
all_code = self._GetStockListByMarket()
data_len = 1000000 ## 차트 데이터를 조회할 개수
for item_code in all_code:
print(f"조회 중인 종목코드:{item_code}")
print(f"5분봉 차트를 조회합니다.")
CpSysDib.StockChart().chart_MT(item_code, "m", data_len, 5, save_gubun=True) ## 5분봉 조회
print(f"15분봉 차트를 조회합니다.")
CpSysDib.StockChart().chart_MT(item_code, "m", data_len, 15, save_gubun=True) ## 15분봉 조회
▶ 실행 결과 확인하기(프로그램 실행 후 [전종목 차트 데이터 저장] 버튼 클릭)
[인자값:1] 종목코드 목록:('A000020' (이하 생략)
[인자값:2] 종목코드 목록:('A000250' (이하 생략)
코스피:2245 / 코스닥:1753 / 전체:3998
종목코드:('A000020', 'A000040', 'A000050', (이하 생략)
A000020
A000040
A000050
( 중략 )
A950190
A950200
A950220
조회 중인 종목코드:A000020
5분봉 차트를 조회합니다.
self.object:chart_MT
self.object:chart_MT
self.object:chart_MT
self.object:chart_MT
self.object:chart_MT
self.object:chart_MT
( 이하 생략 )
일봉 · 주봉 · 월봉 차트 데이터도 조회 및 저장하기
분봉 차트 데이터를 조회하고 저장하는 코드를 추가해준 것과 마찬가지로, 일봉 · 주봉 · 월봉 차트 데이터도 동일한 로직으로 한줄씩 코드를 추가해주면 된다. ([주의] 일봉 차트 데이터가 'test' 데이터베이스로 저장되는 경우 `def chart_DWM` 함수(CpSysDib.py 파일)의 끝 부분에 `db_name`이라는 인자에 전달한 데이터 저장 경로를 'test'에서 'day_data'로 변경해주셔야 합니다. )
※ Line: 12 ~ 17
def _save_all_chart(self):
"""전종목 차트 데이터 조회 후 저장하는 함수"""
all_code = self._GetStockListByMarket()
data_len = 1000000 ## 차트 데이터를 조회할 개수
for item_code in all_code:
print(f"조회 중인 종목코드:{item_code}")
print(f"5분봉 차트를 조회합니다.")
CpSysDib.StockChart().chart_MT(item_code, "m", data_len, 5, save_gubun=True) ## 5분봉 조회
print(f"15분봉 차트를 조회합니다.")
CpSysDib.StockChart().chart_MT(item_code, "m", data_len, 15, save_gubun=True) ## 15분봉 조회
print(f"일봉 차트를 조회합니다.")
CpSysDib.StockChart().chart_DWM(item_code, "D", data_len, save_gubun=True) ## 일봉 조회
print(f"주봉 차트를 조회합니다.")
CpSysDib.StockChart().chart_DWM(item_code, "W", data_len, save_gubun=True) ## 주봉 조회
print(f"월봉 차트를 조회합니다.")
CpSysDib.StockChart().chart_DWM(item_code, "M", data_len, save_gubun=True) ## 월봉 조회
'AUTO TRADE > [대신증권] CYBOS PLUS' 카테고리의 다른 글
대신증권 CYBOS PLUS 프로그램 구현 (20) - 전종목 차트 데이터 저장하기 ③ (0) | 2024.09.23 |
---|---|
대신증권 CYBOS PLUS 프로그램 구현 (19) - 전종목 차트 데이터 저장하기 ② (0) | 2024.09.21 |
대신증권 CYBOS PLUS 프로그램 구현 (17) - 데이터베이스 관리 자동화 (0) | 2024.09.18 |
대신증권 CYBOS PLUS 프로그램 구현 (16) - 차트 데이터 저장하기 ③ (2) | 2024.09.18 |
대신증권 CYBOS PLUS 프로그램 구현 (15) - 차트 데이터 저장하기 ② (2) | 2024.09.18 |
소중한 공감 감사합니다