AUTO TRADE/[대신증권] CYBOS PLUS

대신증권 CYBOS PLUS 프로그램 구현 (5) - 전종목 종목코드 조회하기 ①

  • 종목코드 조회 함수 제작하기
  • GUI 내부에서 종목코드 조회 버튼 생성하기
  • 파이썬 내부에서 종목코드 조회 버튼과 함수 연결하기
  • 종목코드 조회 함수 캡슐화

 

대신증권 CYBOS PLUS에서 종목코드를 조회하는 함수는 CpUtil.CpCodeMgr 모듈의 GetStockListByMarket 함수를 통해 제공되고 있다. 이 함수는 아래의 사진에서 확인할 수 있듯이, 전달된 시장 구분 값에 따라 해당 시장에 소속된 주식 종목코드들을 반환하는 기능을 갖고 있다.

  • 1: 거래소(코스피)
  • 2: 코스닥
  • 3: K-OTC (금투협에서 운영하는 장외주식시장)
  • 4: KRX
  • 5: KONEX

그렇다면 이제 해당 함수에 각각의 데이터를 전달하고 그 결과 데이터를 반환받아보도록 하자.

## CpUtil.py ##
class CpCodeMgr:
def __init__(self):
self.codemgr = win32com.client.Dispatch("CpUtil.CpCodeMgr") ## COM 연결
def _GetStockListByMarket(self, market_kind_code):
"""
:param market_kind_code: GetStockMarketKind 함수의 인자값 참조
1: 거래소, 2: 코스닥, 3: K-OTC, 4: KRX, 5: KONEX
:return : 시장 구분에 따른 주식 종목 배열
"""
value = self.codemgr.GetStockListByMarket(market_kind_code)
print(f"[인자값:{market_kind_code}] 종목코드 목록:{value}")
## 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.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.codemgr._GetStockListByMarket(1)
def _open_cybosplus(self):
if self.cybos._IsConnect() == True: ## 연결되어 있는 경우
print(f"로그인되어 있습니다.")
elif self.cybos._IsConnect() == False:
print(f"로그인되어 있지 않습니다. 로그인을 시도합니다.")
login()
while True:
if self.cybos._IsConnect() == False:
time.sleep(1)
elif self.cybos._IsConnect() == True:
print(f"로그인되었습니다. 반복문에서 나갑니다.")
break
class login:
"""CYBOS PLUS 실행 함수"""
def __init__(self):
self.Id = ""
self.Password = ""
self.Cert = "*"
self.run()
def run(self):
app = application.Application()
executable_path = "C:\\DAISHIN\\STARTER\\ncStarter.exe"
args = f" /prj:cp /id:{self.Id} /pwd:{self.Password} /pwdcert:{self.Cert} /autostart"
app.start(f"{executable_path}{args}")
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = cybos()
myWindow.show()
app.exec_()

▶ 실행 결과 확인하기

더보기

[통신결과:0] 서버와의 연결에 실패했습니다.
[통신결과:0] 서버와의 연결에 실패했습니다.
[통신결과:0] 서버와의 연결에 실패했습니다.
[통신결과:0] 서버와의 연결에 실패했습니다.
[통신결과:1] 서버와의 연결에 성공했습니다.
[통신결과:1] 서버와의 연결에 성공했습니다.
로그인되었습니다. 반복문에서 나갑니다.
[인자값:1] 종목코드 목록:('A000020', 'A000040', 'A000050', 'A000070', 'A000075', · · · (중략) · · ·  'Q760013')

여기까지의 내용에 따르면, 실질적으로 우리는 1번과 2번 데이터를 주로 사용하게 될 것이지만 경우에 따라서는 3번, 4번, 5번 데이터를 전달하여 결과값을 확인할 수도 있기 때문에 어떠한 데이터를 전달할지에 대해서는 재량이 있어야 한다. 이 때 우리가 떠올려야 할 부분은 바로 '캡슐화'이다. 즉, 이 경우에는 1에서 5까지 다섯 가지의 데이터 유형이 전달될 수 있기 때문에 캡슐화를 통해 어떠한 데이터가 인자로 전달되든지 간에 그 인자를 가지고 올바르게 처리할 수 있도록 하는 것이다. 다만 캡슐화와 관련해서는 조금 더 나중에 구현하도록 하고, 일단 GUI를 먼저 만들어주도록 하자.

 

 


반응형
728x90

 

 

다시 이전에 만들어두었던 main.ui 파일을 열어서 좌측의 PushButton 하나를 드래그해서 화면에 넣어주도록 하자. 그 후에 해당 버튼을 더블클릭해서 이름을 "종목코드 조회"로 바꿔준 후에, 그 버튼을 클릭(활성화)한 상태로 Qt Designer의 우측을 보면 해당 버튼의 객체 이름이 pushButton라고 적혀 있는 것을 확인할 수 있다. 여기서의 pushButton, 즉 객체 이름이 우리의 코드에 필요한 이름이니 기억해두도록 하자.

 

 

앞서 살펴봤던 pushButton은 단순한 하나의 객체 이름에 해당할 뿐, 이 pushButton이 어떠한 기능을 수행할 수 있는지에 대해서는 우측의 클래스 행에 표기되어 있는 QPushButton을 살펴보아야 한다. 다만 여기서 클래스라고 적혀 있는 부분에서 우리는 '아. 이 클래스가 갖고 있는 여러 가지 함수를 사용할 수 있겠구나.'하는 생각을 할 수 있어야 한다. 이 클래스를 대표하는 함수는 clicked라는 함수인데, 이는 말 그대로 '클릭됐을 때'를 의미한다. 그렇다면 pushButton이 클릭됐을 때를 코드로 표현할 때에는 어떻게 표현할 수 있을까 ? 아래와 같이 표현할 수 있다.

## clicked ##
self.pushButton.clicked

물론 이 역시도 깊게 알아보자면, 사실 QPushButton이라는 클래스는 clicked라는 이벤트를 발생시킨다. 즉, 우리가 이전에 이벤트 처리기를 생성하여 해당 이벤트가 발생했을 때 그 이벤트를 처리할 함수를 별도로 지정해주었듯이 이 경우에도 그 이벤트를 처리할 함수와 연결해주어야 한다. 따라서 이제 이 버튼이 클릭됐을 때(=이벤트가 발생했을 때) 수행할 작업과 연결하는 작업이 필요한데, 그 기능은 connect가 수행하게 된다.

## connect ##
self.pushButton.clicked.connect(수행할 함수)

위의 코드를 해석하자면, self.pushButton 객체에서 clicked라는 이벤트가 발생했을 때, 수행할 함수를  connect하라는 내용으로 볼 수 있다. 여기서 우리가 아직 수행할 함수를 정확하게 지정해주지는 않았지만, 대충 어떠한 구조의 함수가 들어가야 할지는 어렵지 않게 예측할 수 있을 것이다. 일단 Boss.py 파일 내부에서 self.pushButton의 이벤트를 처리하는 코드를 넣어주도록 하자.

이와 더불어, QPushButton 등과 같은 클래스를 사용하기 위해서는 반드시 self.setupUi(self)라는 구문을 추가해주어야 한다. 만약 이 구문 없이 코드를 실행하게 되면 AttributeError: 'cybos' object has no attribute 'pushButton'라는 에러가 발생하게 되는데, 이는 간단하게 설명하자면 현재 pushButton을 사용할 수 없기 때문에 발생하는 오류이다. 즉, setupUi 함수를 사용하지 않으면 GUI 내에서 제공되는 버튼을 사용할 수 없다는 것이다.
※ Line: 19, 28

## 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.pushButton.clicked.connect()

▶ 실행 결과 확인하기

더보기

    self.pushButton.clicked.connect()
TypeError: Required argument 'slot' (pos 1) not found

실행 결과를 보면 알겠지만, 에러가 발생한다. 뭔가가 잘못된 것 같지만 사실 잘못되지 않았다. 왜냐하면 우리가 아직 수행할 함수를 지정해주지 않았기 때문이다. 이제 앞에서 작업하다가 멈춘 '캡슐화' 작업을 수행해주도록 하자.

 

 

함수를 하나의 캡슐로 만든다는 것은 이전 게시글에서부터 수도 없이 살펴봤던 내용이기 때문에, 여기서는 간단하게 CpUtil.py 파일 내부에 있는 class CpCodeMgrdef _GetStockListByMarket(self, market_kind_code): 함수의 캡슐화 작업을 진행하도록 하자.

하지만 아래의 코드를 보기 전에 앞서, self.pushButton.clicked.connect()와 같은 코드를 통해 수행할 함수를 지정하여 실행되도록 할 때에는 인자를 함께 전달할 수 없다. 그렇기 때문에 Boss.py 파일 내부의 def _GetStockListByMarket(self): 함수 내부에서 market_kind=1이라는 내용을 추가하여 인자를 함께 전달해줄 수밖에 없다. 이 부분과 관련하여, 우리가 아래에서 구현한 반쪽짜리 캡슐화가 아니라 온전한 캡슐화를 통해 이 함수의 인자로 데이터를 전달할 수 있도록 하는 기능은 다음 게시글에서 구현해보록 하자.
※ Line: 30, 31, 32

## 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.pushButton.clicked.connect()
def _GetStockListByMarket(self):
market_kind = 1
self.codemgr._GetStockListByMarket(market_kind_code=market_kind)
def _open_cybosplus(self):
if self.cybos._IsConnect() == True: ## 연결되어 있는 경우
print(f"로그인되어 있습니다.")
elif self.cybos._IsConnect() == False:
print(f"로그인되어 있지 않습니다. 로그인을 시도합니다.")
login()
while True:
if self.cybos._IsConnect() == False:
time.sleep(1)
elif self.cybos._IsConnect() == True:
print(f"로그인되었습니다. 반복문에서 나갑니다.")
break

▶ 실행 결과 확인하기

더보기

## 버튼 클릭 전

[통신결과:1] 서버와의 연결에 성공했습니다.
로그인되어 있습니다.

## 버튼 클릭 후
[통신결과:1] 서버와의 연결에 성공했습니다.
로그인되어 있습니다.
[인자값:1] 종목코드 목록:('A000020', 'A000040',  · · · (중략) · · ·  'Q760013')

## 버튼 클릭할 때마다
[인자값:1] 종목코드 목록:('A000020', 'A000040',  · · · (중략) · · ·  'Q760013')
[인자값:1] 종목코드 목록:('A000020', 'A000040',  · · · (중략) · · ·  'Q760013')
[인자값:1] 종목코드 목록:('A000020', 'A000040',  · · · (중략) · · ·  'Q760013')

 

 


728x90
반응형

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

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