본문 바로가기
알고리즘 트레이딩/CREON API 예제 분석

CREON API (Python) 주식 현재가 조회/실시간

by 빵빵댇 2022. 2. 20.

들어가며

이번 예제에서는 PyQt5를 사용하여 윈도우UI를 구성하여 프로그램을 실행한다. 내가 이 블로그에 글을 쓰기 시작하며 생각했던 주식 매매 프로그램은 PC가 서버 역할을 해 자동으로 주식을 매매/매수하고 모바일로 거래내역에 대한 알림을 받는 형태의 모델이었기 때문에 윈도우UI는 사용할 일이 없다. 따라서 본 예제에서 PyQt5 관련 사항은 분석하지 않기로 한다.

 

코드

import sys
from PyQt5.QtWidgets import *
import win32com.client
 
 
class CpEvent:
    instance = None
 
    def OnReceived(self):
        # time = CpEvent.instance.GetHeaderValue(3)  # 시간
        timess = CpEvent.instance.GetHeaderValue(18)  # 초
        exFlag = CpEvent.instance.GetHeaderValue(19)  # 예상체결 플래그
        cprice = CpEvent.instance.GetHeaderValue(13)  # 현재가
        diff = CpEvent.instance.GetHeaderValue(2)  # 대비
        cVol = CpEvent.instance.GetHeaderValue(17)  # 순간체결수량
        vol = CpEvent.instance.GetHeaderValue(9)  # 거래량
 
        if (exFlag == ord('1')):  # 동시호가 시간 (예상체결)
            print("실시간(예상체결)", timess, "*", cprice, "대비", diff, "체결량", cVol, "거래량", vol)
        elif (exFlag == ord('2')):  # 장중(체결)
            print("실시간(장중 체결)", timess, cprice, "대비", diff, "체결량", cVol, "거래량", vol)
 
 
class CpStockCur:
    def Subscribe(self, code):
        self.objStockCur = win32com.client.Dispatch("DsCbo1.StockCur")
        win32com.client.WithEvents(self.objStockCur, CpEvent)
        self.objStockCur.SetInputValue(0, code)
        CpEvent.instance = self.objStockCur
        self.objStockCur.Subscribe()
 
    def Unsubscribe(self):
        self.objStockCur.Unsubscribe()
 
 
 
class CpStockMst:
    def Request(self, code):
        # 연결 여부 체크
        objCpCybos = win32com.client.Dispatch("CpUtil.CpCybos")
        bConnect = objCpCybos.IsConnect
        if (bConnect == 0):
            print("PLUS가 정상적으로 연결되지 않음. ")
            return False
 
        # 현재가 객체 구하기
        objStockMst = win32com.client.Dispatch("DsCbo1.StockMst")
        objStockMst.SetInputValue(0, code)  # 종목 코드 - 삼성전자
        objStockMst.BlockRequest()
 
        # 현재가 통신 및 통신 에러 처리
        rqStatus = objStockMst.GetDibStatus()
        rqRet = objStockMst.GetDibMsg1()
        print("통신상태", rqStatus, rqRet)
        if rqStatus != 0:
            return False
 
        # 현재가 정보 조회
        code = objStockMst.GetHeaderValue(0)  # 종목코드
        name = objStockMst.GetHeaderValue(1)  # 종목명
        time = objStockMst.GetHeaderValue(4)  # 시간
        cprice = objStockMst.GetHeaderValue(11)  # 종가
        diff = objStockMst.GetHeaderValue(12)  # 대비
        open = objStockMst.GetHeaderValue(13)  # 시가
        high = objStockMst.GetHeaderValue(14)  # 고가
        low = objStockMst.GetHeaderValue(15)  # 저가
        offer = objStockMst.GetHeaderValue(16)  # 매도호가
        bid = objStockMst.GetHeaderValue(17)  # 매수호가
        vol = objStockMst.GetHeaderValue(18)  # 거래량
        vol_value = objStockMst.GetHeaderValue(19)  # 거래대금
 
        print("코드 이름 시간 현재가 대비 시가 고가 저가 매도호가 매수호가 거래량 거래대금")
        print(code, name, time, cprice, diff, open, high, low, offer, bid, vol, vol_value)
        return True
 
 
class MyWindow(QMainWindow):
 
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PLUS API TEST")
        self.setGeometry(300, 300, 300, 150)
        self.isRq = False
        self.objStockMst = CpStockMst()
        self.objStockCur = CpStockCur()
 
        btn1 = QPushButton("요청 시작", self)
        btn1.move(20, 20)
        btn1.clicked.connect(self.btn1_clicked)
 
        btn2 = QPushButton("요청 종료", self)
        btn2.move(20, 70)
        btn2.clicked.connect(self.btn2_clicked)
 
        btn3 = QPushButton("종료", self)
        btn3.move(20, 120)
        btn3.clicked.connect(self.btn3_clicked)
 
    def StopSubscribe(self):
        if self.isRq:
            self.objStockCur.Unsubscribe()
        self.isRq = False
 
    def btn1_clicked(self):
        testCode = "A000660"
        if (self.objStockMst.Request(testCode) == False):
            exit()
 
        # 하이닉스 실시간 현재가 요청
        self.objStockCur.Subscribe(testCode)
 
        print("빼기빼기================-")
        print("실시간 현재가 요청 시작")
        self.isRq = True
 
    def btn2_clicked(self):
        self.StopSubscribe()
 
 
    def btn3_clicked(self):
        self.StopSubscribe()
        exit()
 
if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()
    myWindow.show()
    app.exec_()

 

실행결과

실행결과 아래와 같은 어플리케이션이 실행된다.

 

요청 시작 버튼을 클릭한 경우, 아래와 같은 문자열이 출력되는데 '실시간 현재가 요청 시작' 이후 대상 종목인 SK하이닉스의 실시간 현재가가 출력되어야 하지만 장 마감시간 이후에 프로그램을 실행했기 때문에 출력되는 내용 없이 실시간 요청만 진행하고 있는 상태다. 요청 종료를 누르면 프로그램 내부적으로 요청을 종료하지만 별도로 출력되는 내용은 없다.

장 마감시간 이후에 프로그램을 실행했기 때문에 실시간 정보가 없다

 

장이 열려있어 거래가 진행중인 시간이라면 아래와 같이 출력된다. 아래는 CREON 홈페이지에서 캡쳐한 내용이다.

'빼기빼기================-' 문자열 부분이 다른데 아마도 CREON 측에서 예제 소스를 잘못 올린 것 같다. 코드를 작성한 사람이 임시로 본인이 알아볼 수 있도록 빼기빼기라고 작성한 것 같다ㅋㅋ

 

 

분석내용

MyWindow, CpStockMst, CpStockCur, CpEvent 클래스를 구현했다. 사실 이번 예제에서 CREON API 사용 관련 내용은 CpStockCur 클래스만 분석해도 될 것으로 보이지만.. 기왕 하는김에 예제 구조도 함께 정리해보기로 했다.

 

  • MyWindow
    • 윈도우UI 구현하여 사용자로부터 요청시작/종료 명령을 입력받는다.
    • MyWindow 객체가 생성되는 순간 객체 내부에 CpStockMst, CpStockCur 객체를 생성한다.
    • '요청 시작' 시 동작 
      1. CpStockMst 객체의 Request 메소드를 호출하여 대상 종목의 현재가 정보 출력
      2. CpStockCur 객체의 Suscribe 메소드를 호출하여 현재가 요청을 시작
      3. 실시간 요청 진행여부 Flag값 True로 변경
    • '요청 종료'시 동작
      1. CpStockCur 객체의 Unsubscribe 메소드를 호출하여 요청 종료
      2. 실시간 요청 진행여부 Flag값 False로 변경 
    • '종료'시 동작
      1. 그레이스풀 셧다운을 위한 '요청 종료'시 동작 수행
      2. 프로그램 종료
  • CpStockMst
    • 이전에 분석한 적 있는 현재가 조회 예제와 동일한 내용으로, 대상 종목의 현재가 정보를 읽는 역할을 한다.
    • 다음 글의 내용을 참고하면 된다.
    • https://bbdad.tistory.com/14?category=536957
 

CREON API (Python) 주식 현재가 조회

코드 import win32com.client # 연결 여부 체크 objCpCybos = win32com.client.Dispatch("CpUtil.CpCybos") bConnect = objCpCybos.IsConnect if (bConnect == 0): print("PLUS가 정상적으로 연결되지 않음. ") ex..

bbdad.tistory.com

  • CpStockCur
    • DsCbo1.StockCur COM객체를 사용하여 주식 현재가 정보를 CREON으로부터 구독(Subscribe)/구독해제(Unsubscribe)한다.
    • CpStockCur 클래스는 멤버변수 없이 Subscribe, Unsubscribe 두개의 메소드만으로 구성되어 있다.
    • Unsubscribe는 단순히 StockCur COM객체의 Unsubscribe 메소드를 호출하며 해당 메소드는 당연하게도 CREON으로부터의 구독을 해제하는 기능이다.
    • Subscribe에서는 아래와 같은 동작을 한다.
      1. StockCur 객체로부터 발생하는 이벤트를 처리할 클래스를 등록한다.
        win32com.client.WithEvents(self.objStockCur, CpEvent)​
      2. StockCur 객체의 SetInputValue 메소드를 호출하여 구독 대상 종목을 설정한다. 첫번째 파라미터는 0 고정값을 사용하며 두번째 파라미터는 대상 종목의 종목코드값이다.
      3. StockCur 객체의 Subscribe 메소드를 호출하여 구독(Subscribe)을 시작한다.
  • CpEvent
    • StockCur 객체에 접근하기 위한 멤버변수인 instance와 이벤트를 처리하는 메소드인 OnReceived로 구성되어 있다. 어차피 StockCur 객체만 접근할 멤버변수인데 instance라는 변수명을 쓰니까 좀 헷갈리는 것 같다... stockCur 정도로 짓는게 가독성이 더 좋은것 같다는 생각이 든다.
    • OnReceived 메소드는 구독상태인 StockCur 객체에서 이벤트가 발생하는 경우 호출되는데, 여기서 이벤트란 StockCur 객체에 접근해서 읽을 수 있는 주식 현재가의 업데이트이다. 여하튼, 이벤트가 발생하면 instance라는 변수명의 StockCur 객체의 정보를 읽어 체결 내역을 출력한다.
    • StockCur 객체의 GetHeaderValue 메소드를 통해 정보를 읽는데 이는 이전 예제의 COM객체들과 특별히 다른 내용은 없다. 파라미터 상세값은 아래 참조 란을 참고하길 바란다.

 

참고

DsCbo1.StockCur 도움말 참조

https://money2.creontrade.com/e5/mboard/ptype_basic/HTS_Plus_Helper/DW_Basic_Read_Page.aspx?boardseq=284&seq=16&page=1&searchString=StockCur&p=8841&v=8643&m=9505 

 

크레온플러스 도움말 - 크레온

설명주식/업종/ELW시세데이터를수신합니다통신종류Subscribe/Publish관련 RQ/RP StockMst ,Elw관련CYBOS [7021현재가] [7024 시간대별체결]등의실시간데이타모듈위치cpdib.dll Method object.SetInputValue(type,value) type

money2.creontrade.com

 

댓글