CYBOS Plus로 종목 주가 불러오는 법 CpSysDib.StockChart
가이드 1
CpSysDib.StockChart
는 주식, 업종, ELW의 차트데이터를 수신한다. API를 사용하는 것에 익숙하지 않다면 이 체계를 이해하기가 대단히 어려울 수 있다. 주식회사 씨젠의 주가를 불러오는 파이썬 예제를 실행해보고 그 작동방식을 파악해보자.
SetInputValue()
: 어떤 데이터를 원하는지를 구체적으로 지정한다.BlockRequest()
: 지정된 데이터 수신을 요청한다.GetHeaderValue()
: 수신된 헤드 데이터를 리턴한다.GetDataValue()
: 수신된 데이터를 리턴한다.
이렇게 기괴한 함수들을 이상하게 사용하는 이유는 CYBOS Plus가 딱히 파이썬 라이브러리가 아니기 때문이다. 설명에서 더 자세히 다루겠다.
하이라이트
>>> days = 10
>>> instStockChart = win32com.client.Dispatch("CpSysDib.StockChart")
>>> instStockChart.SetInputValue(0, seegene)
>>> instStockChart.SetInputValue(1, ord('2'))
>>> instStockChart.SetInputValue(4, days)
>>> instStockChart.SetInputValue(5, 5)
>>> instStockChart.SetInputValue(6, ord('D'))
>>> instStockChart.SetInputValue(9, ord('1'))
>>> instStockChart.BlockRequest()
0
>>> numData = instStockChart.GetHeaderValue(3)
>>> for i in range(numData):
... print(instStockChart.GetDataValue(0, i), end = ', ')
...
80700, 80100, 77400, 77200, 82600, 85800, 83800, 88000, 88000, 90500, >>>
2021년 7월 21일 오전 10시경을 기준으로 주가데이터를 잘 불러온 것을 확인할 수 있다.
설명
instStockChart = win32com.client.Dispatch("CpSysDib.StockChart")
instStockChart.SetInputValue(0, 'A096530')
앞서 언급했듯 CYBOS Plus는 딱히 파이썬을 위해서만 개발되지 않았다. Windows 시스템 COM Object 라이브러리를 사용할 수 있는 개발 환경이라면 어디서든 사용할 수 있고, 비주얼 스튜디오나 파이썬, MS 오피스 등에서도 사용된다. 오브젝트 instStockChart
는 win32com.client.Dispatch()
를 통해 CpSysDib.StockChart
를 불러와 만들어졌지만, 그 내부가 딱히 파이써닉pythonic해야할 이유가 하등 없다. 따라서 퓨어 파이썬pure Python과 다른 인터페이스interface를 사용하게 되는 것이다.
object.SetInputValue(0, code)
는 object
의 종목을 code
로 지정해주는데, 사실 파이썬스러운 문법으로 상상해보면 instStockChart.code = 'A096530'
와 같이 instStockChart
의 프로퍼티property인 code
에 직접 접근해서 값을 주는 게 자연스럽지만, 파이썬이 아니기 때문에 CYBOS Plus의 방식을 따르게 되는 것이다.
다음은 데이터를 기간으로 요청할지, 갯수로 요청할지에 대한 지정이다.
- 1 - 요청구분(char)
- ‘1’: 기간으로 요청
- ‘2’: 갯수로 요청
instStockChart.SetInputValue(1, ord('2'))
그런데 지정하는 방식이 조금 이상하다. 그냥 2가 아니라 ord()
함수로 감싼 ord('2')
를 넘겨주고 있다. ord()
는 유니코드 문자를 나타내는 문자열을 정수인 유니코드 포인트로 리턴하는 함수로, 구체적으로 ord('2')
는 정수 50을 리턴한다. 위와 같이 문자열 '2'
를 그대로 넘기는 게 아니라 굳이 유니코드로 넘겨야 하는 것도 앞에서 설명한 이유와 맥락을 함께한다.
그런데 다음은 어떤 값을 요청할지에 대한 지정이다.
- 5 - 필드(long array)
- 5: 종가
- 8: 거래량
- 20: 기관순매수
- …
instStockChart.SetInputValue(5, 5)
이는 씨젠의 종가 데이터를 받아오겠다는 말이다. 이러한 필드의 종류는 0번부터 37번까지로 총 38가지가 있고, 각자의 상세한 용법은 공식 도움말을 참조하자. 그런데 이 입력데이터에서처럼 정수를 사용하지 않는 것도 아닌데 왜 요청구분(1)은 굳이 캐릭터를 받는지, 받는건 둘째 치더라도 헷갈리게 ‘1’과 ‘2’인 이유가 무엇인지는 알 수 없다. 그러려니 하고 넘어가야한다.
이제 종합적으로 위 코드가 어떤 데이터를 요구하는지에 대해 알아보자.
days = 10
instStockChart = win32com.client.Dispatch("CpSysDib.StockChart")
instStockChart.SetInputValue(0, seegene)
instStockChart.SetInputValue(1, ord('2'))
instStockChart.SetInputValue(4, days)
instStockChart.SetInputValue(5, 5)
instStockChart.SetInputValue(6, ord('D'))
instStockChart.SetInputValue(9, ord('1'))
위에서부터 다음과 같다.
- 0 - 종목코드
- 씨젠 (A096530)
- 1 - 요청구분
- ‘2’: 개수
- 4 - 요청개수
- days (10). 열흘간의 데이터를 요청할 것이다.
- 5 - 필드
- 5: 종가. 장을 마감할 때의 가격이다.
- 6 - 차트구분
- ‘D’: 일간 데이터
- 9 - 수정주가
- ‘1’: 수정주가. 증자, 액분 등 어떤 사유에서든 주가의 단위가 바뀌었더라도 현재 가격에 맞는 비율로 주가를 수정해주는지에 대한 여부다. 씨젠은 21년 전반기에 무상증자를 한 바 있으니 수정주가로 요청하는 것이 바람직할 것이다.
이에 따라 instStockChart
오브젝트는 데이터를 요청했을 때 ‘씨젠의 일일 종가를 수정주가로 최근 10일치만큼’ 받아온다. 이 오브젝트의 프로퍼티를 세팅해준것과 마찬가지다.
instStockChart.BlockRequest()
이제 object.BlockRequest()
메소드를 실행시키면 지정한대로의 데이터를 받아온다. 사실 이런 부분을 보면 사고방식 자체는 파이썬다운것을 알 수 있다.
numData = instStockChart.GetHeaderValue(3)
for i in range(numData):
print(instStockChart.GetDataValue(0, i), end = ', ')
GetHeaderValue()
: 수신된 헤더 데이터를 리턴한다. 데이터와의 차이는 약간 메타데이터인지 아닌지 정도인 것 같은데, 모듈마다도 조금씩 다르니 직접 공식 도움말을 보고 이해하는 게 빠를 것이다.
- 3: 받아온 데이터의 갯수를 요청한다. 이 예제에선 애초에 10일치를 요청했으니
numData
는 정확히 10일 것이다. 기간으로 요청할 경우 거래일 기준으로 받아오기 때문에 이 값이 얼마든지 달라질 수 있다.
GetDataValue(Type,index)
: 수신된 데이터를 리턴한다.
Type
번째로 요청한 타입의index
번째 값을 리턴한다. 이 예제에선 종가 하나만을 요청했으니 0번째 타입인 종가의i
번째 값을 리턴하는 게 될 것이다.
전체 코드
import win32com.client
instCpCybos = win32com.client.Dispatch("CpUtil.CpCybos")
if instCpCybos.IsConnect:
print("Cybos Plus Connected...")
instCpStockCode = win32com.client.Dispatch("CpUtil.CpStockCode")
seegene = instCpStockCode.NameToCode("씨젠")
days = 10
instStockChart = win32com.client.Dispatch("CpSysDib.StockChart")
instStockChart.SetInputValue(0, seegene)
instStockChart.SetInputValue(1, ord('2'))
instStockChart.SetInputValue(4, days)
instStockChart.SetInputValue(5, 5)
instStockChart.SetInputValue(6, ord('D'))
instStockChart.SetInputValue(9, ord('1'))
instStockChart.BlockRequest()
numData = instStockChart.GetHeaderValue(3)
for i in range(numData):
print(instStockChart.GetDataValue(0, i), end = ', ')