AUTO TRADE/[대신증권] CYBOS PLUS

대신증권 CYBOS PLUS 프로그램 구현 (8) - 일봉 차트 조회 : 데이터 개수

프로그램 구현 목표

  • 데이터 개수를 가지고 차트 데이터 조회하기
  • GUI의 pushButton과 연결하기

 

데이터 개수를 가지고 차트 데이터 조회하기

지난 게시글에서는 일봉 차트 데이터를 조회하는 함수의 동작 방식을 알아보는 동시에  일자 범위를 가지고 일봉 차트 데이터를 조회하는 함수를 구현해보았다. 이번 게시글에서는 "요청 구분"이 2(개수)인 경우에 차트 데이터를 어떻게 수신받을 수 있는지에 대해 살펴보고 그에 대응하는 차트 데이터 조회 함수를 구현해보고자 한다. 이전 게시글에서 살펴보았듯이 "요청 구분"이 1(기간)인 경우에는 일봉 차트 데이터만 조회할 수 있었는데, "요청 구분"이 2(개수)인 경우에는 일봉을 포함하여 분봉, 주봉, 월봉, 틱봉 모두 조회가 가능하다.

하지만 본격적으로 코드를 제작하기 전에 앞서, 일봉, 주봉, 월봉은 기본적으로 날짜라는 데이터만 포함되어 있으면 구분해낼 수 있지만 분봉과 틱봉 차트는 날짜라는 데이터와 더불어 시간이라는 데이터도 함께 포함되어 있어야 어느 시점의 데이터인지를 구분해낼 수 있다. 다시 말해, 데이터를 요청할 때 `Type 5`로 전달하는 필드 배열의 구성이 다르다는 것이다. 이 부분은 일단 염두에 두고, 일봉과 주봉 그리고 월봉 차트 데이터를 '개수' 데이터를 전달하여 조회하는 함수를 구현해보자. 가장 먼저 이 함수의 이름은 `def _len_chart(self):`로 하도록 하고, 이 함수가 어떠한 인자들을 전달받아야 하는지 알아보자. (분봉 및 틱봉 차트 데이터는 `def _len_chart_min(self):`로 하여 추후에 별도의 함수로 생성할 예정이다. 그 이유는 나중에 다시 살펴보자.)

다시 본론으로 돌아와 이 함수가 전달받아야 할 인자의 목록으로 가장 먼저 종목코드(`item_code`)는 기본적으로 전달받아야 할테고, "요청 구분"이 1(기간)이 아닌 2(개수)인 만큼 서버로부터 회신받을 데이터의 개수(`quantity`)도 인자로 전달받아야 할 것이다. 더 나아가, 우리가 조회하고자 하는 데이터가 '일봉, 주봉, 월봉, 분봉, 틱봉' 중 어떠한 것인지(`request`)에 대해서도 인자로 전달받아야 서버에 올바른 데이터를 요청할 수 있다. 

## CpSysDib.py ##
import win32com.client

class StockChart:
    def __init__(self):
        self.stockchart = win32com.client.Dispatch("CpSysDib.StockChart")  ## COM 인스턴스 생성
        self.handlers = win32com.client.WithEvents(self.stockchart, event_handler_CpSysDib)

    def _len_chart(self, item_code, request, quantity):
        pass

데이터를 개수로 조회하고자 할 때에 서버로 전달해주어야 하는 데이터 목록은 지난 번에 일자 범위를 가지고 데이터를 조회할 때 전달해주었던 데이터 목록과는 다소 다르다. 애초에 "요청 구분"이 1이 아닌 2를 전달해주기 때문에, 요청 종료일과 요청 시작일 데이터는 전달하지 않고 요청 개수만 전달해주면 된다. 더불어 전달하고자 하는 데이터 중 6번째 데이터는 "차트 구분"을 의미하는 것으로, 일봉이라면 "D", 주봉이라면 "W", 월봉이라면 "M"을 전달해주면 된다. 마지막으로 Line 11에서는 이벤트가 발생했을 때 올바르게 이벤트를 처리할 수 있도록 `class event_handler_CpSysDib` 클래스의 `def set_instance(self, disp, obejct)` 함수의 인자 중 `object`에 함수의 이름(`_len_chart`)을 전달해주도록 하자.

    def _len_chart(self, item_code, request, quantity):
        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, "_len_chart")
        self.stockchart.BlockRequest()  ## 데이터 요청

다음으로 이벤트 처리기의 `def OnReceived(self):` 함수에서는 `elif self.object ==`라는 조건문을 통해 오브젝트의 이름이 위의 함수 이름(`_len_chart`)인 경우에 관련 데이터를 불러오도록 추가해주면 된다.
※ Line: 28~43

class event_handler_CpSysDib:
    """차트 데이터 조회 시 이벤트 처리"""
    def set_instance(self, disp, object):
        self.disp = disp
        self.object = object
        print(f"self.object:{self.object}")

    def OnReceived(self):
        if self.object == "_day_range":
            print("Raised OnReceived Event(_day_range)")
            len_fild = self.disp.GetHeaderValue(1)    ## 요청한 필드 개수
            array_fild = self.disp.GetHeaderValue(2)  ## 팔드 배열
            len = self.disp.GetHeaderValue(3)         ## 데이터 개수 확인
            print(f"필드 개수:{len_fild}({array_fild}), 데이터 개수:{len}")

            for index in range(len):
                date = self.disp.GetDataValue(0, index)     ## 0: 날짜,    index: 인덱스 번호
                open = self.disp.GetDataValue(1, index)     ## 2: 시가,    index: 인덱스 번호
                high = self.disp.GetDataValue(2, index)     ## 3: 고가,    index: 인덱스 번호
                low = self.disp.GetDataValue(3, index)      ## 4: 저가,    index: 인덱스 번호
                close = self.disp.GetDataValue(4, index)    ## 5: 종가,    index: 인덱스 번호
                dif = self.disp.GetDataValue(5, index)      ## 6: 전일대비, index: 인덱스 번호
                vol = self.disp.GetDataValue(6, index)      ## 8: 거래량,   index: 인덱스 번호
                tvol = self.disp.GetDataValue(7, index)     ## 9: 거래대금, index: 인덱스 번호
                pm = self.disp.GetDataValue(8, index)       ## 37: 대비부호,index: 인덱스 번호
                print(f"[{date}] 시:{open}, 고:{high}, 저:{low}, 종:{close}, 전일대비:{pm}{dif}, 거래량:{vol}, 거래대금:{tvol}")

        elif self.object == "_len_chart":
            print("Raised OnReceived Event(_len_chart)")
            len_fild = self.disp.GetHeaderValue(1)    ## 요청한 필드 개수
            array_fild = self.disp.GetHeaderValue(2)  ## 팔드 배열
            len = self.disp.GetHeaderValue(3)         ## 데이터 개수 확인
            print(f"필드 개수:{len_fild}({array_fild}), 데이터 개수:{len}")

            for index in range(len):
                date = self.disp.GetDataValue(0, index)     ## 0: 날짜,    index: 인덱스 번호
                open = self.disp.GetDataValue(1, index)     ## 2: 시가,    index: 인덱스 번호
                high = self.disp.GetDataValue(2, index)     ## 3: 고가,    index: 인덱스 번호
                low = self.disp.GetDataValue(3, index)      ## 4: 저가,    index: 인덱스 번호
                close = self.disp.GetDataValue(4, index)    ## 5: 종가,    index: 인덱스 번호
                vol = self.disp.GetDataValue(5, index)      ## 8: 거래량,   index: 인덱스 번호
                tvol = self.disp.GetDataValue(6, index)     ## 9: 거래대금, index: 인덱스 번호
                print(f"[{date}] 시:{open}, 고:{high}, 저:{low}, 종:{close}, 거래량:{vol}, 거래대금:{tvol}")

이제 Boss.py 파일 내부의 초기화 함수에서, 아래와 같은 코드를 추가하여 일봉 차트 데이터를 조회해보도록 하자.

## 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.cybos = CpUtil.CpCybos()
        self.stockchart = CpUtil.CpStockCode()
        self.trade = CpTrade.CpTdUtil()
        self.codemgr = CpUtil.CpCodeMgr()
        self.stockmst = DsCbo1.StockMst()
        self.stockchart = CpSysDib.StockChart()

        self._open_cybosplus()
        self.stockchart._len_chart("A005930", "D", 62)
        self.stockchart._day_range("A005930", "20230101", "20230331")

▶ 실행 결과 확인하기

더보기

self.object:CpCybos
[통신결과:1] 서버와의 연결에 성공했습니다.
로그인되어 있습니다.
self.object:_len_chart
필드 개수:7(('날짜', '시가', '고가', '저가', '종가', '거래량', '거래대금')), 데이터 개수:5
[20240830] 시:74400, 고:75000, 저:74100, 종:74300, 거래량:16358520, 거래대금:1217838000000
[20240829] 시:73600, 고:74700, 저:73500, 종:74000, 거래량:16884479, 거래대금:1250517000000
[20240828] 시:75800, 고:76400, 저:75400, 종:76400, 거래량:9794514, 거래대금:743267000000
[20240827] 시:75700, 고:76500, 저:75600, 종:75800, 거래량:11130145, 거래대금:845521000000
[20240826] 시:78100, 고:78200, 저:76000, 종:76100, 거래량:15655938, 거래대금:1200212000000
self.object:_day_range
Raised OnReceived Event(_day_range)
필드 개수:9(('날짜', '시가', '고가', '저가', '종가', '전일대비', '거래량', '거래대금', '대비부호')), 데이터 개수:62
[20230331] 시:64000, 고:64000, 저:63700, 종:64000, 전일대비:50800, 거래량:14094479, 거래대금:900711000000
[20230330] 시:63700, 고:63700, 저:63100, 종:63200, 전일대비:50500, 거래량:15684377, 거래대금:993903000000
( 중략 )
[20230103] 시:55400, 고:56000, 저:54500, 종:55400, 전일대비:53-100, 거래량:13547030, 거래대금:747898000000
[20230102] 시:55500, 고:56100, 저:55200, 종:55500, 전일대비:50200, 거래량:10031448, 거래대금:558433000000

 

 


반응형
728x90

 

 

GUI의 pushButton과 연결하기

main.ui 파일을 열어서 "종목코드"나 "시작일자"와 같은 데이터는 `label`을 통해 입력해주고, 그 오른쪽에 데이터를 입력하는 란은 `lineEdit`, 데이터를 조회하는 버튼은 `pushButton`, 그리고 "차트구분"은 이전에 사용해봤던 `comboBox`를 사용하여 아래와 같은 모양으로 만들어주도록 하자. 여기서 "차트구분"에는 '틱봉, '분봉', '일봉', '주봉', '월봉'의 다섯 개 데이터를 입력해주자.

먼저 특정 범위를 대상으로 차트 데이터를 조회하는 함수의 이름을 `def _len_chart(self):`로 하여 Boss.py 파일 내부에 생성해준 후에, 일봉 조회(범위) 버튼이 갖는 객체 이름인 `pushButton_2`와 함께 연결해주도록 하자. 더 나아가 기존에 테스트할 때 만들어두었던 Line 28Line 29에 있는 코드는 삭제해주도록 하자.
※ Line: 28, 29, 32 ~ 35

## 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.cybos = CpUtil.CpCybos()
        self.stockcode = CpUtil.CpStockCode()
        self.trade = CpTrade.CpTdUtil()
        self.codemgr = CpUtil.CpCodeMgr()
        self.stockmst = DsCbo1.StockMst()
        self.stockchart = CpSysDib.StockChart()

        self._open_cybosplus()
        ## self.stockchart._len_chart("A005930", "D", 5) ## 삭제
        ## self.stockchart._day_range("A005930", "20230101", "20230331") ## 삭제

        self.pushButton.clicked.connect(self._GetStockListByMarket)
        self.pushButton_2.clicked.connect(self._day_range)

    def _day_range(self):
        pass

그 후에 종목코드를 입력하는 QLineEdit의 객체 이름인 `lineEdit`을 종목코드로, 시작일자를 입력하는 QLineEdit의 객체 이름인 `lineEdit_2`를 시작일자로, 종료일자를 입력하는 QLineEdit의 객체 이름인 `lineEdit_3`를 종료일자로 하여 사전에 만들어두었던 `self.stockchart._day_range()` 함수의 인자로 각각 전달해주도록 하자.
※ Line: 32 ~ 36

## 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.cybos = CpUtil.CpCybos()
        self.stockcode = CpUtil.CpStockCode()
        self.trade = CpTrade.CpTdUtil()
        self.codemgr = CpUtil.CpCodeMgr()
        self.stockmst = DsCbo1.StockMst()
        self.stockchart = CpSysDib.StockChart()

        self._open_cybosplus()

        self.pushButton.clicked.connect(self._GetStockListByMarket)
        self.pushButton_2.clicked.connect(self._day_range)

    def _day_range(self):
        item_code = self.lineEdit.text()
        start_date = self.lineEdit_2.text()
        end_date = self.lineEdit_3.text()
        self.stockchart._day_range(item_code, start_date, end_date)

이제 프로그램을 실행시킨 후에 아래와 같이 데이터를 입력한 후, 그 아래에 있는 일봉 조회(범위) 버튼을 눌러보자.

▶ 실행 결과 확인하기

더보기

self.object:CpCybos
[통신결과:1] 서버와의 연결에 성공했습니다.
로그인되어 있습니다.
self.object:_day_range
Raised OnReceived Event(_day_range)
필드 개수:9(('날짜', '시가', '고가', '저가', '종가', '전일대비', '거래량', '거래대금', '대비부호')), 데이터 개수:62
[20230331] 시:64000, 고:64000, 저:63700, 종:64000, 전일대비:50800, 거래량:14094479, 거래대금:900711000000
[20230330] 시:63700, 고:63700, 저:63100, 종:63200, 전일대비:50500, 거래량:15684377, 거래대금:993903000000
( 중략 )
[20230103] 시:55400, 고:56000, 저:54500, 종:55400, 전일대비:53-100, 거래량:13547030, 거래대금:747898000000
[20230102] 시:55500, 고:56100, 저:55200, 종:55500, 전일대비:50200, 거래량:10031448, 거래대금:558433000000

이제 개수로 차트 데이터를 조회하는 함수도 GUI와 연결해주도록 하자. `def _len_chart(self):`라는 함수를 Boss.py 파일 내에 새롭게 생성한 후, 위의 함수와 마찬가지로 QLineEdit에 입력되어 있을 종목코드와 조회 개수를 `text()` 메서드를 사용하여 전달받아보도록 하자.
※ Line: 31 ~ 37

## 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.cybos = CpUtil.CpCybos()
        self.stockcode = CpUtil.CpStockCode()
        self.trade = CpTrade.CpTdUtil()
        self.codemgr = CpUtil.CpCodeMgr()
        self.stockmst = DsCbo1.StockMst()
        self.stockchart = CpSysDib.StockChart()

        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 = self.lineEdit_5.text()
        request = ""
        self.stockchart._len_chart(item_code, request, data_len)

    def _day_range(self):
        item_code = self.lineEdit.text()
        start_date = self.lineEdit_2.text()
        end_date = self.lineEdit_3.text()
        self.stockchart._day_range(item_code, start_date, end_date)

위 코드 중 Line 36 부분을 보면 알 수 있겠지만, 우리는 `comboBox_2` 객체에 입력되어 있는 데이터를 가져온 후 그 데이터를 `request`에 "m"이나 "T", 또는 "D", "W", "M" 등과 같은 적절한 데이터로 변경한 후 함수에 전달해주어야 한다. 여기서 QComboBox 클래스는 `currentIndex()`라는 메서드를 활용하여 현재 활성화되어 있는 데이터의 인덱스 번호를 가져올 수 있는데, 우리가 사전에 입력해두었던 '틱봉, 분봉, 일봉, 주봉, 월봉'은 각각 '0, 1, 2, 3, 4'라는 인덱스 번호를 갖는다. 따라서 그 인덱스 번호가 0인 경우 `request` 변수에는 "T"를 입력하면 되고, 1인 경우에는 "m"을 입력해주면 된다.
※ Line: 37 ~ 48

## 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.cybos = CpUtil.CpCybos()
        self.stockcode = CpUtil.CpStockCode()
        self.trade = CpTrade.CpTdUtil()
        self.codemgr = CpUtil.CpCodeMgr()
        self.stockmst = DsCbo1.StockMst()
        self.stockchart = CpSysDib.StockChart()

        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 = 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"
        self.stockchart._len_chart(item_code, request, data_len)

    def _day_range(self):
        item_code = self.lineEdit.text()
        start_date = self.lineEdit_2.text()
        end_date = self.lineEdit_3.text()
        self.stockchart._day_range(item_code, start_date, end_date)

이제 프로그램을 실행시킨 후, 위에서 일봉 조회(범위) 버튼을 조회할 때 했던 방식과 동일하게 종목코드와 데이터 개수를 입력한 후 차트 구분을 일봉으로 놓고 아래에 있는 차트 조회(개수) 버튼을 눌러 결과값을 확인해보도록 하자.

▶ 실행 결과 확인하기

더보기

self.object:CpCybos
[통신결과:1] 서버와의 연결에 성공했습니다.
로그인되어 있습니다.
self.object:_len_chart
필드 개수:7(('날짜', '시가', '고가', '저가', '종가', '거래량', '거래대금')), 데이터 개수:5
[20240830] 시:74400, 고:75000, 저:74100, 종:74300, 거래량:16358520, 거래대금:1217838000000
[20240829] 시:73600, 고:74700, 저:73500, 종:74000, 거래량:16884479, 거래대금:1250517000000
[20240828] 시:75800, 고:76400, 저:75400, 종:76400, 거래량:9794514, 거래대금:743267000000
[20240827] 시:75700, 고:76500, 저:75600, 종:75800, 거래량:11130145, 거래대금:845521000000
[20240826] 시:78100, 고:78200, 저:76000, 종:76100, 거래량:15655938, 거래대금:1200212000000

 

 


728x90
반응형
Contents

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

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