CYBOS PLUS/CREON PLUS API 를 이용하여 간단한 분차트를 그리는 예제 코드입니다 

차트는 matplotlib 라이브러리를 이용했습니다 

matplotlib 사용방법이 은근히 까다롭네요 


화면 좌 상단에는 파생 종목 코드 리스트를 콤보에 넣어 종목을 선택할 수 있게 했습니다. 



[전체 코드]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
import datetime
import sys
import ctypes
import time
 
import numpy as np
from PyQt5.QtWidgets import *
import win32com.client
import pandas as pd
import os
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.finance as matfin
import matplotlib.ticker as ticker
 
C_DT = 0    # 일자
C_TM = 1    # 시간
C_OP = 2    # 시가
C_HP = 3    # 고가
C_LP = 4    # 저가
C_CP = 5    # 종가
C_VL = 6    # 거래량
C_MA5 = 7    # 5일 이동평균
C_MA10 = 8    # 10일 이동평균
C_MA20 = 9    # 20일 이동평균
 
 
 
g_objCodeMgr = win32com.client.Dispatch('CpUtil.CpCodeMgr')
g_objCpStatus = win32com.client.Dispatch('CpUtil.CpCybos')
g_objCpTrade = win32com.client.Dispatch('CpTrade.CpTdUtil')
g_objFutureMgr = win32com.client.Dispatch("CpUtil.CpFutureCode")
def InitPlusCheck():
    # 프로세스가 관리자 권한으로 실행 여부
    if ctypes.windll.shell32.IsUserAnAdmin():
        print('정상: 관리자권한으로 실행된 프로세스입니다.')
    else:
        print('오류: 일반권한으로 실행됨. 관리자 권한으로 실행해 주세요')
        return False
 
    # 연결 여부 체크
    if (g_objCpStatus.IsConnect == 0):
        print("PLUS가 정상적으로 연결되지 않음. ")
        return False
 
    # 주문 관련 초기화
    if (g_objCpTrade.TradeInit(0!= 0):
        print("주문 초기화 실패")
        return False
 
    return True
 
 
 
 
class CpFutureChart:
    def __init__(self):
        self.objFutureChart = win32com.client.Dispatch("CpSysDib.FutOptChart")
 
 
    # 차트 요청 - 분간, 틱 차트
    def RequestMT(self, code, dwm, count, caller):
        # 연결 여부 체크
        bConnect = g_objCpStatus.IsConnect
        if (bConnect == 0):
            print("PLUS가 정상적으로 연결되지 않음. ")
            return False
 
        self.objFutureChart.SetInputValue(0, code)  # 종목코드
        self.objFutureChart.SetInputValue(1, ord('2'))  # 개수로 받기
        self.objFutureChart.SetInputValue(4, count)  # 조회 개수
        self.objFutureChart.SetInputValue(5, [0123458])  # 요청항목 - 날짜, 시간,시가,고가,저가,종가,거래량
        self.objFutureChart.SetInputValue(6, dwm)  # '차트 주기 - 분/틱
        self.objFutureChart.SetInputValue(71)  # 분틱차트 주기
        self.objFutureChart.SetInputValue(8, ord('1'))  # 갭보정
        self.objFutureChart.SetInputValue(9, ord('1'))  # 수정주가 사용
        self.objFutureChart.BlockRequest()
 
        rqStatus = self.objFutureChart.GetDibStatus()
        rqRet = self.objFutureChart.GetDibMsg1()
        print("통신상태", rqStatus, rqRet)
        if rqStatus != 0:
            exit()
 
        len = self.objFutureChart.GetHeaderValue(3)
 
        caller.chartData = {}
        caller.chartData[C_DT] = []
        caller.chartData[C_TM] = []
        caller.chartData[C_OP] = []
        caller.chartData[C_HP] = []
        caller.chartData[C_LP] = []
        caller.chartData[C_CP] = []
        caller.chartData[C_VL] = []
        caller.chartData[C_MA5] = []
        caller.chartData[C_MA10] = []
        caller.chartData[C_MA20] = []
 
        for i in range(len):
            caller.chartData[C_DT].insert(0, self.objFutureChart.GetDataValue(0, i))
            caller.chartData[C_TM].insert(0, self.objFutureChart.GetDataValue(1, i))
            caller.chartData[C_OP].insert(0, self.objFutureChart.GetDataValue(2, i))
            caller.chartData[C_HP].insert(0, self.objFutureChart.GetDataValue(3, i))
            caller.chartData[C_LP].insert(0, self.objFutureChart.GetDataValue(4, i))
            caller.chartData[C_CP].insert(0, self.objFutureChart.GetDataValue(5, i))
            caller.chartData[C_VL].insert(0, self.objFutureChart.GetDataValue(6, i))
 
        #print(self.objFutureChart.Continue)
 
 
        return
 
 
 
class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
 
        # plus 상태 체크
        if InitPlusCheck() == False:
            exit()
 
 
        # 기본 변수들
        self.chartData = {}
        self.code = ''
        self.isRq = False
 
        self.objChart = CpFutureChart()
 
        self.sizeControl()
        # 선물 종목 코드 추가
        for i in range(g_objFutureMgr.GetCount()):
            code = g_objFutureMgr.GetData(0, i)
            self.comboStg.addItem(code)
        self.comboStg.setCurrentIndex(0)
 
 
 
    def sizeControl(self) :
        # 윈도우 버튼 배치
        self.setWindowTitle("PLUS API TEST")
 
        self.setGeometry(50501200600)
        self.comboStg = QComboBox()
        #self.comboStg.move(20, nH)
        self.comboStg.currentIndexChanged.connect(self.comboChanged)
        #self.comboStg.resize(100, 30)
        self.label = QLabel('종목코드')
        #self.label.move(140, nH)
 
        # Figure 를 먼저 만들고 레이아웃에 들어 갈 sub axes 를 생성 한다.
        self.fig = plt.Figure()
        self.canvas = FigureCanvas(self.fig)
 
 
        # top layout
        topLayout = QHBoxLayout()
        topLayout.addWidget(self.comboStg)
        topLayout.addWidget(self.label)
        topLayout.addStretch(1)
        # topLayout.addSpacing(20)
 
        chartlayout = QVBoxLayout()
        chartlayout.addWidget(self.canvas)
 
 
        layout = QVBoxLayout()
        layout.addLayout(topLayout)
        layout.addLayout(chartlayout)
        layout.setStretchFactor(topLayout, 0)
        layout.setStretchFactor(chartlayout, 1)
 
        self.setLayout(layout)
 
    # 분차트 받기
    def RequestMinChart(self):
        if self.objChart.RequestMT(self.code, ord('m'), 100, self) == False:
            exit()
 
    def makeMovingAverage(self, maData, interval):
        #maData = []
        for i in range(0len(self.chartData[C_DT])) :
            if (i < interval) :
                maData.append(float('nan'))
                continue
            sum = 0
            for j in range (0, interval) :
                sum += self.chartData[C_CP][i - j]
            ma = sum / interval
            maData.append(ma)
        # print(maData)
 
 
    def drawMinChart(self):
        # 기존 거 지운다.
        self.fig.clf()
 
        # 211 - 2(행) * 1(열) 배치 1번째
        self.ax1 = self.fig.add_subplot(2,1,1)
        # 212 - 2(행) * 1(열) 배치 2번째
        self.ax2 = self.fig.add_subplot(2,1,2)
 
        ###############################################
        # 봉차트 그리기
        # self.ax1.xaxis.set_major_formatter(ticker.FixedFormatter(schartData[C_TM]))
        matfin.candlestick2_ohlc(self.ax1, self.chartData[C_OP], self.chartData[C_HP], self.chartData[C_LP], self.chartData[C_CP],
                                  width=0.8, colorup='r', colordown='b')
 
 
        ###############################################
        # x 축 인덱스 만들기 - 기본 순차 배열 추가
        x_tick_raw =  [i for i in range(len(self.chartData[C_DT]))]
        # x 축 인덱스 만들기 - 실제 화면에 표시될 텍스트 만들기
        x_tick_labels = []
 
        startDate = 0
        dateChanged = True
        for i in range(len(self.chartData[C_DT])) :
            # 날짜 변경 된 경우 날짜 정보 저장
            date = self.chartData[C_DT][i]
            if (date != startDate) :
                yy, mm = divmod(date, 10000)
                mm,dd = divmod(mm, 100)
                sDate = '%2d/%d '%(mm,dd)
                print(sDate)
                startDate = date
                dateChanged = True
 
            # 0 분 또는 30분 단위로 시간 표시
            hhh, mmm = divmod(self.chartData[C_TM][i], 100)
            stime = '%02d:%02d' % (hhh, mmm)
            if (mmm == 0 or mmm == 30):
                if dateChanged == True:
                    sDate += stime
                    x_tick_labels.append(sDate)
                    dateChanged = False
                else:
                    x_tick_labels.append(stime)
            else:
                x_tick_labels.append('')
 
 
        ###############################################
        # 이동 평균 그리기
        self.ax1.plot(x_tick_raw, self.chartData[C_MA5], label='ma5')
        self.ax1.plot(x_tick_raw, self.chartData[C_MA10], label='ma10')
        self.ax1.plot(x_tick_raw, self.chartData[C_MA20], label='ma20')
 
 
        ###############################################
        # 거래량 그리기
        self.ax2.bar(x_tick_raw, self.chartData[C_VL])
 
        ###############################################
        # x 축 가로 인덱스 지정
        self.ax1.set(xticks=x_tick_raw, xticklabels=x_tick_labels)
        self.ax2.set(xticks=x_tick_raw, xticklabels=x_tick_labels)
 
        self.ax1.grid()
        self.ax2.grid()
        plt.tight_layout()
        self.ax1.legend(loc='upper left')
 
        self.canvas.draw()
 
 
    def comboChanged(self):
        if self.isRq == True:
            return
        self.isRq = True
        self.code = self.comboStg.currentText()
        self.name = g_objFutureMgr.CodetoName(self.code)
        self.label.setText(self.name)
        self.RequestMinChart()
        self.makeMovingAverage(self.chartData[C_MA5], 5)
        self.makeMovingAverage(self.chartData[C_MA10], 10)
        self.makeMovingAverage(self.chartData[C_MA20], 20)
        self.drawMinChart()
        self.isRq = False
 
 
        #self.requestStgID(cur)
 
 
 
 
 
if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = MyWindow()
    myWindow.show()
    app.exec_()
 
 
cs


가장 까다로웠던 차트 인덱스 그리기 부분

matplotlib 는 X 축을 항상 연속으로 그리게 되어 있어 있습니다 

15:10분 이후에 거래가 없어서 15:15 분 데이터가 있으면 matplotlib 에서는 자동으로 X 축에 15:11~15:14 분을 채워넣네요 

이 부분을 방지하기 위해 가로축 기본 데이터는 그냥 0 ~ 데이터 개수 만큼 순차적으로 세팅하고 

라벨 부분만 원하는 문자열을 채워 넣었습니다.

관련 코드는 아래 부분 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        ###############################################
        # x 축 인덱스 만들기 - 기본 순차 배열 추가
        x_tick_raw =  [i for i in range(len(self.chartData[C_DT]))]
        # x 축 인덱스 만들기 - 실제 화면에 표시될 텍스트 만들기
        x_tick_labels = []
 
        startDate = 0
        dateChanged = True
        for i in range(len(self.chartData[C_DT])) :
            # 날짜 변경 된 경우 날짜 정보 저장
            date = self.chartData[C_DT][i]
            if (date != startDate) :
                yy, mm = divmod(date, 10000)
                mm,dd = divmod(mm, 100)
                sDate = '%2d/%d '%(mm,dd)
                print(sDate)
                startDate = date
                dateChanged = True
 
            # 0 분 또는 30분 단위로 시간 표시
            hhh, mmm = divmod(self.chartData[C_TM][i], 100)
            stime = '%02d:%02d' % (hhh, mmm)
            if (mmm == 0 or mmm == 30):
                if dateChanged == True:
                    sDate += stime
                    x_tick_labels.append(sDate)
                    dateChanged = False
                else:
                    x_tick_labels.append(stime)
            else:
                x_tick_labels.append('')
cs



  1. Psalms23 2018.05.19 15:37 신고

    감사합니다
    Python을 공부하고있는 초보생입니다
    주식에 관련하여서 자료를 찾다보니 귀한 소스 코드를 올려주셔서 열공중입니다.

    또한 방문한 곳의 사진을 소소하게 올려주셔서 글도 잘읽고 있습니다
    저도 언제 저런곳을 여행해볼수있을지 동경의 대상이 되고있습니다~~^^ 부럽스니당~~ㅠ

    윗글을 보면서 궁금사항들이있어서 메일로 궁금사항을 보내드리고 싶은데.....
    못찾고있습니다.
    자세한 내용을 메일로 요청드리고 싶습니다.

    • BlogIcon esstory 2018.05.19 21:40 신고

      블로그 댓글로 힘드신 내용인가요 ?
      우선 비밀댓글로라도 간단히 올려주시면 추가 답변 드리겠습니다
      그리고 파이썬 주식 트레이딩 카페에 좋은 코드와 고수들이 많으니 참고해 봐 주세요

      http://cafe.naver.com/pystock

+ Recent posts