- 자동매매 프로그램 GitHub URL - https://github.com/mujomboy/xingProject.git
- 캔들차트 조회하기 [t8412] 전체 코드
import sys
import pythoncom
import win32com.client
from PyQt5.QtChart import QChart, QChartView, QCandlestickSeries, QCandlestickSet, QDateTimeAxis, \
QValueAxis
from PyQt5.QtCore import QSize, Qt, QDateTime
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QGridLayout
from win32api import Sleep
# 세션 클래스
class SessionEvents:
def __init__(self):
self.state = ""
self.msg = ""
def OnLogin(self, code, msg):
self.state = code
self.msg = msg
print('OnLogin', code, msg)
def OnLogout(self):
print("OnLogout")
def OnDisconnect(self):
print("OnDisconnect")
# 쿼리 클래스
class QueryEvents:
def __init__(self):
self.state = False
self.error = False
self.code = ""
self.msgCode = ""
self.msg = ""
def OnReceiveData(self, code):
print('OnReceiveData', code)
self.code = code
self.state = True
def OnReceiveMessage(self, error, msgCode, msg):
print('OnReceiveMessage', error, msgCode, msg)
self.error = error
self.msgCode = msgCode
self.msg = msg
self.state = True
if error != 0:
self.error = True
class MainScreen(QMainWindow):
def __init__(self, wid, hei):
super().__init__()
self.setWindowTitle("TEST SCREEN") # 프로젝트 타이틀 설정
self.setGeometry(0, 0, int(wid * .5), int(hei * .5)) # 화면 사이즈 설정
self.mainWidget = QWidget() # 메인 위젯 생성
self.mainLayout = QGridLayout(self.mainWidget) # 메인 레이아웃 생성 및 메인 위젯 연결
self.mainLayout.setSpacing(100)
self.setCentralWidget(self.mainWidget) # 메인윈도우 센트럴위젯에 메인 위젯 연결
# 로그인
self.login()
# 쿼리 이벤트 객체 가져오기
self.query = win32com.client.DispatchWithEvents("XA_DataSet.XAQuery", QueryEvents)
# 차트 만들기
self.create_chart('009150', '삼성전기', 0, 0) # 삼성전기
self.create_chart('322000', '현대에너지솔루션', 0, 1) # 현대에너지솔루션
self.create_chart('376180', '피코그램', 1, 0) # 피코그램
self.create_chart('181710', 'NHN', 1, 1) # NHN
self.showMaximized()
def login(self):
# 세션 객체 요청 및 객체 생성
session = win32com.client.DispatchWithEvents("XA_Session.XASession", SessionEvents)
url = 'demo.ebestsec.co.kr' # 모의 투자
# url = 'hts.ebestsec.co.kr' # 실제 투자
session.ConnectServer(url, 200001)
session.Login("아이디", "비번", "", 0, 0)
while session.state == "":
# 로그인 상태 변경 메시지 채크
pythoncom.PumpWaitingMessages()
def create_chart(self, code, name, r, c):
# 차트 데이터 가져오기
self.req_chart_data(code)
chart = QChart() # 차트
chart.legend().hide()
chart.setTitle(name)
axis_x = QDateTimeAxis()
axis_x.setFormat("hh:mm:ss")
axis_y = QValueAxis()
axis_y.setLabelFormat("%i")
series = QCandlestickSeries() # 캔들스틱 시리즈
series.setIncreasingColor(Qt.red) # 상승시 색상
series.setDecreasingColor(Qt.blue) # 하락시 색상
# 조회 시 리턴 파라미터 타입 명 t8412InBlock
outblock1 = "%sOutBlock1" % "t8412"
for i in range(self.query.GetBlockCount(outblock1)):
date = self.query.GetFieldData(outblock1, "date", i).strip() # 날짜
time = self.query.GetFieldData(outblock1, "time", i).strip() # 시간
open = self.query.GetFieldData(outblock1, "open", i).strip() # 시가
high = self.query.GetFieldData(outblock1, "high", i).strip() # 고가
low = self.query.GetFieldData(outblock1, "low", i).strip() # 저가
close = self.query.GetFieldData(outblock1, "close", i).strip() # 종가
dt = QDateTime.fromString(date + time, "yyyyMMddhhmmss")
series.append(QCandlestickSet(float(open), float(high), float(low), float(close), dt.toMSecsSinceEpoch()))
chart.addSeries(series) # 시리즈 연결
chart.addAxis(axis_x, Qt.AlignBottom) # x축 좌표 설정
chart.addAxis(axis_y, Qt.AlignLeft) # y축 좌표 설정
series.attachAxis(axis_x)
series.attachAxis(axis_y)
chart_view = QChartView(chart) # 차트뷰
chart_view.setRenderHint(QPainter.Antialiasing)
self.mainLayout.addWidget(chart_view, r, c) # 메인레이아웃에 차트 배치
def req_chart_data(self, code):
# 주식챠트(N분)데이터 조회에 해당되는 t8412.res 파일이 있는 경로 가져오기
resfile_path = "C:\\Users\\bysik\\PycharmProjects\\xingProject\\res\\t8412.res"
# 조회 시 입력 파라미터 타입 명 t8412InBlock
inblock = "%sInBlock" % "t8412"
# 경로를 통해 res 파일을 로드.
self.query.LoadFromResFile(resfile_path)
# 입력 파리미터를 초기화 합니다.
self.query.SetFieldData(inblock, "shcode", 0, code) # 종목코드
self.query.SetFieldData(inblock, "ncnt", 0, '5') # (N)분 5분 챠트 데이터
self.query.SetFieldData(inblock, "sdate", 0, '20220729') # 시작날짜 2022년 7월 7일
self.query.SetFieldData(inblock, "edate", 0, '20220729') # 종료날짜 2022년 7월 8일
self.query.SetFieldData(inblock, "comp_yn", 0, "N") # 압축여부
# 조회 요청
self.query.Request(0)
while not self.query.state:
# 응답 대기
pythoncom.PumpWaitingMessages()
self.query.state = False
if self.query.error:
self.query.state = False
self.query.error = False
print('REQUEST')
Sleep(900)
self.req_chart_data(code)
if __name__ == '__main__':
app = QApplication(sys.argv)
size: QSize = app.primaryScreen().size() # 모니터 사이즈
main = MainScreen(size.width()/2, size.height())
sys.exit(app.exec_())
소스 코드의 길이가 조금 길다 보니
이번 글에서는 코드의 편한 이해를 돕기 위한 약간의 도움글을 추가하도록 하겠습니다.
1. 이벤트 클래스
# 세션 클래스
class SessionEvents:
def __init__(self):
self.state = ""
self.msg = ""
def OnLogin(self, code, msg):
self.state = code
self.msg = msg
print('OnLogin', code, msg)
def OnLogout(self):
print("OnLogout")
def OnDisconnect(self):
print("OnDisconnect")
# 쿼리 클래스
class QueryEvents:
def __init__(self):
self.state = False
self.error = False
self.code = ""
self.msgCode = ""
self.msg = ""
def OnReceiveData(self, code):
print('OnReceiveData', code)
self.code = code
self.state = True
def OnReceiveMessage(self, error, msgCode, msg):
print('OnReceiveMessage', error, msgCode, msg)
self.error = error
self.msgCode = msgCode
self.msg = msg
self.state = True
if error != 0:
self.error = True
요청 및 응답을 위한 이벤트 클래스 입니다.
일종의 다리 역할을 한다고 보시면 됩니다.
클래스의 이름은 원하시는 이름으로 정하시면 됩니다.
중요한 것은 함수들의 이름입니다.
함수들을 통해 정보를 요청 하고 응답을 해주기 때문에 함수의 이름은 변경하시면 안됩니다.
SessionEvents 클래스는 로그인과 관련된 요청 및 응답을 받기 위한 클래스 입니다.
QueryEvents 클래스는 증권 관련 데이터 요청 및 응답을 받기 위한 클래스 입니다.
2. 로그인
def login(self):
# 세션 객체 요청 및 객체 생성
session = win32com.client.DispatchWithEvents("XA_Session.XASession", SessionEvents)
SessionEvents 클래스 객체 생성을 요청합니다. 생성이 완료되면 객체를 리턴 해줍니다.
url = 'demo.ebestsec.co.kr' # 모의 투자
# url = 'hts.ebestsec.co.kr' # 실제 투자
session.ConnectServer(url, 200001)
session.Login("아이디", "비번", "", 0, 0)
생성된 session 객체를 통해 로그인을 위한 변수들을 입력하고 함수를 호출해 줍니다.
ConnectServer 함수를 통해 필요한 파라미터를 전달합니다. 파라미터에 대한 설명은 아래와 같습니다.
파라미터명 | 설명 |
szServerIP | 연결할 서버주소 |
nServerPort | 연결할 서버포트 |
Login 함수를 통해 필요한 파라미터를 전달합니다. 파라미터에 대한 설명은 아래와 같습니다.
파라미터명 | 설명 |
szID | 로그인 아이디 |
szPwd | 로그인 비밀번호 |
szCertPwd | 공인인증 비밀번호(모의투자 접속시에는 사용안함) |
nServerType | 사용안함 |
bShowCertErrDlg | 공인인증 과정에서 발생한 에러에 대해 미리 정의된 Dialog를 표시할지 여부 |
while session.state == "":
# 로그인 상태 변경 메시지 채크
pythoncom.PumpWaitingMessages()
로그인 진행이 종료 되면 SessionEvents 클래스의 OnLogin 함수가 호출 됩니다.
state 값이 채워지면서 while 문을 탈출 합니다.
3. 차트 데이터 요청
def req_chart_data(self, code):
# 주식챠트(N분)데이터 조회에 해당되는 t8412.res 파일이 있는 경로 가져오기
resfile_path = "C:\\Users\\bysik\\PycharmProjects\\xingProject\\res\\t8412.res"
# 조회 시 입력 파라미터 타입 명 t8412InBlock
inblock = "%sInBlock" % "t8412"
# 경로를 통해 res 파일을 로드.
self.query.LoadFromResFile(resfile_path)
t8412.res 파일은 차트 데이터 요청에 쓰입니다. 경로를 지정해주고 로드해줍니다.
# 입력 파리미터를 초기화 합니다.
self.query.SetFieldData(inblock, "shcode", 0, code) # 종목코드
self.query.SetFieldData(inblock, "ncnt", 0, '5') # (N)분 5분 챠트 데이터
self.query.SetFieldData(inblock, "sdate", 0, '20220729') # 시작날짜 2022년 7월 7일
self.query.SetFieldData(inblock, "edate", 0, '20220729') # 종료날짜 2022년 7월 8일
self.query.SetFieldData(inblock, "comp_yn", 0, "N") # 압축여부
# 조회 요청
self.query.Request(0)
요청을 위해 필요한 파라미터 값들을 세팅해 줍니다.
while not self.query.state:
# 응답 대기
pythoncom.PumpWaitingMessages()
self.query.state = False
요청이 완료 되면 QueryEvents 클래스의 OnReceiveData 함수가 호출됩니다.
state 값이 True 로 바뀌면서 while 문을 탈출 합니다.
state 값은 다시 리셋 해줍니다.
if self.query.error:
self.query.state = False
self.query.error = False
print('REQUEST')
Sleep(900)
self.req_chart_data(code)
요청에 대한 에러 여부를 채크 합니다.
에러가 있을 시 Sleep 함수를 통해 약간의 시차를 둡니다.
그 후 다시 요청 합니다.
에러가 발생한 이유는 요청과 요청사이의 딜레이 시간이 짧으면 조회 자체를 하지 않고 에러를 리턴해 주기 때문입니다.
그래서 약간의 시차를 두고 다시 요청을 시도 합니다.
딜레이를 강제한 이유는 서버의 과부하를 막기 위함 이라고 합니다.
4. 차트 생성
차트 생성부분은 아래 링크를 참조 하시기 바랍니다.
2022.07.20 - [PYQT5/QtChart] - [QtChart] 캔들스틱차트 생성, 타이틀 설정, 데이터 삽입, 색상 변경, 좌표축 설정
'xingAPI > 자동 매매 프로그램 만들기 (PYQT5)' 카테고리의 다른 글
[xingAPI, 파이썬, PYQT5 - QtChart] 주식 이동평균선 만들기 (5) | 2022.08.20 |
---|---|
[xingAPI, 파이썬] 주식차트(N분) 데이터 조회하기 (0) | 2022.07.08 |
[xingApi, 파이썬] 로그인 기능 만들기 (0) | 2022.06.30 |