Toggle navigation
Toggle navigation
This project
Loading...
Sign in
2020-2-capstone-design2
/
2015104491
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
이하영
2020-11-03 07:07:07 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
cb922bd6f0903dd753a205058bc64971f95fab1f
cb922bd6
1 parent
ec3f8e8e
open api를 통한 정보 조회 기능 추가
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
306 additions
and
29 deletions
proj/__pycache__/errCode.cpython-37.pyc
proj/errCode.py
proj/open_api.py
proj/__pycache__/errCode.cpython-37.pyc
0 → 100644
View file @
cb922bd
No preview for this file type
proj/errCode.py
0 → 100644
View file @
cb922bd
def
errors
(
err_code
):
err_dict
=
{
0
:(
'OP_ERR_NONE'
,
'정상처리'
),
-
10
:(
'OP_ERR_FAIL'
,
'실패'
),
-
100
:(
'OP_ERR_LOGIN'
,
'사용자정보교환실패'
),
-
101
:(
'OP_ERR_CONNECT'
,
'서버접속실패'
),
-
102
:(
'OP_ERR_VERSION'
,
'버전처리실패'
),
-
103
:(
'OP_ERR_FAIRWALL'
,
'개인방화벽실패'
),
-
104
:(
'OP_ERR_MEMORY'
,
'메모리보호실패'
),
-
105
:(
'OP_ERR_INPUT'
,
'함수입력값오류'
),
-
106
:(
'OP_ERR_SOCKET_CLOSED'
,
'통신연결종료'
),
-
200
:(
'OP_ERR_SISE_OVERFLOW'
,
'시세조회과부화'
),
-
201
:(
'OP_ERR_RQ_STRUCT_FAIL'
,
'전문작성초기화실패'
),
-
202
:(
'OP_ERR_RQ_STRING_FAIL'
,
'전문작성입력값오류'
),
-
203
:(
'OP_ERR_NO_DATA'
,
'데이터없음'
),
-
204
:(
'OP_ERR_OVER_MAX_DATA'
,
'조회가능한종목수초과'
),
-
205
:(
'OP_ERR_DATA_RCV_FAIL'
,
'데이터수신실패'
),
-
206
:(
'OP_ERR_OVER_MAX_FID'
,
'조회가능한FID수초과'
),
-
207
:(
'OP_ERR_REAL_CANCEL'
,
'실시간해제오류'
),
-
300
:(
'OP_ERR_ORD_WRONG_INPUT'
,
'입력값오류'
),
-
301
:(
'OP_ERR_ORD_WRONG_ACCNO'
,
'계좌비밀번호없음'
),
-
302
:(
'OP_ERR_OTHER_ACC_USE'
,
'타인계좌사용오류'
),
-
303
:(
'OP_ERR_MIS_2BILL_EXC'
,
'주문가격이20억원을초과'
),
-
304
:(
'OP_ERR_MIS_5BILL_EXC'
,
'주문가격이50억원을초과'
),
-
305
:(
'OP_ERR_MIS_1PER_EXC'
,
'주문수량이총발행주수의1
%
초과오류'
),
-
306
:(
'OP_ERR_MIS_3PER_EXC'
,
'주문수량이총발행주수의3
%
초과오류'
),
-
307
:(
'OP_ERR_SEND_FAIL'
,
'주문전송실패'
),
-
308
:(
'OP_ERR_ORD_OVERFLOW'
,
'주문전송과부화'
),
-
309
:(
'OP_ERR_MIS_300CNT_EXC'
,
'주문수량300계약초과'
),
-
310
:(
'OP_ERR_MIS_500CNT_EXC'
,
'주문수량500계약초과'
),
-
340
:(
'OP_ERR_ORD_WRONG_ACCINFO'
,
'계좌정보없음'
),
-
500
:(
'OP_ERR_ORD_SYMCODE_EMPTY'
,
'종목코드없음'
)
}
result
=
err_dict
[
err_code
]
return
result
\ No newline at end of file
proj/open_api.py
View file @
cb922bd
from
PyQt5.QtWidgets
import
*
from
PyQt5.QAxContainer
import
*
from
PyQt5.QtCore
import
*
from
PyQt5.QtTest
import
*
from
pandas
import
DataFrame
import
time
import
sys
import
logging.handlers
import
errCode
# set formatter object
formatter
=
logging
.
Formatter
(
'[
%(levelname)
s|
%(filename)
s:
%(lineno)
s]
%(asctime)
s >
%(message)
s'
)
logger
=
logging
.
getLogger
(
"crumbs"
)
logger
.
setLevel
(
logging
.
DEBUG
)
# set handler object
streamHandler
=
logging
.
StreamHandler
()
streamHandler
.
setFormatter
(
formatter
)
logger
.
addHandler
(
streamHandler
)
TR_REQ_TIME_INTERVAL
=
0.2
TR_REQ_TIME_INTERVAL
=
3600
class
OpenApi
(
QAxWidget
):
def
__init__
(
self
):
...
...
@@ -23,36 +14,63 @@ class OpenApi(QAxWidget):
# event_loop list
self
.
login_event_loop
=
None
self
.
detail_account_info_event_loop
=
QEventLoop
()
self
.
calculator_event_loop
=
QEventLoop
()
# variable list
self
.
account_no
=
None
# 계좌번호
self
.
account_stock_dict
=
{}
# 보유종목
self
.
not_account_stock_dict
=
{}
# 미체결종목
self
.
calc_data
=
[]
# 종목분석용
# account variable list
self
.
user_money
=
0
self
.
user_money_percent
=
0.5
# screen number list
self
.
screen_my_info
=
"2000"
self
.
screen_calculation_stock
=
"4000"
self
.
_get_instance
()
self
.
_event_slot
()
self
.
comm_connect
()
self
.
account_info
()
self
.
account_info
()
# 계좌정보 가져오기
self
.
detail_account_info
()
# 예수금 가져오기
self
.
detail_account_mystock
()
# 계좌평가잔고내역 가져오기
self
.
not_concluded_account
()
# 미체결 종목 조회
# get ocx controller for kioom open api
self
.
calculator_fnc
()
# 종목분석용용
#get ocx controller to use kiwoom open api
def
_get_instance
(
self
):
try
:
self
.
setControl
(
"KHOPENAPI.KHOpenAPICtrl.1"
)
except
Exception
as
e
:
logger
.
critical
(
e
)
print
(
e
)
sys
.
exit
()
#
deal events for using
open api
#
event slot to use
open api
def
_event_slot
(
self
):
try
:
self
.
OnEventConnect
.
connect
(
self
.
login_slot
)
self
.
OnEventConnect
.
connect
(
self
.
login_slot
)
# for login
self
.
OnReceiveTrData
.
connect
(
self
.
trdata_slot
)
# for tr data
except
Exception
as
e
:
logger
.
critical
(
e
)
print
(
e
)
sys
.
exit
()
# if login event success, return errCode=0
def
login_slot
(
self
,
errCode
):
# login event slot
# param code : if login success, code=0
def
login_slot
(
self
,
code
):
try
:
if
errCode
==
0
:
logger
.
debug
(
"connected"
)
result
=
errCode
.
errors
(
code
)
if
code
==
0
:
print
(
"Connected - "
,
result
[
0
],
result
[
1
])
else
:
logger
.
debug
(
"failed to connect. err_code : "
+
errCode
)
print
(
"Failed to connect"
,
result
[
0
],
result
[
1
]
)
self
.
login_event_loop
.
exit
()
except
Exception
as
e
:
logger
.
critical
(
e
)
print
(
e
)
sys
.
exit
()
# try login
def
comm_connect
(
self
):
...
...
@@ -61,24 +79,248 @@ class OpenApi(QAxWidget):
self
.
login_event_loop
=
QEventLoop
()
# wait for login complete
self
.
login_event_loop
.
exec_
()
except
Exception
as
e
:
logger
.
critical
(
e
)
print
(
e
)
sys
.
exit
()
# get user account information
# get user information
# param tag: ACCNO - 보유계좌리스트
# ACCOUNT_CNT - 보유계좌 수
# USER_ID - 사용자 ID
# USER_NAME - 사용자 이름
# KEY_BSECGB - 키보드 보안 해제 여부 (0 : 정상, 1: 해지)
# FIREW_SECGB - 방화벽 설정여부 (0 : 미설정, 1: 설정, 2 : 해지)
# GetServerGubun - 접속서버 구분 (1 : 모의투자, 나머지 : 실서버)
# return: tag를 통해 요청한 정보(ret) 반환
def
get_login_info
(
self
,
tag
):
try
:
ret
=
self
.
dynamicCall
(
"GetLoginInfo(QString)"
,
tag
)
return
ret
except
Exception
as
e
:
logger
.
critical
(
e
)
print
(
e
)
sys
.
exit
()
# print user account information
def
account_info
(
self
):
try
:
account_number
=
self
.
get_login_info
(
"ACCNO"
)
self
.
account_no
=
account_number
.
split
(
";"
)[
0
]
logger
.
debug
(
"계좌번호 : "
+
self
.
account_no
)
print
(
"계좌번호 : "
,
self
.
account_no
)
except
AttributeError
as
e
:
logger
.
critical
(
e
)
print
(
e
)
sys
.
exit
()
# detail information about deposit
def
detail_account_info
(
self
):
self
.
dynamicCall
(
"SetInputValue(String,String)"
,
"계좌번호"
,
self
.
account_no
)
self
.
dynamicCall
(
"SetInputValue(String,String)"
,
"비밀번호"
,
'0000'
)
self
.
dynamicCall
(
"SetInputValue(String,String)"
,
"비밀번호입력매체구분"
,
'00'
)
self
.
dynamicCall
(
"SetInputValue(String,String)"
,
"조회구분"
,
'2'
)
self
.
dynamicCall
(
"CommRqData(String,String,int,String)"
,
"예수금상세현황요청"
,
"opw00001"
,
"0"
,
self
.
screen_my_info
)
self
.
detail_account_info_event_loop
.
exec_
()
# detail information about account
def
detail_account_mystock
(
self
,
sPreNext
=
"0"
):
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"계좌번호"
,
self
.
account_no
)
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"비밀번호"
,
'0000'
)
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"비밀번호입력매체구분"
,
'00'
)
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"조회구분"
,
'2'
)
self
.
dynamicCall
(
"CommRqData(QString,QString,int,QString)"
,
"계좌평가잔고내역요청"
,
"opw00018"
,
sPreNext
,
"2000"
)
self
.
detail_account_info_event_loop
.
exec_
()
# detail information about outstanding order
def
not_concluded_account
(
self
,
sPrevNext
=
"0"
):
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"계좌번호"
,
self
.
account_no
)
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"체결구분"
,
'1'
)
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"매매구분"
,
'0'
)
self
.
dynamicCall
(
"CommRqData(QString,QString,int,QString)"
,
"실시간미체결요청"
,
'opt10075'
,
sPrevNext
,
self
.
screen_my_info
)
self
.
detail_account_info_event_loop
.
exec_
()
# slot receiving tr request
# param sScrNo: 스크린번호
# param sRQName: 요청했을 때 지은 이름
# param sTrCode: 요청 id, tr코드
# param sRecordName: 레코드 이름
# param sPrevNext: 다음 페이지가 있는지 여부. "2" : 다음페이지 존재, "0" or "" : 다음페이지 없음
def
trdata_slot
(
self
,
sScrNo
,
sRQName
,
sTrCode
,
sRecordName
,
sPrevNext
):
if
sRQName
==
"예수금상세현황요청"
:
deposit
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
0
,
"예수금"
)
possible
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
0
,
"출금가능금액"
)
order_possible
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
0
,
"주문가능금액"
)
self
.
user_money
=
int
(
deposit
)
*
self
.
user_money_percent
self
.
user_money
=
self
.
user_money
/
4
print
(
"예수금 : "
,
int
(
deposit
))
print
(
"출금가능금액 : "
,
int
(
possible
))
print
(
"주문가능금액 : "
,
int
(
order_possible
))
self
.
detail_account_info_event_loop
.
exit
()
elif
sRQName
==
"계좌평가잔고내역요청"
:
total_buy_money
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
0
,
"총매입금액"
)
total_profit_rate
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
0
,
"총수익률(
%
)"
)
print
(
"총매입금액 : "
,
int
(
total_buy_money
))
print
(
"총수익률(
%
) : "
,
float
(
total_profit_rate
))
rows
=
self
.
dynamicCall
(
"GetRepeatCnt(QString,QString)"
,
sTrCode
,
sRQName
)
# 보유종목수 반환
cnt
=
0
for
i
in
range
(
rows
):
code
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"종목번호"
)
code
=
code
.
strip
()[
1
:]
code_nm
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"종목명"
)
stock_quantity
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"보유수량"
)
buy_price
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"매입가"
)
learn_rate
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"수익률(
%
)"
)
current_price
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"현재가"
)
total_chegual_price
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"매입금액"
)
possible_quantity
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"매매가능수량"
)
if
code
in
self
.
account_stock_dict
:
pass
else
:
self
.
account_stock_dict
.
update
({
code
:{}})
code_nm
=
code_nm
.
strip
()
buy_price
=
int
(
buy_price
.
strip
())
learn_rate
=
float
(
learn_rate
.
strip
())
current_price
=
int
(
current_price
.
strip
())
total_chegual_price
=
int
(
total_chegual_price
)
possible_quantity
=
int
(
possible_quantity
)
acd
=
self
.
account_stock_dict
[
code
]
acd
.
update
({
"종목명"
:
code_nm
})
acd
.
update
({
"보유수량"
:
stock_quantity
})
acd
.
update
({
"매입가"
:
buy_price
})
acd
.
update
({
"수익률(
%
)"
:
learn_rate
})
acd
.
update
({
"현재가"
:
current_price
})
acd
.
update
({
"매입금액"
:
total_chegual_price
})
acd
.
update
({
"매매가능수량"
:
possible_quantity
})
cnt
+=
1
print
(
"계좌 종목 : "
,
self
.
account_stock_dict
)
print
(
"계좌 종목 수 : "
,
cnt
)
if
sPrevNext
==
"2"
:
self
.
detail_account_mystock
(
sPreNext
=
"2"
)
# If the next page exists, repeat the process
else
:
self
.
detail_account_info_event_loop
.
exit
()
elif
sRQName
==
"실시간미체결요청"
:
rows
=
self
.
dynamicCall
(
"GetRepeatCnt(QString,QString)"
,
sTrCode
,
sRQName
)
for
i
in
range
(
rows
):
code
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"종목번호"
)
code
=
code
.
strip
()
code_nm
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"종목명"
)
order_no
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"주문번호"
)
order_status
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"주문상태"
)
# 접수, 확인, 체결
order_quantity
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"주문수량"
)
order_price
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"주문가격"
)
order_gubun
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"주문구분"
)
# 매도, 매수,
not_quantity
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"미체결수량"
)
ok_quantity
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"체결량"
)
code_nm
=
code_nm
.
strip
()
order_no
=
int
(
order_no
.
strip
())
order_status
=
order_status
.
strip
()
order_quantity
=
int
(
order_quantity
.
strip
())
order_price
=
int
(
order_price
.
strip
())
order_gubun
=
order_gubun
.
lstrip
(
"+"
)
.
lstrip
(
'-'
)
not_quantity
=
int
(
not_quantity
.
strip
())
ok_quantity
=
int
(
ok_quantity
.
strip
())
if
order_no
in
self
.
not_account_stock_dict
:
pass
else
:
self
.
not_account_stock_dict
[
order_no
]
=
{}
nasd
=
self
.
not_account_stock_dict
[
order_no
]
nasd
.
update
({
"종목코드"
:
code
})
nasd
.
update
({
"주문명"
:
code_nm
})
nasd
.
update
({
"주분번호"
:
order_no
})
nasd
.
update
({
"주문상태"
:
order_status
})
nasd
.
update
({
"주문수량"
:
order_quantity
})
nasd
.
update
({
"주문가격"
:
order_price
})
nasd
.
update
({
"주문구분"
:
order_gubun
})
nasd
.
update
({
"미체결수량"
:
not_quantity
})
nasd
.
update
({
"체결량"
:
ok_quantity
})
print
(
"미체결 종목"
,
self
.
not_account_stock_dict
[
order_no
])
self
.
detail_account_info_event_loop
.
exit
()
elif
sRQName
==
"주식일봉차트조회"
:
code
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
"0"
,
"종목코드"
)
code
=
code
.
strip
()
print
(
code
,
" 일봉데이터 요청"
)
cnt
=
self
.
dynamicCall
(
"GetRepeatCnt(QString,QString)"
,
sTrCode
,
sRQName
)
print
(
"데이터 일수"
,
cnt
)
# 한 번 조회시 600일치까지 조회 가능
for
i
in
range
(
cnt
):
data
=
[]
current_price
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"현재가"
)
# 종가
value
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"거래량"
)
trading_value
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"거래대금"
)
date
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"일자"
)
start_price
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"시가"
)
high_price
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"고가"
)
low_price
=
self
.
dynamicCall
(
"GetCommData(QString,QString,int,QString)"
,
sTrCode
,
sRQName
,
i
,
"저가"
)
data
.
append
(
""
)
data
.
append
(
current_price
.
strip
())
data
.
append
(
value
.
strip
())
data
.
append
(
trading_value
.
strip
())
data
.
append
(
date
.
strip
())
data
.
append
(
start_price
.
strip
())
data
.
append
(
high_price
.
strip
())
data
.
append
(
low_price
.
strip
())
self
.
calc_data
.
append
(
data
.
copy
())
print
(
len
(
self
.
calc_data
))
if
sPrevNext
==
"2"
:
self
.
day_kiwoom_db
(
code
=
code
,
sPrevNext
=
sPrevNext
)
else
:
self
.
calculator_event_loop
.
exit
()
# 종목 코드를 반환
def
get_code_list_by_market
(
self
,
market_code
):
code_list
=
self
.
dynamicCall
(
"GetCodeListByMarket(QString)"
,
market_code
)
code_list
=
code_list
.
split
(
";"
)[:
-
1
]
return
code_list
# 종목 분석 실행용 함수
def
calculator_fnc
(
self
):
code_list
=
self
.
get_code_list_by_market
(
"10"
)
print
(
"코스닥 갯수"
,
len
(
code_list
))
for
idx
,
code
in
enumerate
(
code_list
):
self
.
dynamicCall
(
"DisconnectRealData(QString)"
,
self
.
screen_calculation_stock
)
print
(
"
%
s /
%
s : KOSDAQ Stock Code :
%
s is updating..."
%
(
idx
+
1
,
len
(
code_list
),
code
))
self
.
day_kiwoom_db
(
code
=
code
)
def
day_kiwoom_db
(
self
,
code
=
None
,
date
=
None
,
sPrevNext
=
"0"
):
QTest
.
qWait
(
TR_REQ_TIME_INTERVAL
)
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"종목코드"
,
code
)
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"수정주가구분"
,
"1"
)
if
date
!=
None
:
self
.
dynamicCall
(
"SetInputValue(QString,QString)"
,
"기준일자"
,
date
)
self
.
dynamicCall
(
"CommRqData(QString,QString,int,QString)"
,
"주식일봉차트조회"
,
"opt10081"
,
sPrevNext
,
self
.
screen_calculation_stock
)
self
.
calculator_event_loop
.
exec_
()
if
__name__
==
"__main__"
:
app
=
QApplication
(
sys
.
argv
)
...
...
Please
register
or
login
to post a comment