AUTO TRADE/[대신증권] CYBOS PLUS

대신증권 CYBOS PLUS 프로그램 구현 (10) - 일봉 차트 조회 : 연속 조회 사용하기 ①

  • 조회 횟수당 최대로 조회할 수 있는 데이터 확인해보기
  • Continue 속성 활용하여 이해하기
  • 개수 비교 로직 추가하기
  • 연속 조회 구현하기

 

이전에 만들어둔 프로그램을 실행시켜서 조회 개수 란에 3,000을 입력한 후 데이터를 조회해보면, 서버로부터 회신되는 데이터의 개수는 2,856개밖에 되지 않는다는 사실을 확인할 수 있다. 그렇다면 요청하고자 하는 차트 데이터의 유형에 따라 각각의 유형에 대하여 각기 다른 제한된 데이터 개수가 지정되어 있을까 ? 결론부터 이야기하자면, 일봉이든 주봉이든 분봉이든 틱봉이든 간에 2,856개의 데이터를 한도로 하여 데이터를 회신해준다. 그렇다면 결국에는 2,856개의 데이터가 회신된 후에 우리가 요청하고도 돌려받지 못한 144개의 데이터를 추가로 요청해야 되는데, 이 때 활용해야 하는 정보가 바로 COM의 Continue 속성이다.

이전까지는 우리가 일봉  차트 데이터를 조회할 때, 데이터 회신 제한 개수인 2,856개보다 적은 5개의 데이터만 조회했기 때문에 아무런 문제가 발생하지 않았지만 이보다 큰 5,000개나 10,000개의 데이터를 조회할 때에는 서버로부터 올바른 수량의 데이터를 회신받지 못하는 문제가 발생하게 된다. 따라서 여기서 우리가 서버로 요청한 데이터의 개수(위의 경우 3,000개)와 서버로부터 회신 받은 데이터의 개수(위의 경우에는 2,856개)를 서로 비교하는 로직을 추가해주어야 하는데, 조금 더 구체적으로 살펴보자면 '서버로부터 회신 받은 데이터의 개수를 누적시켜서 우리가 서버로 요청한 데이터의 개수와 같아졌는지'를 확인해주어야 한다.

 

 

앞서 언급했던 Continue 속성이란, 단순하게 '아직 추가적으로 조회할 수 있는 데이터가 있는지'를 회신해주는 속성이다. 이 속성은 추가적으로 조회할 수 있는 데이터가 있다면 "1"을 반환해주고 없다면 데이터를 반환해주지 않는다. 여기서 오해하지 않아야 하는 부분이 하나 있는데 여기서 "추가적으로 조회할 수 있는 데이터가 있는지"라는 개념의 기준이 우리가 서버에 요청한 '데이터의 개수'에 있지 않고 그 종목의 전체 '차트 데이터의 개수'에 있다는 것이다.

예를 들어, 서버에 3,000개의 데이터를 요청했을 때에는 서버에서는 당연히 2,856개의 데이터만 회신해줄 것이고 우리는 144개의 데이터를 추가로 요청해야 하므로 Continue 속성으로 반환된 "1"이라는 데이터를 가지고 서버에 재요청을 할 수 있다. 하지만 반대로 서버에 1,000개의 데이터를 요청했을 때에는 서버에서는 2,856개보다 적은 데이터를 요청했으므로 1,000개의 데이터만 전달해주지만, 그와 동시에 그 종목의 일봉 차트 데이터로 조회할 수 있는 데이터가 있으므로 Continue 속성으로 "1"이라는 데이터를 전달해주면서 '추가적으로 조회할 수 있는 데이터가 있음'이라는 신호를 전달해준다.

그렇다면 우리는 어떤 정보를 기준으로 서버에 데이터를 다시 요청할 수 있을까 ? Continue 속성은 반드시 활용해야 하는 것은 맞다. 왜냐하면 서버로부터 데이터를 회신해줄 근거가 없다면 데이터 조회를 멈춰야 하기 때문이다. 하지만 서버로부터 데이터를 회신받을 수 있는 잔여분 데이터가 있다 하더라도 우리가 필요하지 않은(우리가 요청하지 않은) 데이터는 굳이 회신받을 필요는 없는데, 이 때 사용할 수 있는 것이 바로 사전에 만들어둔 데이터프레임에 있는 데이터 개수와 서버에 요청한 데이터 개수를 비교하는 것이다. 여기서 Continue 속성을 활용하여 서버로부터 회신받을 데이터가 있는지 없는지 여부를 먼저 확인하여 이 속성이 어떻게 동작하는지 살펴보고, 이후에 데이터프레임의 개수와 서버에 요청한 개수를 비교하는 로직을 추가하여 '개수로 조회하는 함수'를 완성시켜보자.

일단 기존에 작성했던 def _len_chart(self): 함수가 아닌 def _cont_len_chart(self):라는 새로운 이름의 함수를 생성해주도록 하자. 이 함수는 별도로 이벤트 처리기와 연결하지 않을 예정이다.(class event_handler_CpSysDib: 내부의 함수인 def OnReceived(self): 함수에 if self.object == "_cont_len_chart":를 사용하지 않을 것이다.) 이 함수 역시 서버에 데이터를 요청할 때에는 종목코드와 차트구분(request), 그리고 데이터 개수(quantity)는 필요하기 때문에 def _len_chart(self): 함수와 동일한 인자를 전달받도록 하자.

## CpSysDib.py ##
import win32com.client
import pandas as pd
class StockChart:
def __init__(self):
self.stockchart = win32com.client.Dispatch("CpSysDib.StockChart") ## COM 인스턴스 생성
self.handlers = win32com.client.WithEvents(self.stockchart, event_handler_CpSysDib)
def _cont_len_chart(self, item_code, request, quantity):
pass

다음으로, 서버에 데이터를 요청하기 전에 앞서 데이터프레임으로 만들기 위한 dictionary 형태의 변수를 새롭게 생성해주자. 이 변수는 데이터프레임(DataFrame)으로 만들 때 그 데이터프레임의 근간이 되는 데이터이다. 이 내용은 지난 게시글에서 설명했으니, 여기서는 이쯤 하고 넘어가도록 하자.
※ Line: 11

## CpSysDib.py ##
import win32com.client
import pandas as pd
class StockChart:
def __init__(self):
self.stockchart = win32com.client.Dispatch("CpSysDib.StockChart") ## COM 인스턴스 생성
self.handlers = win32com.client.WithEvents(self.stockchart, event_handler_CpSysDib)
def _cont_len_chart(self, item_code, request, quantity):
_df = {'date':[], 'open':[], 'high':[], 'low':[], 'close':[], 'vol':[], 'tvol':[]}

이제 이 아래에 들어올 내용은 이전에 작성했던 def _len_chart(self): 함수에서 작성했던 부분과 완벽하게 동일하다. 차이점이 있다면 Line 21 부분에서, set_instance의 두 번째 인자로 "_cont_len_chart"를 전달해준다는 것이다. 하지만 앞서 설명했듯이 이벤트 처리기 내부에서 "_cont_len_chart"를 처리하도록 하는 코드를 구현하지 않을 예정이므로 이 코드는 아무런 기능을 수행하지 않는다. 그럼에도 인자로 전달해주는 이유는, 서버로부터 이벤트가 발생했을 때 그 이벤트를 처리할 담당자가 없으면 오류가 발생하기 때문이다. 즉, 우리는 담당자는 지정해두었지만 그 담당자의 업무를 공란으로 두는 것이다.
※ Line: 12 ~ 22

## CpSysDib.py ##
import win32com.client
import pandas as pd
class StockChart:
def __init__(self):
self.stockchart = win32com.client.Dispatch("CpSysDib.StockChart") ## COM 인스턴스 생성
self.handlers = win32com.client.WithEvents(self.stockchart, event_handler_CpSysDib)
def _cont_len_chart(self, item_code, request, quantity):
_df = {'date':[], '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, 2, 3, 4, 5, 8, 9])
self.stockchart.SetInputValue(6, ord(f"{request}")) ## 차트 구분("D", "W", "M:)
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, "_cont_len_chart")
self.stockchart.BlockRequest() ## 데이터 요청

이제 데이터를 요청했으면 서버로부터 데이터를 가져오는 코드가 필요한데, 이 부분 역시 이벤트 처리기에 있는 코드와 동일하다. 다만 다른 코드와의 차이점이 있다면 서버로부터 데이터를 회신받은 후에 각각의 데이터들을 _df라는 변수에 입력해주는 것이다.(Line: 37~43)
※ Line: 24 ~ 43

## CpSysDib.py ##
import win32com.client
import pandas as pd
class StockChart:
def __init__(self):
self.stockchart = win32com.client.Dispatch("CpSysDib.StockChart") ## COM 인스턴스 생성
self.handlers = win32com.client.WithEvents(self.stockchart, event_handler_CpSysDib)
def _cont_len_chart(self, item_code, request, quantity):
_df = {'date':[], '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, 2, 3, 4, 5, 8, 9])
self.stockchart.SetInputValue(6, ord(f"{request}")) ## 차트 구분("D", "W", "M:)
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, "_cont_len_chart")
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: 인덱스 번호
open = self.stockchart.GetDataValue(1, index) ## 2: 시가, index: 인덱스 번호
high = self.stockchart.GetDataValue(2, index) ## 3: 고가, index: 인덱스 번호
low = self.stockchart.GetDataValue(3, index) ## 4: 저가, index: 인덱스 번호
close = self.stockchart.GetDataValue(4, index) ## 5: 종가, index: 인덱스 번호
vol = self.stockchart.GetDataValue(5, index) ## 8: 거래량, index: 인덱스 번호
tvol = self.stockchart.GetDataValue(6, index) ## 9: 거래대금, index: 인덱스 번호
_df['date'].append(str(date))
_df['open'].append(open)
_df['high'].append(high)
_df['low'].append(low)
_df['close'].append(close)
_df['vol'].append(vol)
_df['tvol'].append(tvol)

이제부터 Continue 속성을 활용하여 데이터를 추가적으로 조회할 예정인데, 서버로부터 회신되는 데이터가 어떠한지를 살펴보아야 하니 일단 Boss.py 파일의 코드를 아래와 같이 수정한 후에, 다시 CpSysDib.py 파일로 돌아와서 for 문이 끝난 후의 지점에서 아래와 같은 코드를 추가하여 이 속성이 전달해주는 값을 확인해보도록 하자.
※ Boss.py : Line: 32, 45
※ CpSysDib.py : Line: 45

## Boss.py ##
import win32com.client
from pywinauto import application
from COM import CpSysDib
from COM import CpUtil
from COM import CpTrade
from COM import DsCbo1
import time
## GUI ##
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
main_ui = uic.loadUiType("main.ui")[0]
class cybos(QMainWindow, main_ui):
def __init__(self):
super().__init__()
self.setupUi(self)
self.stockcode = CpUtil.CpStockCode()
self.trade = CpTrade.CpTdUtil()
self.stockmst = DsCbo1.StockMst()
self._open_cybosplus()
self.pushButton.clicked.connect(self._GetStockListByMarket)
self.pushButton_2.clicked.connect(self._day_range)
self.pushButton_3.clicked.connect(self._len_chart)
def _len_chart(self):
item_code = self.lineEdit_4.text()
data_len = int(self.lineEdit_5.text())
request = ""
cur_idx = self.comboBox_2.currentIndex()
if cur_idx == 0:
request = "T"
elif cur_idx == 1:
request = "m"
elif cur_idx == 2:
request = "D"
elif cur_idx == 3:
request = "W"
elif cur_idx == 4:
request = "M"
CpSysDib.StockChart()._cont_len_chart(item_code, request, data_len)
## CpSysDib.py ##
import win32com.client
import pandas as pd
class StockChart:
def __init__(self):
self.stockchart = win32com.client.Dispatch("CpSysDib.StockChart") ## COM 인스턴스 생성
self.handlers = win32com.client.WithEvents(self.stockchart, event_handler_CpSysDib)
def _cont_len_chart(self, item_code, request, quantity):
_df = {'date':[], '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, 2, 3, 4, 5, 8, 9])
self.stockchart.SetInputValue(6, ord(f"{request}")) ## 차트 구분("D", "W", "M:)
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, "_cont_len_chart")
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: 인덱스 번호
open = self.stockchart.GetDataValue(1, index) ## 2: 시가, index: 인덱스 번호
high = self.stockchart.GetDataValue(2, index) ## 3: 고가, index: 인덱스 번호
low = self.stockchart.GetDataValue(3, index) ## 4: 저가, index: 인덱스 번호
close = self.stockchart.GetDataValue(4, index) ## 5: 종가, index: 인덱스 번호
vol = self.stockchart.GetDataValue(5, index) ## 8: 거래량, index: 인덱스 번호
tvol = self.stockchart.GetDataValue(6, index) ## 9: 거래대금, index: 인덱스 번호
_df['date'].append(str(date))
_df['open'].append(open)
_df['high'].append(high)
_df['low'].append(low)
_df['close'].append(close)
_df['vol'].append(vol)
_df['tvol'].append(tvol)
print(self.stockchart.Continue)

▶ 실행 결과 확인하기

더보기

self.object:CpCybos
[통신결과:1] 서버와의 연결에 성공했습니다.
로그인되어 있습니다.
self.object:_cont_len_chart
필드 개수:7(('날짜', '시가', '고가', '저가', '종가', '거래량', '거래대금')), 데이터 개수:2856
1

 

 


반응형
728x90

 

 

위에서 구현한 부분은 Continue 속성을 확인하는 부분이었다. 그렇다면 이제는 조회된 데이터의 개수와 우리가 서버에 요청한 데이터의 개수를 확인해주도록 하자. 현재까지 조회된 데이터의 개수는 _df['date'] 변수의 개수로 확인할 수 있고, 서버에 요청한 데이터의 개수는 quantity 변수로 확인할 수 있다. 이제 아래와 같이 코드를 수정한 후, 프로그램을 실행시켜서 서버로 5,000개의 일봉 차트 데이터를 요청해보자.
※ Line: 46

## CpSysDib.py ##
import win32com.client
import pandas as pd
class StockChart:
def __init__(self):
self.stockchart = win32com.client.Dispatch("CpSysDib.StockChart") ## COM 인스턴스 생성
self.handlers = win32com.client.WithEvents(self.stockchart, event_handler_CpSysDib)
def _cont_len_chart(self, item_code, request, quantity):
_df = {'date':[], '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, 2, 3, 4, 5, 8, 9])
self.stockchart.SetInputValue(6, ord(f"{request}")) ## 차트 구분("D", "W", "M:)
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, "_cont_len_chart")
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: 인덱스 번호
open = self.stockchart.GetDataValue(1, index) ## 2: 시가, index: 인덱스 번호
high = self.stockchart.GetDataValue(2, index) ## 3: 고가, index: 인덱스 번호
low = self.stockchart.GetDataValue(3, index) ## 4: 저가, index: 인덱스 번호
close = self.stockchart.GetDataValue(4, index) ## 5: 종가, index: 인덱스 번호
vol = self.stockchart.GetDataValue(5, index) ## 8: 거래량, index: 인덱스 번호
tvol = self.stockchart.GetDataValue(6, index) ## 9: 거래대금, index: 인덱스 번호
_df['date'].append(str(date))
_df['open'].append(open)
_df['high'].append(high)
_df['low'].append(low)
_df['close'].append(close)
_df['vol'].append(vol)
_df['tvol'].append(tvol)
print(self.stockchart.Continue)
print(f"회신받은 개수:{len(_df['date'])}, 요청한 개수:{quantity}")

▶ 실행 결과 확인하기

더보기

self.object:CpCybos
[통신결과:1] 서버와의 연결에 성공했습니다.
로그인되어 있습니다.
self.object:_cont_len_chart
필드 개수:7(('날짜', '시가', '고가', '저가', '종가', '거래량', '거래대금')), 데이터 개수:2856
1
회신받은 개수:2856, 요청한 개수:5000

이제 프로그램을 어떻게 구현해야할지 대충 감이 올 것이다. 가장 먼저, 우리가 요청한 개수(quantity)보다 서버로부터 회신받은 데이터의 개수(len(_df['date'])가 작거나 같은 경우에는 데이터를 추가적으로 조회해야 하는데, 그 때 사용하는 조건문은 아래와 같이 구현할 수 있다. 즉, 이 조건문을 통해 "현재 서버에 요청한 데이터 개수보다 적은 데이터가 회신된 경우"라는 조건을 상정한 후 그 이후에 수행할 작업들을 입력해주면 된다.

## 개수 비교 로직
if len(_df['date']) <= quantity:
pass
else:
pass

□ 만약 Traceback (most recent call last): 오류가 발생한다면

더보기

Traceback (most recent call last):
    if len(_df['date']) <= quantity:
TypeError: '<=' not supported between instances of 'int' and 'str'

와 같은 오류가 발생하시는 경우에는 Boss.py 파일의 Line 32를 참고하시기 바랍니다. 기본적으로 QLineEdit 클래스가 갖는 text() 메서드의 경우에는 그 데이터값을 문자열 형태로 가져오기 때문에, 애초에 quantity 값이 문자열 형태로 전달되었을 수 있으므로 self.lineEdit_5.text()가 아닌 int(self.lineEdit_5.text())와 같은 형태로 변경해주셔야 합니다. 이 오류는 데이터의 형식이 맞지 않아서 발생하는 오류이며, 문자열의 "5000"과 숫자형의 2,856은 비교할 수 없다는 오류로 문자열인 "5000"을 숫자형인 5,000으로 변경해주시면 되는 간단한 오류입니다.

이제 서버로부터 회신받은 데이터의 개수가 회신받아야 하는 데이터의 개수보다 적다는 것이 확인되었다면, 아래의 두 내용을 구분해야 하는데 이 때 사용하는 것이 Continue 속성이다.

  • 정말 그 종목의 일봉 차트로 회신해줄 데이터가 없는지(상장된지 2,856 거래일이 안 됐는지)
  • 일봉 차트로 회신해줄 데이터가 있다면 추가 작업 수행
## CpSysDib.py ##
if len(_df['date']) <= quantity: ## 아직 다 회신받지 못한 경우
if self.stockchart.Continue == 1: ## 추가 작업 수행
pass
else: ## 데이터 조회 종료
pass
else: ## 데이터 조회 종료(모두 회신받음)
pass

 

 

이제 서버로 데이터를 요청했으나 ①서버에서 회신받을 추가적인 데이터가 존재하고 ②요청한 데이터를 다 전달받지 못한 경우에만 수행할 작업을 코드로 구현해주면 된다. 이 부분도 크게 어려울 게 없는게 현재 제작 중인 def _cont_len_chart(self): 함수에서 사용했던 코드 중에서 SetInputValue()를 통해 데이터를 입력해주었던 부분을 제외하고 그 아래에 데이터를 요청하는 코드(set_instanceBlockRequest())부터 나머지 부분만 그대로 복사해서 넣어주면 된다. (Line 12부터 34까지의 코드가 Line 41에서 63에 그대로 들어감) 아래는 현재까지 작성한 함수의 코드 전문이다.

def _cont_len_chart(self, item_code, request, quantity):
_df = {'date':[], '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, 2, 3, 4, 5, 8, 9])
self.stockchart.SetInputValue(6, ord(f"{request}")) ## 차트 구분("D", "W", "M:)
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, "_cont_len_chart")
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: 인덱스 번호
open = self.stockchart.GetDataValue(1, index) ## 2: 시가, index: 인덱스 번호
high = self.stockchart.GetDataValue(2, index) ## 3: 고가, index: 인덱스 번호
low = self.stockchart.GetDataValue(3, index) ## 4: 저가, index: 인덱스 번호
close = self.stockchart.GetDataValue(4, index) ## 5: 종가, index: 인덱스 번호
vol = self.stockchart.GetDataValue(5, index) ## 8: 거래량, index: 인덱스 번호
tvol = self.stockchart.GetDataValue(6, index) ## 9: 거래대금, index: 인덱스 번호
_df['date'].append(str(date))
_df['open'].append(open)
_df['high'].append(high)
_df['low'].append(low)
_df['close'].append(close)
_df['vol'].append(vol)
_df['tvol'].append(tvol)
print(self.stockchart.Continue)
print(f"회신받은 개수:{len(_df['date'])}, 요청한 개수:{quantity}")
if len(_df['date']) <= quantity: ## 아직 다 회신받지 못한 경우
if self.stockchart.Continue == 1: ## 추가 작업 수행
self.handlers.set_instance(self.stockchart, "_cont_len_chart")
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: 인덱스 번호
open = self.stockchart.GetDataValue(1, index) ## 2: 시가, index: 인덱스 번호
high = self.stockchart.GetDataValue(2, index) ## 3: 고가, index: 인덱스 번호
low = self.stockchart.GetDataValue(3, index) ## 4: 저가, index: 인덱스 번호
close = self.stockchart.GetDataValue(4, index) ## 5: 종가, index: 인덱스 번호
vol = self.stockchart.GetDataValue(5, index) ## 8: 거래량, index: 인덱스 번호
tvol = self.stockchart.GetDataValue(6, index) ## 9: 거래대금, index: 인덱스 번호
_df['date'].append(str(date))
_df['open'].append(open)
_df['high'].append(high)
_df['low'].append(low)
_df['close'].append(close)
_df['vol'].append(vol)
_df['tvol'].append(tvol)
pass
else: ## 데이터 조회 종료
pass
else: ## 데이터 조회 종료(모두 회신받음)
pass

이제 데이터가 모두 조회된 후에는 차트 데이터를 데이터프레임으로 만들어서 출력해보자. 조회 개수는 5,000개이다.
※ Line: 79, 80

## CpSysDib.py ##
import win32com.client
import pandas as pd
class StockChart:
def __init__(self):
self.stockchart = win32com.client.Dispatch("CpSysDib.StockChart") ## COM 인스턴스 생성
self.handlers = win32com.client.WithEvents(self.stockchart, event_handler_CpSysDib)
def _cont_len_chart(self, item_code, request, quantity):
_df = {'date':[], '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, 2, 3, 4, 5, 8, 9])
self.stockchart.SetInputValue(6, ord(f"{request}")) ## 차트 구분("D", "W", "M:)
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, "_cont_len_chart")
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: 인덱스 번호
open = self.stockchart.GetDataValue(1, index) ## 2: 시가, index: 인덱스 번호
high = self.stockchart.GetDataValue(2, index) ## 3: 고가, index: 인덱스 번호
low = self.stockchart.GetDataValue(3, index) ## 4: 저가, index: 인덱스 번호
close = self.stockchart.GetDataValue(4, index) ## 5: 종가, index: 인덱스 번호
vol = self.stockchart.GetDataValue(5, index) ## 8: 거래량, index: 인덱스 번호
tvol = self.stockchart.GetDataValue(6, index) ## 9: 거래대금, index: 인덱스 번호
_df['date'].append(str(date))
_df['open'].append(open)
_df['high'].append(high)
_df['low'].append(low)
_df['close'].append(close)
_df['vol'].append(vol)
_df['tvol'].append(tvol)
print(self.stockchart.Continue)
print(f"회신받은 개수:{len(_df['date'])}, 요청한 개수:{quantity}")
if len(_df['date']) <= quantity: ## 아직 다 회신받지 못한 경우
if self.stockchart.Continue == 1: ## 추가 작업 수행
self.handlers.set_instance(self.stockchart, "_cont_len_chart")
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: 인덱스 번호
open = self.stockchart.GetDataValue(1, index) ## 2: 시가, index: 인덱스 번호
high = self.stockchart.GetDataValue(2, index) ## 3: 고가, index: 인덱스 번호
low = self.stockchart.GetDataValue(3, index) ## 4: 저가, index: 인덱스 번호
close = self.stockchart.GetDataValue(4, index) ## 5: 종가, index: 인덱스 번호
vol = self.stockchart.GetDataValue(5, index) ## 8: 거래량, index: 인덱스 번호
tvol = self.stockchart.GetDataValue(6, index) ## 9: 거래대금, index: 인덱스 번호
_df['date'].append(str(date))
_df['open'].append(open)
_df['high'].append(high)
_df['low'].append(low)
_df['close'].append(close)
_df['vol'].append(vol)
_df['tvol'].append(tvol)
pass
else: ## 데이터 조회 종료
pass
else: ## 데이터 조회 종료(모두 회신받음)
pass
chart_data = pd.DataFrame(_df, columns=['date', 'open', 'high', 'low', 'close', 'vol', 'tvol'])
print(chart_data)

▶ 실행 결과 확인하기

더보기

self.object:CpCybos
[통신결과:1] 서버와의 연결에 성공했습니다.
로그인되어 있습니다.
self.object:_cont_len_chart
필드 개수:7(('날짜', '시가', '고가', '저가', '종가', '거래량', '거래대금')), 데이터 개수:2856
1
회신받은 개수:2856, 요청한 개수:5000
self.object:_cont_len_chart
필드 개수:7(('날짜', '시가', '고가', '저가', '종가', '거래량', '거래대금')), 데이터 개수:2856
          date    open    high     low   close       vol           tvol
0     20240906   69100   69700   68000   69000  12647589   870495000000
1     20240905   70100   71200   69000   69000  25686769  1795890000000
2     20240904   69800   71100   69800   70000  27366563  1923751000000
3     20240903   74100   74300   72500   72500  16314599  1195017000000
4     20240902   74500   74700   73500   74400  12641376   938130000000
...        ...     ...     ...     ...     ...       ...            ...
5707  20010802  201000  202000  194000  195500    635840   125604000000
5708  20010801  191500  199500  190500  198000   1157583   227329000000
5709  20010731  187000  190500  186000  189500    444664    84178000000
5710  20010730  188000  189000  184500  185500    401109    74832000000
5711  20010727  186500  189500  184500  185500    576045   107796000000

 

2,856개의 데이터가 두 번 회신되면서 총 5,712개의 데이터가 수신되었다. 물론 우리가 요청한 데이터의 개수는 5,000개가 맞긴 하지만 5,000개에서 딱 끊어내는 코드는 따로 구현하지 않았다. 다음 게시글에서는 ①두 번보다도 더 많은 횟수의 데이터를 조회할 수 있는 기능과 ②우리가 요청한 데이터의 개수만큼만 출력하도록 하는 기능을 추가한 후 일봉 차트 데이터를 연속으로 조회하는 방법을 마무리하도록 할 예정이다.

 

 


728x90
반응형

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

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