28강에서 opt10045 주문 전송 결과에 대하여 싱글데이터와 멀티데이터를 받아왔습니다. 멀티데이터 중 하나인 기관일별순매수량과 외국인일별순매수량 데이터를 분석하여 계좌 위험도를 판단해 보겠습니다.
[유튜브 강의, 링크]와 같이 보시면 많은 도움이 되실 겁니다.
1. 계좌위험도 판단 함수 만들기
아래 그림과 같이 28강에 연속으로 self.kigwan_meme_dong2() 함수를 실행시키는 문구를 코딩하였습니다. 그리고 함수안에 self.calcul2_data(기관일별순매매수량)과 self.calcul2_data3(외국인일별순매매수량)을 할당하여 두 정보를 가지고 계좌 위험도를 판단해 보겠습니다.
그리고 self.detail_account_info_event_loop.exit() 문구가 코딩되어 있는데 위의 계좌위험도 판단 함수가 종료되면 앞서 주문시 정의 했던 exec_를 종료해주는 역할을 합니다. 키움으로 전송된 명령이 다 수행되면 exec__를 종료하여 다음 코드가 진행되게 해야 겠죠?
2. 계좌위험도 판단 함수 코딩하기
계좌위험도 판단 함수 만들때 self.kigwan_meme_dong2(self.calcul2_data, self.calcul2_data3)를 할당해 주었기 때문에 def kigwan_meme_dong2() 함수에서는 def kigwan_meme_dong2(self, a, c)로 할당 받습니다.
a = self.calcul2_data, b = self.calcul2_data3라 생각하시면 됩니다. 그러면 우리는 10일치의 데이터가 있으나 저 같은 경우 4일치 데이터만 사용해서 계좌 위험도를 판단하기 위해 아래와 같이 코딩하였습니다. (1)을 참고하십시요.
- a = a[0:4]
- c = c[0:4]
- 파이썬의 경우 c[0:4]를 넣게되면 0, 1, 2, 3이 출력됩니다. 파이썬의 법칙이니 이해하시고 외우시면 될 것 같습니다.
위험도를 어떻게 판단했는지 알아 볼까요? 상당히 직관적으로 코딩하였습니다. (2)를 확인하십시요.
- 만약 4일치의 기관/외국인일별순매매수량이 음수(즉 전부 팔았을 때는)면 손절하라고 코딩하였습니다.
- 기관일별순매매수량이 [-3000, -2000, -5000, -4000] 이면 a[0] ~ a[3]까지 모두 0보다 작게 됩니다.
- 외국인일별순매매수량이 [-3000, -2000, -5000, -4000] 이면 a[0] ~ a[3]까지 모두 0보다 작게 됩니다.
- 이러한 조건이 맞춰지면 self.k.acc_portfolio의 현재 선택된 종목의 코드번호를 입력 후 "위험도": "손절" 이라고 저장되게 하였습니다.
if a[0] < 0 and a[1] < 0 and a[2] < 0 and a[3] < 0 and c[0] < 0 and c[1] < 0 and c[2] < 0 and c[3] < 0:
self.k.acc_portfolio[self.code_in_all].update({"위험도": "손절"})
- 아래는 동일하게 코딩하시면 됩니다.
- 만약 3일치 기관/외국인일별순매매수량이 음수(즉 전부 팔았을 때는)면 주의라고 코딩하였습니다.
- 만약 2일치 기관/외국인일별순매매수량이 음수(즉 전부 팔았을 때는)면 관심이라고 코딩하였습니다.
- 그 외의 경우 (1일치 또는 0일치)에서는 위험도가 낮음이라고 코딩하였습니다.
다음 강의에서는 저장된 위험도 판단 데이터를 GUI에 입력하도록 하겠습니다. 이번강의는 정말 중요합니다. 여러분들은 다양한 데이터를 이렇게 응용해서 코딩하셔야 됩니다. 물론 이 데이터 만으로 손절 등을 판당하지는 않습니다. 더욱 많은 데이터들이 필요하죠. 우선적으로 이것만 이해하셔도 많은 발전이 있는 것입니다. 감사합니다.
from PyQt5.QtCore import * # eventloop/스레드를 사용 할 수 있는 함수 가져옴.
from kiwoom import Kiwoom # 로그인을 위한 클래스
from PyQt5.QtWidgets import * # PyQt import
from PyQt5.QtTest import * # 시간관련 함수
from datetime import datetime, timedelta # 특정 일자를 조회
class Thread2(QThread):
def __init__(self, parent): # 부모의 윈도우 창을 가져올 수 있다.
super().__init__(parent) # 부모의 윈도우 창을 초기화 한다.
self.parent = parent # 부모의 윈도우를 사용하기 위한 조건
################## 키움서버 함수를 사용하기 위해서 kiwoom의 능력을 상속 받는다.
self.k = Kiwoom()
################## 사용되는 변수
self.Find_down_Screen = "1200" # 계좌평가잔고내역을 받기위한 스크린
self.code_in_all = None # 1600개 코드 중 1개 코드, 쌓이지 않고 계속 갱신
###### 슬롯
self.k.kiwoom.OnReceiveTrData.connect(self.trdata_slot) # 내가 알고 있는 Tr 슬롯에다 특정 값을 던져 준다.
###### EventLoop
self.detail_account_info_event_loop = QEventLoop() # 계좌 이벤트루프
###### 기관외국인 평균가 가져오기
self.C_K_F_class()
def C_K_F_class(self):
code_list = []
for code in self.k.acc_portfolio.keys():
code_list.append(code)
print("계좌 종목 개수 %s" % (code_list))
#self.parent.progressBar5.setMaximum(len(code_list) - 1) /차 후 설명 드리겠습니다.
for idx, code in enumerate(code_list):
#self.parent.progressBar5.setValue(idx) / 차 후 설명드리겠습니다.
QTest.qWait(1000)
self.k.kiwoom.dynamicCall("DisconnectRealData(QString)", self.Find_down_Screen) # 해당 스크린을 끊고 다시 시작
self.code_in_all = code # 종목코드 선언 (중간에 코드 정보 받아오기 위해서)
print("%s / %s : 종목 검사 중 코드이름 : %s." % (idx + 1, len(code_list), self.code_in_all))
date_today = datetime.today().strftime("%Y%m%d")
date_prev = datetime.today() - timedelta(10) # 넉넉히 10일전의 데이터를 받아온다. 또는 20일이상 데이터도 필요
date_prev = date_prev.strftime("%Y%m%d")
self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", code)
self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "시작일자", date_prev)
self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종료일자", date_today)
self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "기관추정단가구분", "1")
self.k.kiwoom.dynamicCall("SetInputValue(QString, QString)", "외인추정단가구분", "1")
self.k.kiwoom.dynamicCall("CommRqData(String, String, int, String)", "종목별기관매매추이요청2", "opt10045", "0", self.Find_down_Screen)
self.detail_account_info_event_loop.exec_()
def kigwan_meme_dong2(self, a, c): # a. 기관일별순매수량, b. 종가/기관/외국인 평균가, c. 외국인일별순매수량, d. 등락률
a = a[0:4]
c = c[0:4]
print(a)
# a = sum(a, [])
# c = sum(c, [])
if a[0] < 0 and a[1] < 0 and a[2] < 0 and a[3] < 0 and c[0] < 0 and c[1] < 0 and c[2] < 0 and c[3] < 0:
self.k.acc_portfolio[self.code_in_all].update({"위험도": "손절"})
elif a[0] < 0 and a[1] < 0 and a[2] < 0 and c[0] < 0 and c[1] < 0 and c[2] < 0:
self.k.acc_portfolio[self.code_in_all].update({"위험도": "주의"})
elif a[0] < 0 and a[1] < 0 and c[0] < 0 and c[1] < 0:
self.k.acc_portfolio[self.code_in_all].update({"위험도": "관심"})
else:
self.k.acc_portfolio[self.code_in_all].update({"위험도": "낮음"})
def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):
if sRQName == "종목별기관매매추이요청2":
cnt2 = self.k.kiwoom.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName) # 10일치 이상을 하려면 이부분에 10일치 이상데이터 필요
self.calcul2_data = []
self.calcul2_data2 = []
self.calcul2_data3 = []
self.calcul2_data4 = []
for i in range(cnt2): #
Kigwan_meme = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, i, "기관일별순매매수량"))
Kigwan_meme_ave = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "기관추정평균가"))
Forgin_meme = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, i, "외인일별순매매수량"))
Forgin_meme_ave = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, 0, "외인추정평균가"))
percentage = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, i, "등락율"))
Jongga = (self.k.kiwoom.dynamicCall("GetCommData(String, String, int, String)", sTrCode, sRQName, i, "종가"))
self.calcul2_data.append(int(Kigwan_meme.strip()))
self.calcul2_data2.append(abs(int(Jongga.strip())))
self.calcul2_data2.append(abs(int(Kigwan_meme_ave.strip())))
self.calcul2_data2.append(abs(int(Forgin_meme_ave.strip())))
self.calcul2_data3.append(int(Forgin_meme.strip()))
self.calcul2_data4.append(float(percentage.strip()))
# 여기까지 code의 기관일별순매수량, 외국인일별순매수량, 기관/외국인 평균가, 등락률 정보가 나온다.
# self.kigwan_meme_dong2(self.calcul2_data, self.calcul2_data2[0:3], self.calcul2_data3, self.calcul2_data4)
self.kigwan_meme_dong2(self.calcul2_data, self.calcul2_data3)
self.detail_account_info_event_loop.exit()
'주식 자동매매 강의 > 기초반(모든 코딩의 뿌리)' 카테고리의 다른 글
주식자동매매 31강. 계좌관리하기 (8), opt10045 최종 요약 및 코드 공개 (7) | 2022.05.19 |
---|---|
주식자동매매 30강. 계좌관리하기 (7), opt10045 결과 GUI에 입력하기 (2) | 2022.05.18 |
주식자동매매 28강. 계좌관리하기 (5), opt10045 전송 주문 결과 받아오기 (8) | 2022.05.17 |
주식자동매매 27강. 계좌관리하기 (4), opt10045 주문 전송하기 (4) | 2022.05.16 |
주식자동매매 26강. 계좌관리하기 (3), opt10045 개념 파악 및 기본 셋팅을 위한 QThread_2 코딩 (6) | 2022.05.13 |