저번 강의에서는 종목명/종목 코드를 가져왔었죠. 이번 강의에서는 종목의 현재가까지 가져와 우리가 테이블 위젯에 업데이트해 보겠습니다. 기초반에서 했던 거지만(아래 링크 참조) 복습한다 생각하시고 따라오세요.
1. 현재가 가져오기
종목명/종목코들 가져왔으니 이번에는 현재가를 가져오겠습니다. 현재가는 다양한 방면으로 응용될 수 있습니다. 혹시 잘 모르겠으면 이전 강의 또는 기초반 강의를 참고하세요.
우선 현재가를 가져오기 위해 아래와 같이 코딩을 합니다.
- self.getItemInfo(self.new_code) : 이전 강의에서 self.new_code에 우리가 확인하고자 하는 종목의 코드를 입력하였죠. self. getItemInfo()라는 함수를 만들어 코드를 넣어 줍니다.
(1) 현재가 요청하기 : KOA Studio opt10001 주식기본정보요청
KOA Studio opt10001 주식 기본정보 요청하기를 사용할 것입니다. 이 함수를 사용하면 원하는 종목의 현재가뿐만 아니라 액면가/자본금/상장주식/신용비율/PER/EPS 등등의 상당히 많은 데이터를 받아 올 수 있는데 우리는 현재가만 뽑아내겠습니다.
- def getItemInfo(self, new_code) : 앞서 전달해온 self.new_code의 코드번호를 new_code로 받습니다.
- self.k.kiwoom.dynamicCall(~new_code) : 위의 KOA Studio에서 원하는 값을 입력하는데 SetInputValue를 통해 종목코드 번호를 우선 입력합니다.
- self.k.kiwoom.dynamicCall("opt1001,0,"100") : 다음으로 sTrCode인 opt10001을 입력하고 스크린 넘버는 100을 입력 후 CommRqData를 통해 현재가를 요청합니다.
- self.detail_account_info_event_loop.exec_() : 이벤트 루프를 동작하여 키움 서버로부터 원하는 값이 반환될 때까지 기다려 줍니다.
(2) 현재가 수신하기
이전 강의에서 반환되는 데이터는 OnReceiveTrData 함수를 통해 trdata_slot에 반환되게 끔 만들었었죠?
그러면 코딩 설명드리겠습니다.
- if sTrCdoe == "opt10001" : sTrCdoe가 opt10001일 경우 아래 코드를 실행합니다.
- if sRQName == "주식 기본정보 요청" : 혹시 여러 군대서 opt10001을 요청할 수 있기 때문에(주식 프로그램이 너무 방대해질 경우) 반환되는 sRQName이 주식 기본정보 요청일 경우 아래 코드를 실행하게 한 번 더 필터링합니다.
- GetCommData를 통해 우리가 원하는 종목의 현재가를 currentPrice에 받아 옵니다. 이때 int를 통해 문자를 정수로 치환하고 정수 앞에 붙어있는 기호를 제거하기 위해 abs(절댓값)을 취합니다.
- row_count = self.buylast.rowCount() : 조금 후 설명드릴 텐데 우리가 저장할 테이블 위젯의 objectName이 buylast이고 rowCount() 함수를 통해 몇 개의 행이 있는지 확인합니다.
- self.buytlast.setItem(row_count - 1, 2, QTableWidgetItem(str(format(int(currentPrice), ", ")))) : 이 부분이 조금 중요한데 우리가 만든 테이블 위젯의 첫 번째 행에는 행의 목차가 들어가 있고 두 번째 행부터 원하는 값이 들어가게 됩니다. 따라서, 첫 행이 비어 있을 지라도 목차로 인해 2행이라고 반환되어 마이너스 1을 해줌으로써 목차를 생략한 1행이다라고 재명 시해 주는 것입니다. 그리고 QTableWidgetItem을 이용하여 currentPrice를 넣을 것인데 3열에 넣기 위해 2를 넣습니다. 반복적으로 말씀드리지만 파이썬은 처음이 0 두 번째가 1로 시작합니다. 2는 3번째 열을 뜻합니다.
2. 종목명/종목코드/현재가/매수 가격/매수수량/매도 가격/매도수량 전부 QtableWidget에 입력하기
아래 코드를 보시면 크게 (1) 표 세팅하기, (2) 원하는 값 입력하기가 있습니다.
(1) QTableWidget 셋팅하기
아래 그림은 우리가 만든 GUI ALBA2.ui이며 QTableWidget의 objectName은 buylast입니다.
-column_head = ["종목코드", "종목명", "현재가", "매수가격_1", ....] : 우리가 만들 표의 목차를 만드는 것입니다. 목차는 종목코드/종목명/현재가 및 매수가격1/매수수량1/~매도가격4/매도수량4 까지 총 19개를 입력합니다.
- colCount = len(column_head) : 열의 개수(목차의 개수)를 계산합니다.
- row_count = self.buylast.rowCount() : 행의 개수를 계산합니다.
- self.buylast.setColumnCount(colCount) : setColumnCount를 통해 표의 열 개수 만큼 생성합니다.
- self.buylast.setRowCount(colCount) : setRowCount를 통해 표의 행 개수를 생성합니다.
- setHorizontalHeaderLabels(colum_head) : 우리가 만든 목차를 표에 삽입합니다.
(2) 표에 원하는 값 집어넣기
지금부터는 간단합니다. 오로지 setItem을 통해 우리가 원하는 값을 집어넣기만 하면 됩니다.
-self.buylast.setItem(row_count, 0, QTalbeWidgetItem(str(self.new_code))) : 종목코드번호를 setItem과 QTalbeWidgetItem함수를 이용해 0열에 집어넣습니다.
-self.buylast.setItem(row_count, 0, QTalbeWidgetItem(str(self.itemNmae))) : 종목 이름을 setItem과 QTalbeWidgetItem함수를 이용해 1열에 집어넣습니다.
-self.getItemInfo(self.new_code) : 원하는 종목의 현재가를 입력합니다. 위에서 함수 세팅하셨죠?
나머지는 다 동일하니 생략하도록 하겠습니다.
3. GUI 정렬과 초기화
이 부분도 기초반에서 열심히 설명한 부분이라 간단히 넘어가도록 하겠습니다. 부족하신 분들은 기초반 강의를 타고 넘어가 확인하시면 자세히 설명되어 있습니다.
아래 그림을 보시면 setTextAligment를 이용해 GUI 들어가는 값의 좌/우/상/하 정렬을 조정할 수 있습니다.
(1) GUI 입력값 정렬
GUI의 디자인을 위해 입력값의 상/하/좌/우 정렬을 합니다.
- 원하는 QtableWidget의 objectName을 입력하고 itme함수와 setTextAlignment 함수를 통해 원하는 세팅을 실시합니다. Qt.AlignVCenter를 통해 상/중/하 중 중앙 정렬하시고 Qt.AlignRight를 통해 좌/중/우 중 우측 정렬을 하십시오.
(2) 초기화
우리가 원하는 종목의 이름/코드/현재가/매수매도 수량 등을 입력한 후 다음 종목 입력을 위해 setValue(0)을 통해 초기화합니다.
4. 결론 및 최종 코드
아래 그림을 보시면 최종 GUI로 종목명을 입력하고 종목 추가를 누를 시 오른쪽 표에 우리가 매수/매도하고자 하는 종목의 모든 정보가 입력되는 것을 확인할 수 있습니다. 이로써 분할 매수/매도할 준비가 끝났습니다. 다음 강의에서는 사용자 편의성을 위해 DB에 관한 입력 사항을 알아보겠습니다.
코드공유
import sys # system specific parameters and functions : 파이썬 스크립트 관리
from PyQt5.QtWidgets import * # GUI의 그래픽적 요소를 제어 하단의 terminal 선택, activate py37_32, pip install pyqt5, 전부다 y
from PyQt5 import uic # ui 파일을 가져오기위한 함수
from PyQt5.QtCore import * # 쓰레드 함수를 불러온다.
################# 부가 기능 수행(일꾼) #####################################
from kiwoom import Kiwoom # 키움증권 함수/공용 방 (싱글턴)
from Qthread_1 import Thread1 # 계좌평가잔고내역 가져오기
from Qthread_2 import Thread2 # 계좌 관리
from Qthread_3 import Thread3 # 실시간 자동매매 시작
###################################################
form_thirdwindow = uic.loadUiType("ALBA3.ui")[0]
class Thirdwindow(QMainWindow, QWidget, form_thirdwindow):
def __init__(self):
super(Thirdwindow, self).__init__()
self.initUi()
self.show()
### 초기 셋팅 : 분할 매수/매도
self.textEdit_1.setValue(0) # 초기 매수 금액
self.textEdit_2.setValue(0) # 초기 매수 금액
self.textEdit_3.setValue(0) # 초기 매수 금액
self.textEdit_4.setValue(0) # 초기 매수 금액
self.textEdit_5.setValue(0) # 초기 매수 금액
self.textEdit_6.setValue(0) # 초기 매수 금액
self.textEdit_7.setValue(0) # 초기 매수 금액
self.textEdit_8.setValue(0) # 초기 매수 금액
self.textEdit_9.setValue(0) # 초기 매수 금액
self.textEdit_10.setValue(0) # 초기 매수 금액
self.textEdit_11.setValue(0) # 초기 매수 금액
self.textEdit_12.setValue(0) # 초기 매수 금액
self.textEdit_13.setValue(0) # 초기 매수 금액
self.textEdit_14.setValue(0) # 초기 매수 금액
self.textEdit_15.setValue(0) # 초기 매수 금액
self.textEdit_16.setValue(0) # 초기 매수 금액
########## 더블 스핀 박스 우측정렬 및 소수점 삭제
self.textEdit_1.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_1.setDecimals(0)
self.textEdit_2.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_2.setDecimals(0)
self.textEdit_3.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_3.setDecimals(0)
self.textEdit_4.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_4.setDecimals(0)
self.textEdit_5.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_5.setDecimals(0)
self.textEdit_6.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_6.setDecimals(0)
self.textEdit_7.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_7.setDecimals(0)
self.textEdit_8.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_8.setDecimals(0)
self.textEdit_9.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_9.setDecimals(0)
self.textEdit_10.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_10.setDecimals(0)
self.textEdit_11.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_11.setDecimals(0)
self.textEdit_12.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_12.setDecimals(0)
self.textEdit_13.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_13.setDecimals(0)
self.textEdit_14.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_14.setDecimals(0)
self.textEdit_15.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_15.setDecimals(0)
self.textEdit_16.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.textEdit_16.setDecimals(0)
####키움증권에 멸령을 보낼 수 있는 싱글턴 가져오기
self.k = Kiwoom() # Kiwoom()을 실행하며 상속 받는다. Kiwoom()은 전지적인 아이다.
###### EventLoop
self.detail_account_info_event_loop = QEventLoop() # 계좌 이벤트루프
################# 부가기능 1 : 종목선택하기 새로운 종목 추가 및 삭제
self.k.kiwoom.OnReceiveTrData.connect(self.trdata_slot) # 키움서버 데이터 받는 곳
self.additmelast.clicked.connect(self.searchItem2) # 종목 추가
def searchItem2(self): # 종목추가시 사용됨.
self.itemName = self.searchItemTextEdit2.toPlainText()
self.new_code = None
if self.itemName != "":
for code in self.k.All_Stock_Code.keys(): # 포트폴리오에 저장된 코드들을 실시간 등록
# 주식체결 정보 가져오기(틱 데이터) : 현재가, 전일대비, 등락률, 매도호가, 매수호가, 거래량, 누적거래량, 고가, 시가, 저가
if self.itemName == self.k.All_Stock_Code[code]['종목명']:
self.new_code = code
if self.new_code != "" and self.itemName == "":
self.new_code = self.searchItemTextEdit3.toPlainText().strip()
for code in self.k.All_Stock_Code.keys(): # 포트폴리오에 저장된 코드들을 실시간 등록
if self.new_code == code:
self.itemName = self.k.All_Stock_Code[code]['종목명']
column_head = ["종목코드", "종목명", "현재가", "매수가격_1", "매수수량_1", "매수가격_2", "매수수량_2", "매수가격_3", "매수수량_3", "매수가격_4", "매수수량_4", "매도가격_1", "매도수량_1", "매도가격_2", "매도수량_2", "매도가격_3", "매도수량_3", "매도가격_4", "매도수량_4"]
colCount = len(column_head)
row_count = self.buylast.rowCount()
self.buylast.setColumnCount(colCount) # 행 갯수
self.buylast.setRowCount(row_count+1) # colum_haed가 한 행을 잡아 먹는다. 실제 입력 되는 값은 1행 부터이다.
self.buylast.setHorizontalHeaderLabels(column_head) # 행의 이름 삽입
self.buylast.setItem(row_count, 0, QTableWidgetItem(str(self.new_code))) # 실제 입력값은 1행부터이나 0부터 들어가야 된다.
self.buylast.setItem(row_count, 1, QTableWidgetItem(str(self.itemName)))
self.getItemInfo(self.new_code)
self.buylast.setItem(row_count, 3, QTableWidgetItem(str(format(int(self.textEdit_1.value()), ","))))
self.buylast.setItem(row_count, 4, QTableWidgetItem(str(format(int(self.textEdit_2.value()), ","))))
self.buylast.setItem(row_count, 5, QTableWidgetItem(str(format(int(self.textEdit_3.value()), ","))))
self.buylast.setItem(row_count, 6, QTableWidgetItem(str(format(int(self.textEdit_4.value()), ","))))
self.buylast.setItem(row_count, 7, QTableWidgetItem(str(format(int(self.textEdit_5.value()), ","))))
self.buylast.setItem(row_count, 8, QTableWidgetItem(str(format(int(self.textEdit_6.value()), ","))))
self.buylast.setItem(row_count, 9, QTableWidgetItem(str(format(int(self.textEdit_7.value()), ","))))
self.buylast.setItem(row_count, 10, QTableWidgetItem(str(format(int(self.textEdit_8.value()), ","))))
self.buylast.setItem(row_count, 11, QTableWidgetItem(str(format(int(self.textEdit_9.value()), ","))))
self.buylast.setItem(row_count, 12, QTableWidgetItem(str(format(int(self.textEdit_10.value()), ","))))
self.buylast.setItem(row_count, 13, QTableWidgetItem(str(format(int(self.textEdit_11.value()), ","))))
self.buylast.setItem(row_count, 14, QTableWidgetItem(str(format(int(self.textEdit_12.value()), ","))))
self.buylast.setItem(row_count, 15, QTableWidgetItem(str(format(int(self.textEdit_13.value()), ","))))
self.buylast.setItem(row_count, 16, QTableWidgetItem(str(format(int(self.textEdit_14.value()), ","))))
############# 좌측 정렬을 우측 정렬로 교체
self.buylast.item(row_count, 0).setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter | Qt.AlignCenter)
self.buylast.item(row_count, 1).setTextAlignment(Qt.AlignVCenter | Qt.AlignLeft)
self.buylast.item(row_count, 2).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 3).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 4).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 5).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 6).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 7).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 8).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 9).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 10).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 11).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 12).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 13).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 14).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 15).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.buylast.item(row_count, 16).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
############################ 초기화
self.textEdit_1.setValue(0) # 초기 매수 금액
self.textEdit_2.setValue(0) # 초기 매수 금액
self.textEdit_3.setValue(0) # 초기 매수 금액
self.textEdit_4.setValue(0) # 초기 매수 금액
self.textEdit_5.setValue(0) # 초기 매수 금액
self.textEdit_6.setValue(0) # 초기 매수 금액
self.textEdit_7.setValue(0) # 초기 매수 금액
self.textEdit_8.setValue(0) # 초기 매수 금액
self.textEdit_9.setValue(0) # 초기 매수 금액
self.textEdit_10.setValue(0) # 초기 매수 금액
self.textEdit_11.setValue(0) # 초기 매수 금액
self.textEdit_12.setValue(0) # 초기 매수 금액
self.textEdit_13.setValue(0) # 초기 매수 금액
self.textEdit_14.setValue(0) # 초기 매수 금액
self.textEdit_15.setValue(0) # 초기 매수 금액
self.textEdit_16.setValue(0) # 초기 매수 금액
def initUi(self):
self.setupUi(self)
def getItemInfo(self, new_code):
self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", new_code)
self.k.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "주식기본정보요청", "opt10001", 0, "100")
self.detail_account_info_event_loop.exec_()
def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):
if sTrCode == "opt10001":
if sRQName == "주식기본정보요청":
currentPrice = abs(int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "현재가")))
#D_R = (self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "신용비율")).strip()
row_count = self.buylast.rowCount()
self.buylast.setItem(row_count - 1, 2, QTableWidgetItem(str(format(int(currentPrice), ","))))
self.detail_account_info_event_loop.exit()
'주식 자동매매 강의 > 중급반(시황 및 차트 구현)' 카테고리의 다른 글
[주식자동매매] 분할 매수/매도 코딩하기(8), 선정 종목 DB 구축(저장, 로드, 삭제) (4) | 2022.07.23 |
---|---|
분할 매수/매도 코딩하기(7), 테이블 위젯(TableWidget)에 선택된 종목(행/열) 정보 삭제하기 (6) | 2022.07.20 |
가치 투자 시 알아야 될 주식 종목 선정하는 방법(기관/외국인 수급, 재무제표, 눌림목의 의미) (5) | 2022.07.16 |
[주식자동매매] 분할 매수/매도 코딩하기(5), 종목명/종목코드 가져오기 (6) | 2022.07.14 |
[주식자동매매] 분할 매수/매도 코딩하기(4), 감시가격/매수수량 입력 GUI 초기화 하기 (10) | 2022.07.14 |