반응형
9강에서 공유해드린 코드와 연동하여 22강까지의 모든 코드를 공유해 드립니다. 코드에 대한 자세한 설명은 이전 강의에서 설명해 두었습니다. 그리고 다음 주(22.5.14.) 정도부터 유튜브 강의도 제작해 올리겠습니다.
[유튜브 강의, 링크]와 같이 보시면 많은 도움이 되실 겁니다.
1. 현재 프로젝트에 있어야 될 자료 : 4가지
(1) Lecture_0503.py : 메인 스크립트입니다.
(2) Qthread_1.py : 계좌평가잔고내역요청 스레드입니다.
(3) kiwoom.py : 매타 클래스 기반 싱글턴 언어입니다.(절대 언어)
(4) ALBA.uI : 우리가 만든 UI입니다.
2. 각 스크립트의 코드 공개
(1) Lecture_0503.py : 프로그램 실행/키움증권 로그인/스레드 실행 등
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 * # eventloop/스레드를 사용 할 수 있는 함수 가져옴.
################# 부가 기능 수행(일꾼) #####################################
from kiwoom import Kiwoom # 키움증권 함수/공용 방 (싱글턴)
from Qthread_1 import Thread1 # 계좌평가잔고내역 가져오기
#=================== 프로그램 실행 프로그램 =========================#
form_class = uic.loadUiType("ALBA.ui")[0] # 만들어 놓은 ui 불러오기
class Login_Machnine(QMainWindow, QWidget, form_class): # QMainWindow : PyQt5에서 윈도우 생성시 필요한 함수
def __init__(self, *args, **kwargs): # Main class의 self를 초기화 한다.
print("Login Machine 실행합니다.")
super(Login_Machnine, self).__init__(*args, **kwargs)
form_class.__init__(self) # 상속 받은 from_class를 실행하기 위한 초기값(초기화)
self.setUI() # UI 초기값 셋업 반드시 필요
### 초기 셋팅
self.label_11.setText(str("총매입금액"))
self.label_12.setText(str("총평가금액"))
self.label_13.setText(str("추정예탁자산"))
self.label_14.setText(str("총평가손익금액"))
self.label_15.setText(str("총수익률(%)"))
#### 기타 함수
self.login_event_loop = QEventLoop() # 이때 QEventLoop()는 block 기능을 가지고 있다.
####키움증권 로그인 하기
self.k = Kiwoom() # Kiwoom()을 실행하며 상속 받는다. Kiwoom()은 전지적인 아이다.
self.set_signal_slot() # 키움로그인을 위한 명령어 전송 시 받는 공간을 미리 생성한다.
self.signal_login_commConnect()
#####이벤트 생성 및 진행
self.call_account.clicked.connect(self.c_acc) # 계좌정보가져오기
def setUI(self):
self.setupUi(self) # UI 초기값 셋업
def set_signal_slot(self):
self.k.kiwoom.OnEventConnect.connect(self.login_slot) # 내가 알고 있는 login_slot에다가 특정 값을 던져 준다.
def signal_login_commConnect(self):
self.k.kiwoom.dynamicCall("CommConnect()") # 네트워크적 서버 응용프로그램에 데이터를 전송할 수 있게 만든 함수
self.login_event_loop.exec_() # 로그인이 완료될 때까지 계속 반복됨. 꺼지지 않음.
def login_slot(self, errCode):
if errCode == 0:
print("로그인 성공")
self.statusbar.showMessage("로그인 성공")
self.get_account_info() # 로그인시 계좌정보 가져오기
elif errCode == 100:
print("사용자 정보교환 실패")
elif errCode == 101:
print("서버접속 실패")
elif errCode == 102:
print("버전처리 실패")
self.login_event_loop.exit() # 로그인이 완료되면 로그인 창을 닫는다.
def get_account_info(self):
account_list = self.k.kiwoom.dynamicCall("GetLoginInfo(String)", "ACCNO")
for n in account_list.split(';'):
self.accComboBox.addItem(n)
def c_acc(self):
print("선택 계좌 정보 가져오기")
##### 1번 일꾼 실행
h1 = Thread1(self)
h1.start()
if __name__=='__main__': # import된 것들을 실행시키지 않고 __main__에서 실행하는 것만 실행 시킨다.
# 즉 import된 다른 함수의 코드를 이 화면에서 실행시키지 않겠다는 의미이다.
app = QApplication(sys.argv) # PyQt5로 실행할 파일명을 자동으로 설정, PyQt5에서 자동으로 프로그램 실행
CH = Login_Machnine() # Main 클래스 myApp으로 인스턴스화
CH.show() # myApp에 있는 ui를 실행한다.
app.exec_() # 이벤트 루프
(2) Qthread_1.py : 계좌평가 잔고내역 가져오기/GUI에 관련 정보 입력하기 등
from PyQt5.QtCore import * # 쓰레드 함수를 불러온다.
from kiwoom import Kiwoom # 로그인을 위한 클래스
from PyQt5.QtWidgets import * #PyQt import
class Thread1(QThread):
def __init__(self, parent): # 부모의 윈도우 창을 가져올 수 있다.
super().__init__(parent) # 부모의 윈도우 창을 초기화 한다.
self.parent = parent # 부모의 윈도우를 사용하기 위한 조건
################## 키움서버 함수를 사용하기 위해서 kiwoom의 능력을 상속 받는다.
self.k = Kiwoom()
##################
################## 사용되는 변수
self.Acc_Screen = "1000" # 계좌평가잔고내역을 받기위한 스크린
###### 슬롯
self.k.kiwoom.OnReceiveTrData.connect(self.trdata_slot) # 내가 알고 있는 Tr 슬롯에다 특정 값을 던져 준다.
###### EventLoop
self.detail_account_info_event_loop = QEventLoop() # 계좌 이벤트루프
###### 계좌정보 가져오기
self.getItemList() # 종목 이름 받아오기
self.detail_acount_mystock() # 계좌평가잔고내역 가져오기
def getItemList(self):
marketList = ["0", "10"]
for market in marketList:
codeList = self.k.kiwoom.dynamicCall("GetCodeListByMarket(QString)", market).split(";")[:-1]
for code in codeList:
name = self.k.kiwoom.dynamicCall("GetMasterCodeName(QString)", code)
self.k.All_Stock_Code.update({code: {"종목명": name}})
def detail_acount_mystock(self, sPrevNext="0"):
print("계좌평가잔고내역 조회")
account = self.parent.accComboBox.currentText() # 콤보박스 안에서 가져오는 부분
self.account_num = account
print("최종 선택 계좌는 %s" % self.account_num)
self.k.kiwoom.dynamicCall("SetInputValue(String, String)", "계좌번호", account)
self.k.kiwoom.dynamicCall("SetInputValue(String, String)", "비밀번호", "0000") # 모의투자 0000
self.k.kiwoom.dynamicCall("SetInputValue(String, String)", "비밀번호입력매체구분", "00")
self.k.kiwoom.dynamicCall("SetInputValue(String, String)", "조회구분", "2")
self.k.kiwoom.dynamicCall("CommRqData(String, String, int, String)", "계좌평가잔고내역요청", "opw00018", sPrevNext, self.Acc_Screen)
self.detail_account_info_event_loop.exec_()
def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):
if sRQName == "계좌평가잔고내역요청":
column_head = ["종목번호", "종목명", "보유수량", "매입가", "현재가", "평가손익", "수익률(%)"]
colCount = len(column_head)
rowCount = self.k.kiwoom.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)
self.parent.stocklistTableWidget_2.setColumnCount(colCount) # 행 갯수
self.parent.stocklistTableWidget_2.setRowCount(rowCount) # 열 갯수 (종목 수)
self.parent.stocklistTableWidget_2.setHorizontalHeaderLabels(column_head) # 행의 이름 삽입
print("계좌에 들어있는 종목 수 %s" % rowCount)
totalBuyingPrice = int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총매입금액"))
currentTotalPrice = int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총평가금액"))
balanceAsset = int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "추정예탁자산"))
totalEstimateProfit = int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총평가손익금액"))
total_profit_loss_rate = float(self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "총수익률(%)"))
#################################### 텍스트 라벨에 집어 넣기
self.parent.label_1.setText(str(totalBuyingPrice))
self.parent.label_2.setText(str(currentTotalPrice))
self.parent.label_3.setText(str(balanceAsset))
self.parent.label_4.setText(str(totalEstimateProfit))
self.parent.label_5.setText(str(total_profit_loss_rate))
#################################################################
for index in range(rowCount):
itemCode = self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, index, "종목번호").strip(" ").strip("A")
itemName = self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, index, "종목명")
amount = int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, index, "보유수량"))
buyingPrice = int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, index, "매입가"))
currentPrice = int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, index, "현재가"))
estimateProfit = int(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, index, "평가손익"))
profitRate = float(self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, index, "수익률(%)"))
total_chegual_price = self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, index, "매입금액")
total_chegual_price = int(total_chegual_price.strip())
possible_quantity = self.k.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, index, "매매가능수량")
possible_quantity = int(possible_quantity.strip())
if itemCode in self.k.acc_portfolio:
pass
else:
self.k.acc_portfolio.update({itemCode:{}}) # self.account_stock_dict[code] = {}
self.k.acc_portfolio[itemCode].update({"종목명": itemName.strip()})
self.k.acc_portfolio[itemCode].update({"보유수량": amount})
self.k.acc_portfolio[itemCode].update({"매입가": buyingPrice})
self.k.acc_portfolio[itemCode].update({"수익률(%)": profitRate})
self.k.acc_portfolio[itemCode].update({"현재가": currentPrice})
self.k.acc_portfolio[itemCode].update({"매입금액": total_chegual_price})
self.k.acc_portfolio[itemCode].update({"매매가능수량": possible_quantity})
self.parent.stocklistTableWidget_2.setItem(index, 0, QTableWidgetItem(str(itemCode)))
self.parent.stocklistTableWidget_2.setItem(index, 1, QTableWidgetItem(str(itemName)))
self.parent.stocklistTableWidget_2.setItem(index, 2, QTableWidgetItem(str(amount)))
self.parent.stocklistTableWidget_2.setItem(index, 3, QTableWidgetItem(str(buyingPrice)))
self.parent.stocklistTableWidget_2.setItem(index, 4, QTableWidgetItem(str(currentPrice)))
self.parent.stocklistTableWidget_2.setItem(index, 5, QTableWidgetItem(str(estimateProfit)))
self.parent.stocklistTableWidget_2.setItem(index, 6, QTableWidgetItem(str(profitRate)))
if sPrevNext == "2":
self.detail_acount_mystock(sPrevNext="2") # 다음 페이지가 있으면 전부 검색한다.
else:
self.detail_account_info_event_loop.exit() # 끊어 준다.
(3) kiwoom.py : 절대 언어
from PyQt5.QtWidgets import * # GUI의 그래픽적 요소를 제어 하단의 terminal 선택, activate py37_32, pip install pyqt5, 전부다 y
from PyQt5.QAxContainer import * # 키움증권의 클레스를 사용할 수 있게 한다.(QAxWidget)
from PyQt5Singleton import Singleton
class Kiwoom(QWidget, metaclass=Singleton): # QMainWindow : PyQt5에서 윈도우 생성시 필요한 함수
def __init__(self, parent=None, **kwargs): # Main class의 self를 초기화 한다.
print("로그인 프로그램을 실행합니다.")
super().__init__(parent, **kwargs)
################ 로그인 관련 정보
self.kiwoom = QAxWidget('KHOPENAPI.KHOpenAPICtrl.1') # CLSID
################# 전체 공유 데이터
self.All_Stock_Code = {} # 코스피, 코스닥 전체 코드넘버 입력
self.acc_portfolio = {} # 계좌에 들어있는 종목의 코드, 수익률 등등 입력
반응형
3. 프로그램 실행 최종 결과
여기까지 따라오신다고 고생하셨습니다.
이 코드만 다 이해하셔도 응용하셔서 모든 코드 제작이 가능합니다.
다음 강의부터는 계좌정보를 이용해 나의 종목 위험도를 판단해 보겠습니다.
반응형
'주식 자동매매 강의 > 기초반(모든 코딩의 뿌리)' 카테고리의 다른 글
주식자동매매 25강. 계좌 관리하기(2), GUI 및 스크립트 만들기 (0) | 2022.05.12 |
---|---|
주식자동매매 24강. 계좌 관리하기(1), 알고리즘 및 방법 개념 설명 (0) | 2022.05.11 |
주식자동매매 22강. 계좌평가잔고내역요청(10), 멀티데이터 GUI에 삽입하기 (1) | 2022.05.09 |
주식자동매매 20강. 계좌평가잔고내역요청(8), 싱글데이터 삽입하기 (0) | 2022.05.09 |
주식자동매매 19강. 계좌평가잔고내역요청(7), GUI에 텍스트(Text) 라벨(Label) 집어넣기 (0) | 2022.05.08 |