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-12-02 05:44:58 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
d00a16a4fce2458b0da7b457e33a9dda6258c5e2
d00a16a4
1 parent
3ae18c5b
open_api 관련함수 추가
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
543 additions
and
126 deletions
proj/library/cf.py
proj/library/open_api.py
proj/library/cf.py
View file @
d00a16a
...
...
@@ -22,3 +22,5 @@ real_num=1
real_bot_name
=
"AutoBot"
+
str
(
real_num
)
real_stockInfo_name
=
"stock_info"
real_dailyInfo_name
=
"daily_info"
max_api_call
=
98
\ No newline at end of file
...
...
proj/library/open_api.py
View file @
d00a16a
from
PyQt5.QtCore
import
*
from
PyQt5.QAxContainer
import
*
from
PyQt5.QtWidgets
import
*
import
pymysql
import
datetime
from
sqlalchemy
import
*
from
collections
import
defaultdict
from
pandas
import
DataFrame
import
re
import
time
import
warnings
warnings
.
simplefilter
(
action
=
'ignore'
,
category
=
UserWarning
)
from
sqlalchemy
import
create_engine
,
event
,
Text
,
Float
from
sqlalchemy.pool
import
Pool
import
pymysql
pymysql
.
install_as_MySQLdb
()
from
Logger
import
*
import
cf
from
Simulator_Api
import
*
pymysql
.
install_as_MySQLdb
()
# open_api에 tr요청을 보낼 때, 연속해서 보내면 오류가 발생하기 때문에 중간에 interval을 줘야 한다.
TR_REQ_TIME_INTERVAL
=
0.5
# interval값을 저장하는 변수
code_pattern
=
re
.
compile
(
r'\d{6}'
)
# 코드 패턴을 저장. 코드는 연속된 6자리의 숫자
# query문의 %를 %%로 변환하는 함수
def
escape_percentage
(
conn
,
clauseelement
,
multiparmas
,
parmas
):
if
isinstance
(
clauseelement
,
str
)
and
'
%
'
in
clauseelement
and
multiparmas
is
not
None
:
while
True
:
replaced
=
re
.
sub
(
r'([^
%
])
%
([^
%
])'
,
r'\1
%%
\2'
,
clauseelement
)
if
replaced
==
clauseelement
:
break
clauseelement
=
replaced
return
clauseelement
,
multiparmas
,
parmas
# MySQL의 default sql_mode 설정
def
setup_sql_mod
(
dbapi_connection
):
cursor
=
dbapi_connection
.
cursor
()
cursor
.
execute
(
"SET sql_mode=''"
)
event
.
listen
(
Pool
,
'connect'
,
setup_sql_mod
)
event
.
listen
(
Pool
,
'first_connect'
,
setup_sql_mod
)
class
Open_Api
(
QAxWidget
):
def
__init__
(
self
):
...
...
@@ -191,13 +218,10 @@ class Open_Api(QAxWidget):
def
_receive_chejan_data
(
self
,
sGubun
,
nItemCnt
,
sFIdList
):
# 체결구분. 접수와 체결
if
sGubun
==
"0"
:
code
=
self
.
get_chejan_data
(
9001
)
# 현재 체결 진행 중인 코드
code
=
re
.
compile
(
r'\d{6}'
)
# 종목코드는 연속된 숫자 6자리
order_num
=
self
.
get_chejan_data
(
9203
)
# 주문번호
# 주문번호가 존재하지 않는다면 주문실패
code
=
code_pattern
.
search
(
self
.
get_chejan_data
(
9001
))
.
group
(
0
)
# 주식 코드가 숫자만오지 않아서 정규식으로 필터링
order_num
=
self
.
get_chejan_data
(
9203
)
# 주문번호
if
not
order_num
:
logger
.
debug
(
code
,
"주문 실패"
)
logger
.
debug
(
f
'{code} 주문 실패'
)
return
chegyul_fail_amount
=
self
.
get_chejan_data
(
902
)
# 미체결 수량
...
...
@@ -208,17 +232,17 @@ class Open_Api(QAxWidget):
if
code
:
if
chegyul_fail_amount
!=
""
:
# 해당 종목을 보유하고 있지 않은 경우
if
not
self
.
is_
exist_possess_item_in_transaction
(
code
):
if
not
self
.
is_
all_stock_check
(
code
):
# 해당 종목의 체결 실패 내역이 없다면
# transaction 테이블에 업데이트. 정상 체결 시 chegyul_check=0
if
chegyul_fail_amount
==
"0"
:
logger
.
debug
(
code
,
"체결 완료"
)
self
.
db_to_
transaction
(
order_num
,
code
,
0
,
purchase_price
,
0
)
self
.
db_to_
all_stocks
(
order_num
,
code
,
0
,
purchase_price
,
0
)
# 체결 실패 내역이 존재한다면
# transaction 테이블에 업데이트. 미체결 시 chegyul_check=1
else
:
logger
.
debug
(
code
,
"미체결"
)
self
.
db_to_
transaction
(
order_num
,
code
,
1
,
purchase_price
,
0
)
self
.
db_to_
all_stocks
(
order_num
,
code
,
1
,
purchase_price
,
0
)
# 매수하는 경우
elif
order_gubun
==
"+매수"
:
...
...
@@ -227,7 +251,7 @@ class Open_Api(QAxWidget):
pass
elif
chegyul_fail_amount
==
"0"
and
self
.
check_stock_chegyul
(
code
):
logger
.
debug
(
"매수 완료"
)
self
.
check_end_invest
(
code
)
self
.
end_invest_count_check
(
code
)
else
:
pass
...
...
@@ -235,7 +259,7 @@ class Open_Api(QAxWidget):
elif
order_gubun
==
"-매도"
:
if
chegyul_fail_amount
==
"0"
:
logger
.
debug
(
"전량 매도"
)
self
.
check_end_sell
(
code
)
self
.
sell_final_check
(
code
)
else
:
logger
.
debug
(
"부분 매도"
)
self
.
check_sell_chegyul_fail
(
code
)
...
...
@@ -255,33 +279,16 @@ class Open_Api(QAxWidget):
else
:
logger
.
debug
(
"Invlid _receive_chejan_data"
)
# 특정 종목을 보유하고 있는지 확인하는 함수
def
is_exist_possess_item_in_transaction
(
self
,
code
):
query
=
"select code from transaction "
\
"where code='
%
s' and (sell_date ='
%
s' or sell_date='
%
s') ORDER BY buy_date desc LIMIT 1"
result
=
self
.
engine_bot
.
execute
(
query
%
(
code
,
0
,
""
))
.
fetchall
()
if
len
(
result
)
!=
0
:
return
True
else
:
return
False
# 해당 종목이 체결되었는지 확인하는 함수
def
check_stock_chegyul
(
self
,
code
):
query
=
"SELECT chegyul_check FROM transaction
"
\
"where code='
%
s' and sell_date = '
%
s
' ORDER BY buy_date desc LIMIT 1"
result
=
self
.
engine_bot
.
execute
(
query
%
(
code
,
0
)
)
.
fetchall
()
query
=
f
"SELECT chegyul_check FROM all_stocks
"
\
f
"where code='{code}' and sell_date = '0
' ORDER BY buy_date desc LIMIT 1"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
if
result
[
0
][
0
]
==
1
:
return
True
else
:
return
False
# 체결 완료 시 transaction 테이블의 chegyul_check항목을 업데이트
def
check_end_invest
(
self
,
code
):
query
=
"UPDATE transaction "
\
"SET "
\
"chegyul_check='
%
s' WHERE code='
%
s' and sell_date = '
%
s' ORDER BY buy_date desc LIMIT 1"
self
.
engine_bot
.
execute
(
query
%
(
0
,
code
,
0
))
# 매도 완료 후 DB 업데이트트
def
check_sell_end
(
self
,
code
):
query
=
"select valuation_profit,rate,item_total_urchase,present_price"
\
...
...
@@ -307,9 +314,9 @@ class Open_Api(QAxWidget):
# 매도 체결 실패시 DB 업데이트
def
check_sell_chegyul_fail
(
self
,
code
):
query
=
"UPDATE transaction SET chegyul_check='
%
s
' "
\
"WHERE code='
%
s' and sell_date = '
%
s'
ORDER BY buy_date desc LIMIT 1"
self
.
engine_
bot
.
execute
(
query
%
(
1
,
code
,
0
)
)
query
=
f
"UPDATE all_stocks SET chegyul_check='1' WHERE code='{code}' and sell_date = '0
' "
\
f
"
ORDER BY buy_date desc LIMIT 1"
self
.
engine_
JB
.
execute
(
query
)
# OnReceiveChejan()이벤트가 호출될때 체결정보나 잔고정보를 얻어오는 함수
# param : nFid - 실시간 타입에 포함된 FID
...
...
@@ -340,8 +347,7 @@ class Open_Api(QAxWidget):
try
:
self
.
dynamicCall
(
"SetInputValue(QString, QString)"
,
sId
,
sValue
)
except
Exception
as
e
:
print
(
e
)
sys
.
exit
()
logger
.
critical
(
e
)
# 조회요청함수
# param : sRQName - 사용자 구분명
...
...
@@ -349,7 +355,16 @@ class Open_Api(QAxWidget):
# nPrevNext - 연속조회여부
# sScreenNo - 화면번호
def
comm_rq_data
(
self
,
sRQName
,
sTrData
,
nPrevNext
,
sScrNo
):
self
.
dynamicCall
(
"CommRqData(QString, QString, int, QString"
,
sRQName
,
sTrData
,
nPrevNext
,
sScrNo
)
self
.
exit_check
()
ret
=
self
.
dynamicCall
(
"CommRqData(QString, QString, int, QString"
,
sRQName
,
sTrData
,
nPrevNext
,
sScrNo
)
if
ret
==-
200
:
logger
.
critical
(
"요청 제한 횟수 초과"
)
self
.
call_time
=
datetime
.
datetime
.
now
()
if
ret
==
0
:
self
.
tr_loop_count
+=
1
self
.
tr_event_loop
.
exec_
()
# OnReceiveTRData()이벤트가 호출될때 조회데이터를 얻어오는 함수
...
...
@@ -369,8 +384,7 @@ class Open_Api(QAxWidget):
ret
=
self
.
dynamicCall
(
"GetRepeatCnt(QString, QString)"
,
sTrCode
,
sRecordName
)
return
ret
except
Exception
as
e
:
print
(
e
)
sys
.
exit
()
logger
.
critical
(
e
)
# 변수 설정
# 실전투자인지 모의투자인지 여부를 확인하고 그에 해당하는 데이터베이스를 생성하는 함수
...
...
@@ -396,7 +410,7 @@ class Open_Api(QAxWidget):
logger
.
debug
(
"Invalid Account Number. Check the Config.py"
)
exit
(
1
)
self
.
is_balance
_null
=
True
self
.
jango_is
_null
=
True
self
.
py_gubun
=
False
# 데이터베이스 생성 및 엔진 설정
...
...
@@ -411,16 +425,14 @@ class Open_Api(QAxWidget):
charset
=
'utf8mb4'
,
cursorclass
=
pymysql
.
cursors
.
DictCursor
)
cursor
=
conn
.
cursor
()
with
conn
.
cursor
()
as
cursor
:
if
not
self
.
is_database_exist
(
cursor
):
self
.
create_database
(
cursor
)
self
.
engine_bot
=
create_engine
(
"mysql+pymysql://"
+
self
.
cf
.
db_id
+
":"
+
self
.
cf
.
db_pw
+
"@"
+
self
.
cf
.
db_ip
+
":"
+
self
.
cf
.
db_port
+
"/"
+
db_name
,
encoding
=
'utf-8'
)
self
.
engine_bot
=
create_engine
(
"mysql+pymysql://"
+
self
.
cf
.
db_id
+
":"
+
self
.
cf
.
db_pw
+
"@"
+
self
.
cf
.
db_ip
+
":"
+
self
.
cf
.
db_port
+
"/"
+
db_name
,
encoding
=
'utf-8'
)
self
.
create_basic_database
(
cursor
)
conn
.
commit
()
cursor
.
close
()
conn
.
close
()
self
.
engine_craw
=
create_engine
(
"mysql+pymysql://"
+
cf
.
db_id
+
":"
+
cf
.
db_pw
+
"@"
+
cf
.
db_ip
+
":"
+
...
...
@@ -430,6 +442,10 @@ class Open_Api(QAxWidget):
self
.
engine_daily_buy_list
=
create_engine
(
"mysql+pymysql://"
+
cf
.
db_id
+
":"
+
cf
.
db_pw
+
"@"
+
cf
.
db_ip
+
":"
+
cf
.
db_port
+
"/daily_buy_list"
,
encoding
=
'utf-8'
)
event
.
listen
(
self
.
engine_craw
,
'before_execute'
,
escape_percentage
,
retval
=
True
)
event
.
listen
(
self
.
engine_daily_craw
,
'before_execute'
,
escape_percentage
,
retval
=
True
)
event
.
listen
(
self
.
engine_daily_buy_list
,
'before_execute'
,
escape_percentage
,
retval
=
True
)
# bot database가 존재하는지 확인하는 함수
def
is_database_exist
(
self
,
cursor
):
query
=
f
"select 1 from information_schema.schemata where schema_name='{self.db_name}'"
...
...
@@ -505,23 +521,23 @@ class Open_Api(QAxWidget):
# simulator_fun 에서 설정한 변수를 가져오는 함수
def
set_simul_variable
(
self
):
logger
.
debug
(
"-* set simul variable
함수
*-"
)
logger
.
debug
(
"-* set simul variable
function
*-"
)
# daily_buy_list에 저장된 가장 최신 날짜
self
.
date_rows_yesterday
=
self
.
sf
.
get_recent_daily_buy_list_date
()
# AutoBot 데이터베이스에 all_stock 테이블이 존재하지 않을 경우 테이블 생성 및 초기화
# all_stock : 모든 주식 거래 내역을 저장하는 테이블
# all_stock
s
: 모든 주식 거래 내역을 저장하는 테이블
if
not
self
.
sf
.
is_simul_table_exist
(
self
.
db_name
,
"all_stocks"
):
logger
.
debug
(
"all_stocks 테이블을 생성합니다"
)
# 테이블 생성 후 초기화
self
.
invest_unit
=
0
self
.
db_to_transaction
(
0
,
0
,
0
,
0
,
0
)
self
.
delete_
transaction_item
(
"0"
)
self
.
delete_
all_stock
(
"0"
)
# setting_data에 invest_unit값이 없다면 설정
if
not
self
.
check_set_invest_unit
():
self
.
set_invest_unit
()
# 존재한다면 해당 값을 simulator_
func
에 저장
# 존재한다면 해당 값을 simulator_
api
에 저장
else
:
self
.
invest_unit
=
self
.
get_invest_unit
()
self
.
sf
.
invest_unit
=
self
.
invest_unit
...
...
@@ -529,6 +545,7 @@ class Open_Api(QAxWidget):
# all_stock(거래 내역) 테이블 생성
def
db_to_all_stocks
(
self
,
order_num
,
code
,
chegyul_check
,
purchase_price
,
rate
):
logger
.
debug
(
"-* db_to_all_stocks function *-"
)
self
.
date_setting
()
self
.
sf
.
init_df_all_stocks
()
# all_stocks 테이블 데이터프레임 생성
...
...
@@ -544,6 +561,7 @@ class Open_Api(QAxWidget):
if
order_num
!=
0
:
recent_daily_buy_list_date
=
self
.
sf
.
get_recent_daily_buy_list_date
()
# 구매 내역이 존재하는 경우 해당 데이터를 추가
if
recent_daily_buy_list_date
:
# 특정 날짜, 특정 종목의 주가 데이터
df
=
self
.
sf
.
get_daily_buy_list_by_code
(
code
,
recent_daily_buy_list_date
)
...
...
@@ -593,14 +611,14 @@ class Open_Api(QAxWidget):
'clo120_diff_rate'
:
Float
,
})
#
거래내역(transaction
) 테이블에서 특정 종목을 삭제하는 함수
#
all_stocks(거래내역
) 테이블에서 특정 종목을 삭제하는 함수
def
delete_transaction_item
(
self
,
code
):
query
=
f
"delete from
transaction
where code={code}"
query
=
f
"delete from
all_stocks
where code={code}"
self
.
engine_bot
.
execute
(
query
)
# setting_data 테이블에 invest_unit이 오늘 업데이트 되었는지 확인
def
check_set_invest_unit
(
self
):
query
=
"select invest_unit, set_invest_unit from setting_data"
query
=
"select invest_unit, set_invest_unit from setting_data
limit 1
"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
if
result
[
0
][
1
]
==
self
.
today
:
self
.
invest_unit
=
result
[
0
][
0
]
...
...
@@ -610,6 +628,7 @@ class Open_Api(QAxWidget):
# 데이터베이스에서 invest_unit값을 가져오는 함수
def
get_invest_unit
(
self
):
logger
.
debug
(
"-* get_invest_unit function *-"
)
query
=
"select invest_unit from setting_data"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
return
result
[
0
][
0
]
...
...
@@ -619,7 +638,7 @@ class Open_Api(QAxWidget):
def
set_invest_unit
(
self
):
self
.
get_deposit
()
self
.
get_balance
()
self
.
total_invest
=
self
.
deposit
+
self
.
total_purchase_price
self
.
total_invest
=
self
.
change_format
(
str
(
int
(
self
.
deposit
)
+
int
(
self
.
total_purchase_price
)))
self
.
invest_unit
=
self
.
sf
.
invest_unit
query
=
f
"update setting_data set invest_unit='{self.invest_unit}', set_invest_unit='{self.today}'"
...
...
@@ -643,36 +662,38 @@ class Open_Api(QAxWidget):
self
.
comm_rq_data
(
"opw00018_req"
,
"opw00018"
,
2
,
"2000"
)
# open_api를 통해 보유한 종목을 가져오는 함수
# 가져온 정보를 possesd_item이라는 테이블에 저장
def
db_to_possessd_item
(
self
):
# 가져온 정보를 posses
se
d_item이라는 테이블에 저장
def
db_to_possess
e
d_item
(
self
):
item_count
=
len
(
self
.
opw00018_output
[
'multi'
])
possesd_item_data
=
{
'date'
:[],
'code'
:[],
'code_name'
:[],
'holding_amount'
:[],
'purchase_price'
:[],
posses
se
d_item_data
=
{
'date'
:[],
'code'
:[],
'code_name'
:[],
'holding_amount'
:[],
'purchase_price'
:[],
'present_price'
:[],
'valuation_profit'
:[],
'rate'
:[],
'item_total_purchase'
:[]}
posses
d_item
=
DataFrame
(
posses
d_item_data
,
posses
sed_item
=
DataFrame
(
possesse
d_item_data
,
columns
=
[
'date'
,
'code'
,
'code_name'
,
'holding_amount'
,
'purchase_price'
,
'present_price'
,
'valuation_profit'
,
'rate'
,
'item_total_purchase'
])
for
i
in
range
(
item_count
):
item
=
self
.
opw00018_output
[
'multi'
][
i
]
possesd_item
.
loc
[
i
,
'date'
]
=
self
.
today
possesd_item
.
loc
[
i
,
'code'
]
=
item
[
7
]
possesd_item
.
loc
[
i
,
'code_name'
]
=
item
[
0
]
posses
d_item
.
loc
[
i
,
'holding_amount'
]
=
int
(
item
[
1
])
posses
d_item
.
loc
[
i
,
'purchase_price'
]
=
int
(
item
[
2
])
posses
d_item
.
loc
[
i
,
'present_price'
]
=
int
(
item
[
3
])
posses
d_item
.
loc
[
i
,
'valuation_profit'
]
=
int
(
item
[
4
])
posses
d_item
.
loc
[
i
,
'rate'
]
=
float
(
item
[
5
])
posses
d_item
.
loc
[
i
,
'item_total_purchase'
]
=
int
(
item
[
6
])
posses
se
d_item
.
loc
[
i
,
'date'
]
=
self
.
today
posses
se
d_item
.
loc
[
i
,
'code'
]
=
item
[
7
]
posses
se
d_item
.
loc
[
i
,
'code_name'
]
=
item
[
0
]
posses
sed_item
.
loc
[
i
,
'holding_amount'
]
=
int
(
item
[
1
])
# 보유량
posses
sed_item
.
loc
[
i
,
'purchase_price'
]
=
int
(
item
[
2
])
# 매수가
posses
sed_item
.
loc
[
i
,
'present_price'
]
=
int
(
item
[
3
])
# 현재가
posses
sed_item
.
loc
[
i
,
'valuation_profit'
]
=
int
(
item
[
4
])
# 평가수익률
posses
sed_item
.
loc
[
i
,
'rate'
]
=
float
(
item
[
5
])
# 수익률
posses
sed_item
.
loc
[
i
,
'item_total_purchase'
]
=
int
(
item
[
6
])
# 총매수금액
posses
d_item
.
to_sql
(
"posses
d_item"
,
self
.
engine_bot
,
if_exists
=
'replace'
)
self
.
c
ontract
_sync
()
posses
sed_item
.
to_sql
(
"possesse
d_item"
,
self
.
engine_bot
,
if_exists
=
'replace'
)
self
.
c
hegyul
_sync
()
#
현재 소유하고 있는 종목에 대해 transaction 테이블을 업데이트
#
매수 완료한 항목을 all_stocks에 기록하는 함수
def
chegyul_sync
(
self
):
query
=
"select code,code_name,rate from possessed_item "
\
"where code not in (select code from transaction where sell_date='0' group by code) group by code"
# 신규 매수한 항목을 가져온다
query
=
"select code, code_name, rate from possessed_item p "
\
"where p.code not in (select a.code from all_stocks a where a.sell_date = '0' group by a.code) "
\
"group by p.code"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
for
item
in
result
:
...
...
@@ -692,7 +713,7 @@ class Open_Api(QAxWidget):
else
:
continue
self
.
db_to_
transaction
(
self
.
not_contract
[
'주문번호'
],
item
.
code
,
contract
_check
,
self
.
not_contract
[
'체결가'
],
item
.
rate
)
self
.
db_to_
all_stocks
(
self
.
not_contract
[
'주문번호'
],
item
.
code
,
chegyul
_check
,
self
.
not_contract
[
'체결가'
],
item
.
rate
)
# posses_item 테이블을 업데이트 했을 경우 setting data 테이블에 업데이트 한 날짜를 표시
def
setting_data_posses_stock
(
self
):
...
...
@@ -730,7 +751,7 @@ class Open_Api(QAxWidget):
def
is_stock_table_exist
(
self
,
code_name
):
query
=
"select 1 from information_schema.tables where table_schema ='stock_info' and table_name = '{}'"
result
=
self
.
engine_stock
.
execute
(
query
.
format
(
code_name
))
.
fetchall
()
if
result
:
if
result
:
ㄴ
return
True
else
:
return
False
...
...
@@ -745,20 +766,20 @@ class Open_Api(QAxWidget):
else
:
return
str
(
0
)
# 체결이 완료되었는지 확인하고
transaction(거래내역) 테이블을 업데이트하는 함수
# 체결이 완료되었는지 확인하고
all_stocks(거래내역)테이블을 업데이트
def
check_chegyul
(
self
):
query
=
"select code from
transaction where chegyul_check='1
'"
r
ows
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
query
=
"select code from
all_stocks where chegyul_check='1' and (sell_date='0' or sell_date='
'"
r
esult
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
for
r
in
r
ows
:
for
r
in
r
esult
:
self
.
set_input_value
(
"종목코드"
,
r
.
code
)
self
.
set_input_value
(
"조회구분"
,
1
)
self
.
set_input_value
(
"계좌번호"
,
self
.
account_no
)
self
.
comm_rq_data
(
"opt10076_req"
,
"opt10076"
,
0
,
"0350"
)
query
=
f
"update
transaction
set chegyul_check='0' where code='{r.code}' and sell_data='0' "
\
query
=
f
"update
all_stocks
set chegyul_check='0' where code='{r.code}' and sell_data='0' "
\
f
"order by buy_date desc limit 1"
# 거래가 완료된 항목은 주문번호가 존재하지 않음
# 거래가 완료된 항목은 주문번호
등 데이터
가 존재하지 않음
# 거래가 완료된 항목에 대해서 contract_check항목을 '0'으로 업데이트
if
not
self
.
not_contract
[
'주문번호'
]:
self
.
engine_bot
.
execute
(
query
)
...
...
@@ -769,28 +790,45 @@ class Open_Api(QAxWidget):
else
:
logger
.
debug
(
"미체결 종목이 존재합니다"
)
# 매도했을 경우 possessed_item(보유종목) 테이블에서 항목을 삭제
def
delete_possessed_item
(
self
,
code
):
query
=
f
"delete from possessed_item where code={code}"
self
.
engine_bot
.
execute
(
query
)
# 매도한 후 transaction 테이블 업데이트
def
check_sell_final
(
self
,
code
):
query
=
f
"update transaction chegyul_check='0', sell_date='{self.today_time}' "
\
f
"where code='{code}' and sell_date='0' order by buy_date desc"
# 매도한 후 all_stocks 테이블 업데이트
def
sell_final_check
(
self
,
code
):
query
=
f
"SELECT valuation_profit, rate, item_total_purchase, present_price FROM possessed_item "
\
f
"WHERE code='{code}' LIMIT 1"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
if
result
:
item
=
result
[
0
]
query
=
f
"update all_stocks set "
\
f
"item_total_purchase={item.item_total_purchase}, chegyul_check=0, "
\
f
"sell_date={self.today_time}, valuation_profit={item.valuation_profit},"
\
f
"sell_rate={item.rate}, sell_price={item.present_price} "
\
f
"where code='{code}' and sell_date='0' order by buy_date desc limit 1"
self
.
engine_bot
.
execute
(
query
)
# posses_item테이블에는 존재하지만 transaction_history테이블에 존재하지 않는 항목에 대해 업데이트
def
final_check_contract
(
self
):
query
=
"select code from transaction_history"
\
"where"
\
"sell_date='
%
s' or sell_date='
%
s' and code not in (select code from posses_item) and contract_check!='
%
s'"
result
=
self
.
engine_bot
.
execute
(
query
%
(
0
,
""
,
1
))
.
fetchall
()
num
=
len
(
result
)
for
i
in
range
(
num
):
self
.
sell_check
(
result
[
i
][
0
])
query
=
"update setting_data set final_contract_check='
%
s'"
self
.
engine_bot
.
execute
(
query
%
(
self
.
today
))
# 매도한 항목을 possessed_item(보유종목) 테이블에서 삭제
self
.
engine_bot
.
execute
(
f
"DELETE FROM possessed_item WHERE code = '{code}'"
)
# 매도했을 때, possessed_item에서 삭제되었지만 all_stocks에 sell_date 칼럼이 업데이트 되지 않은 항목들을 처리하는 함수
def
final_chegyul_check
(
self
):
query
=
"select code from all_stocks a "
\
"where (a.sell_date = '0' or a.sell_date ='') and a.code not in ( select code from possessed_item) "
\
"and a.chegyul_check != '1'"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
num
=
len
(
result
)
for
t
in
range
(
num
):
self
.
sell_final_check2
(
result
[
t
][
0
])
# 모든 항목을 처리했으면 setting_data테이블의 final_chegyul_check 항목에 오늘 날짜를 저장
query
=
f
"UPDATE setting_data SET final_chegyul_check='{self.today}' limit 1"
self
.
engine_bot
.
execute
(
query
)
# 가지고 있던 종목을 판매하여 posses_item테이블에 내역이 존재하지 않지만 transaction_history에 매도처리가 되지 않은 항목 업데이트
def
sell_check
(
self
,
code
):
...
...
@@ -808,9 +846,10 @@ class Open_Api(QAxWidget):
# setting_data에 possessed_item 항목을 업데이트
def
set_setting_data_possessed_item
(
self
):
query
=
f
"update setting_data set possessed_item={self.today}"
query
=
f
"update setting_data set possessed_item={self.today}
limit 1
"
self
.
engine_bot
.
execute
(
query
)
# 특정 종목의 틱(1분별) 데이터 조회 함수
def
get_total_data_min
(
self
,
code
,
code_name
,
start
):
self
.
ohlcv
=
defaultdict
(
list
)
...
...
@@ -819,10 +858,10 @@ class Open_Api(QAxWidget):
self
.
set_input_value
(
"수정주가구분"
,
1
)
self
.
comm_rq_data
(
"opt10080_req"
,
"opt10080"
,
0
,
"1999"
)
self
.
is_
craw_table_exist
=
False
self
.
craw_table_exist
=
False
if
self
.
is_min_craw_table_exist
(
code_name
):
self
.
is_
craw_table_exist
=
True
self
.
craw_table_exist
=
True
self
.
craw_db_last_min
=
self
.
get_craw_db_last_min
(
code_name
)
self
.
craw_db_last_min_sum_volume
=
self
.
get_craw_db_last_min_sum_volume
(
code_name
)
...
...
@@ -840,11 +879,10 @@ class Open_Api(QAxWidget):
if
self
.
ohlcv
[
'date'
][
-
1
]
<
self
.
craw_db_last_min
:
break
time
.
sleep
(
TR_REQ_TIME_INTER
B
VAL
)
time
.
sleep
(
TR_REQ_TIME_INTERVAL
)
if
len
(
self
.
ohlcv
[
'date'
]
==
0
or
self
.
ohlcv
[
'date'
][
0
]
==
''
):
return
[]
if
self
.
ohlcv
[
'date'
]
==
''
:
return
[]
...
...
@@ -852,6 +890,305 @@ class Open_Api(QAxWidget):
return
df
# 특정 종목의 일자별 거래 데이터 조회 함수
def
get_total_data
(
self
,
code
,
code_name
,
date
):
logger
.
debug
(
"-* get_total_data function *-"
)
self
.
ohlcv
=
defaultdict
(
list
)
self
.
set_input_value
(
"종목코드"
,
code
)
self
.
set_input_value
(
"기준일자"
,
date
)
self
.
set_input_value
(
"수정주가구분"
,
1
)
self
.
comm_rq_data
(
"opt10081_req"
,
"opt10081"
,
0
,
"0101"
)
if
not
self
.
is_craw_table_exist
(
code_name
):
while
self
.
remained_data
:
self
.
set_input_value
(
"종목코드"
,
code
)
self
.
set_input_value
(
"기준일자"
,
date
)
self
.
set_input_value
(
"수정주가구분"
,
1
)
self
.
comm_rq_data
(
"opt10081_req"
,
"opt10081"
,
2
,
"0101"
)
if
len
(
self
.
ohlcv
)
==
0
:
return
[]
if
self
.
ohlcv
[
'date'
]
==
''
:
return
[]
df
=
DataFrame
(
self
.
ohlcv
,
columns
=
[
'date'
,
'open'
,
'high'
,
'low'
,
'close'
,
'volume'
])
return
df
# daily_craw 데이터베이스에 {code_name} 테이블이 존재하는지 확인하는 함수
def
is_craw_table_exist
(
self
,
code_name
):
query
=
"select 1 from information_schema.tables where table_schema='daily_craw' and table_name='{}'"
result
=
self
.
engine_daily_craw
.
execute
(
query
.
format
(
code_name
))
if
result
:
return
True
else
:
return
False
# min_craw 데이터베이스에 {code_name} 테이블이 존재하는지 확인하는 함수
def
is_min_craw_table_exist
(
self
,
code_name
):
query
=
"select 1 from information_schema.tables where table_schema ='min_craw' and table_name = '{}'"
result
=
self
.
engine_craw
.
execute
(
query
.
format
(
code_name
))
.
fetchall
()
if
result
:
return
True
else
:
return
False
# min_craw 테이블에서 마지막에 저장한 행의 sum_volume값을 가져오는 함수
def
get_craw_db_last_min_sum_volume
(
self
,
code_name
):
query
=
f
"SELECT sum_volume from `{code_name}` order by date desc limit 1"
result
=
self
.
engine_craw
.
execute
(
query
)
.
fetchall
()
if
len
(
result
):
return
result
[
0
][
0
]
else
:
return
str
(
0
)
# min_craw 테이블에서 마지막에 저장한 행의 시간(분) 정보를 가져오는 함수
def
get_craw_db_last_min
(
self
,
code_name
):
query
=
f
"SELECT date from `{code_name}` order by date desc limit 1"
result
=
self
.
engine_craw
.
execute
(
query
)
.
fetchall
()
if
len
(
result
):
return
result
[
0
][
0
]
# 신생
else
:
return
str
(
0
)
# min_craw 테이블에서 마지막에 저장한 행의 날짜 정보를 가져오는 함수
def
get_craw_db_last_date
(
self
,
code_name
):
query
=
f
"SELECT date from `{code_name}` order by date desc limit 1"
result
=
self
.
engine_craw
.
execute
(
query
)
.
fetchall
()
if
len
(
result
):
return
result
[
0
][
0
]
else
:
return
str
(
0
)
# 특정 종목의 특정 날짜의 특정 데이터(시가/종가/고가/저가/거래량)를 반환하는 함수
def
get_one_day_option_data
(
self
,
code
,
start
,
option
):
self
.
ohlcv
=
defaultdict
(
list
)
self
.
set_input_value
(
"종목코드"
,
code
)
self
.
set_input_value
(
"기준일자"
,
start
)
self
.
set_input_value
(
"수정주가구분"
,
1
)
self
.
comm_rq_data
(
"opt10081_req"
,
"opt10081"
,
0
,
"0101"
)
if
self
.
ohlcv
[
'date'
]
==
''
:
return
False
df
=
DataFrame
(
self
.
ohlcv
,
columns
=
[
'open'
,
'high'
,
'low'
,
'close'
,
'volume'
],
index
=
self
.
ohlcv
[
'date'
])
if
df
.
empty
:
return
False
if
option
==
"open"
:
return
df
.
iloc
[
0
,
0
]
elif
option
==
'high'
:
return
df
.
iloc
[
0
,
1
]
elif
option
==
'low'
:
return
df
.
iloc
[
0
,
2
]
elif
option
==
'close'
:
return
df
.
iloc
[
0
,
3
]
elif
option
==
'volume'
:
return
df
.
iloc
[
0
,
4
]
else
:
return
False
# open_api에 주문요청을 보내는 함수. 성공할 경우 return 0
# param - sRQName : 사용자 구분명
# sScrNo : 화면번호
# sAccNo : 계좌번호
# nOrderType : 주문유형 (1.신규매수/2.신규매도/3.매수취소/4.매도취소/5.매수정정/6.매도정정
# code : 종목코드
# nQty : 주문수량
# nPrice : 주문가격
# sHogaGb : 거래구분 (00.지정가/03.시장가/05.조건부지정가/06.최유리지정가/07.최우선지정가/10.지정가IOC/
# 13.시장가IOC/16.최유리IOC/20.지정가FOK/23.시장가FOK/26.최유리FOK/61.장전시간외종가
# 62.시간외단일가매매/81.장후시간외종가)
# sOrgOrderNo : 원주문번호. 신규주문은 공백, 정정(취소) 주문할 원주문번호 입력
# return - 0 : 성공
# - -308 : 주문가능횟수 초과. 1초에 5회만 주문 가능
# - 이외 : 주문실패
def
send_order
(
self
,
sRQName
,
sScrNo
,
sAccNo
,
nOrderType
,
code
,
nQty
,
nPrice
,
sHogaGb
,
sOrgOrderNo
):
logger
.
debug
(
"send order"
)
try
:
self
.
exit_check
()
self
.
dynamicCall
(
"SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)"
,
[
sRQName
,
sScrNo
,
sAccNo
,
nOrderType
,
code
,
nQty
,
nPrice
,
sHogaGb
,
sOrgOrderNo
])
except
Exception
as
e
:
logger
.
critical
(
e
)
# 코드명에 해당하는 종목코드를 반환하는 함수
def
codename_to_code
(
self
,
codename
):
# 데이터베이스에 종목명과 같은 값을 가지는 행의 code를 반환
query
=
f
"select code from stock_item_all where code_name={codename}"
result
=
self
.
engine_daily_buy_list
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
!=
0
:
return
result
[
0
][
0
]
# 종목명의 길이가 길 경우
query
=
f
"select code from stock_item_all where code_name like '{codename}
%
'"
result
=
self
.
engine_daily_buy_list
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
!=
0
:
return
result
[
0
][
0
]
# 종목명에 해당하는 값이 없을 경우 return False
return
False
# 매수 완료 후 데이터베이스를 업데이트 하는 함수
def
end_invest_count_check
(
self
,
code
):
query
=
f
"update all_stocks set chegyul_check='0' WHERE code='{code}' and sell_date = '0' "
\
f
"ORDER BY buy_date desc LIMIT 1"
self
.
engine_bot
.
execute
(
query
)
# possessed_item 테이블에 중복으로 데이터가 반영되는 것을 막기 위해 possessed_item에서 해당 종목 삭제
query
=
f
"delete from possessed_item where code ={code}"
self
.
engine_bot
.
execute
(
query
)
# 잔액이 생겨서 다시 매수할 수 있는 상황이 되었을 경우, setting_data의 today_buy_stop 옵션을 0으로 변경경
def
reset_buy_check
(
self
):
query
=
"UPDATE setting_data SET today_buy_stop='0' WHERE id='1'"
self
.
engine_bot
.
execute
(
query
)
# 투자 가능한 잔액이 부족하거나, 매수할 종목이 더 이상 없는 경우 setting_data의 today_buy_stop옵션을 0으로 변경
# 더이상 매수하지 않음
def
buy_check_stop
(
self
):
query
=
f
"UPDATE setting_data SET today_buy_stop='{self.today}' limit 1"
self
.
engine_bot
.
execute
(
query
)
# 잔액을 확인하는 함수
# 잔액이 부족하여 더이상 투자를 진행할 수 없는 경우, janfo_is_null을 True로 설정한 후 False 반환
def
check_jango
(
self
):
self
.
get_deposit
()
try
:
if
int
(
self
.
d2_deposit_before_format
)
>
(
int
(
self
.
sf
.
limit_money
)):
self
.
jango_is_null
=
False
# trade 루프를 돌다가 잔액이 부족해졌을 때 루프를 빠져나오기 위한 변수
return
True
else
:
self
.
jango_is_null
=
True
return
False
except
Exception
as
e
:
logger
.
critical
(
e
)
# today_buy_stop 칼럼을 확인하는 함수
# setting_data테이블의 today_buy_stop 칼럼에 오늘 날짜가 적혀있는 경우 매수 중지
def
buy_check
(
self
):
query
=
"select today_buy_stop from setting_data limit 1"
result
=
self
.
engine_JB
.
execute
(
sql
)
.
fetchall
()[
0
][
0
]
if
result
!=
self
.
today
:
return
True
else
:
return
False
# 구매할 수량을 계산하는 함수
def
buy_num_count
(
self
,
invest_unit
,
present_price
):
return
int
(
invest_unit
/
present_price
)
# 거래 함수
def
trade
(
self
):
# 실시간 현재가(close)를 저장
# 현재시점의 종가(close)는 현재가와 같다
current_price
=
self
.
get_one_day_option_data
(
self
.
get_today_buy_list_code
,
self
.
today
,
'close'
)
if
current_price
==
False
:
return
False
min_buy_limit
=
int
(
self
.
get_today_buy_list_close
)
*
self
.
sf
.
invest_min_limit_rate
# 매수가격 최저 범위
max_buy_limit
=
int
(
self
.
get_today_buy_list_close
)
*
self
.
sf
.
invest_limit_rate
# 매수가격 최고 범위
# 현재가가 매수 가격 최저 범위와 매수 가격 최고 범위 안에 들어와 있다면 매수
if
min_buy_limit
<
current_price
<
max_buy_limit
:
buy_num
=
self
.
buy_num_count
(
self
.
invest_unit
,
int
(
current_price
))
logger
.
debug
(
"매수+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- code :
%
s, 목표가:
%
s, 현재가:
%
s, 매수량:
%
s, min_buy_limit:
%
s, max_buy_limit:
%
s , invest_limit_rate:
%
s,예수금:
%
s , today :
%
s, today_min :
%
s, date_rows_yesterday :
%
s, invest_unit :
%
s, real_invest_unit :
%
s +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-"
,
self
.
get_today_buy_list_code
,
self
.
get_today_buy_list_close
,
current_price
,
buy_num
,
min_buy_limit
,
max_buy_limit
,
self
.
sf
.
invest_limit_rate
,
self
.
d2_deposit_before_format
,
self
.
today
,
self
.
today_detail
,
self
.
date_rows_yesterday
,
self
.
invest_unit
,
int
(
current_price
)
*
int
(
buy_num
))
# 03 시장가 매수
# 4번째 parameter: 1: 신규매수 / 2: 신규매도 / 3:매수취소 / 4:매도취소 / 5: 매수정정 / 6:매도정정
self
.
send_order
(
"send_order_req"
,
"0101"
,
self
.
account_number
,
1
,
self
.
get_today_buy_list_code
,
buy_num
,
0
,
"03"
,
""
)
# 만약 sf.only_nine_buy가 False 이면, 매도 후에 잔액이 생기면 다시 매수를 시작
# sf.only_nine_buy가 True이면 1회만 매수, 1회 매수 시 잔액이 부족해지면 바로 매수 중단
if
not
self
.
jango_check
()
and
self
.
sf
.
use_nine
:
# setting_data에 today_buy_stop을 1 로 설정
self
.
buy_check_stop
()
def
get_today_buy_list
(
self
):
# 구매할 목록을 저장하는 테이블(realtime_daily_buy_list)이 존재하지 않거나, 테이블 내에 항목이 존재하지 않는다면 return
if
self
.
sf
.
is_simul_table_exist
(
self
.
db_name
,
"realtime_daily_buy_list"
):
self
.
sf
.
get_realtime_daily_buy_list
()
if
self
.
sf
.
len_df_realtime_daily_buy_list
==
0
:
return
else
:
return
# 만약에 realtime_daily_buy_list 의 종목 수가 1개 이상이면
for
i
in
range
(
self
.
sf
.
len_df_realtime_daily_buy_list
):
code
=
self
.
sf
.
df_realtime_daily_buy_list
.
loc
[
i
,
'code'
]
close
=
self
.
sf
.
df_realtime_daily_buy_list
.
loc
[
i
,
'close'
]
check_item
=
self
.
sf
.
df_realtime_daily_buy_list
.
loc
[
i
,
'check_item'
]
# 매수확인. 오늘 매수한 종목이면 1, 아니면 0
# 잔액이 부족한 경우 break
if
self
.
jango_is_null
:
break
# 이미 매수한 종목은 건너뛰고 다음종목 거래래
if
check_item
==
True
:
continue
else
:
self
.
get_today_buy_list_code
=
code
self
.
get_today_buy_list_close
=
close
# 매수 하기 전에 해당 종목의 check_item을 1로 변경
query
=
f
"UPDATE realtime_daily_buy_list SET check_item='1' WHERE code='{self.get_today_buy_list_code}'"
self
.
engine_bot
.
execute
(
query
)
self
.
trade
()
# 모든 매수를 마쳤으면 더이상 매수 하지 않도록 설정
if
self
.
sf
.
use_nine
:
self
.
buy_check_stop
()
# 보유하고 있는 종목에 대해 all_stocks(거래내역) 테이블을 업데이트
def
rate_check
(
self
):
query
=
"select code,holding_amount,purchase_price,present_price,valuation_profit,rate,item_total_purchase "
\
"from possessed_item group by code"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
num
=
len
(
result
)
for
k
in
range
(
num
):
code
=
result
[
k
][
0
]
holding_amount
=
result
[
k
][
1
]
purchase_price
=
result
[
k
][
2
]
present_price
=
result
[
k
][
3
]
valuation_profit
=
result
[
k
][
4
]
rate
=
result
[
k
][
5
]
item_total_purchase
=
result
[
k
][
6
]
query
=
f
"update all_stocks set "
\
f
"holding_amount ='{holding_amount}', purchase_price ='{purchase_price}', "
\
f
"present_price='{present_price}',valuation_profit='{valuation_profit}',rate='{rate}',"
\
f
"item_total_purchase='{item_total_purchase}' "
\
f
"where code='{code}' and sell_date = '0'"
self
.
engine_bot
.
execute
(
query
)
# 매도 후 possessed_item(보유종목) 테이블에는 없지만,
# all_stocks(거래내역) 테이블에 sell_date가 업데이트되지 않은 항목을 처리하는 함수
def
sell_final_check2
(
self
,
code
):
query
=
f
"UPDATE all_stocks SET chegyul_check='0', sell_date ='{self.today_time}' "
\
f
"WHERE code='{code}' and sell_date ='0' ORDER BY buy_date desc LIMIT 1"
self
.
engine_bot
.
execute
(
query
)
# all_stocks(거래내역) 테이블에서 현재 보유중인 종목이 존재하는지 확인하는 함수
def
is_all_stock_check
(
self
,
code
):
query
=
f
"select code from all_stocks where code='{code}' and (sell_date ='0' or sell_date='') "
\
f
"ORDER BY buy_date desc LIMIT 1"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
!=
0
:
return
True
else
:
return
False
# 주식일봉차트조회 요청 함수 - 하나의 데이터만 저장
def
_opt10081
(
self
,
sRQName
,
sTrCode
):
code
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
0
,
"종목코드"
)
...
...
@@ -895,8 +1232,11 @@ class Open_Api(QAxWidget):
# 예수금 상세현황요청 함수
def
_opw00001
(
self
,
sRQName
,
sTrCode
):
self
.
deposit
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
0
,
"d+2출금가능금액"
)
self
.
deposit
=
int
(
self
.
deposit
)
try
:
self
.
d2_deposit_before_format
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
0
,
"d+2출금가능금액"
)
self
.
d2_deposit
=
self
.
change_format
(
self
.
d2_deposit_before_format
)
except
Exception
as
e
:
logger
.
critical
(
e
)
# 계좌평가 잔고내역을 저장하는 변수 초기화
def
reset_opw00018_output
(
self
):
...
...
@@ -913,23 +1253,23 @@ class Open_Api(QAxWidget):
self
.
total_earning_rate
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
0
,
"총수익률(
%
)"
)
self
.
estimated_deposit
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
0
,
"추정예탁자산"
)
self
.
total_purchase_price
=
in
t
(
self
.
total_purchase_price
)
self
.
total_eval_price
=
in
t
(
self
.
total_eval_price
)
self
.
total_eval_profit_loss_price
=
in
t
(
self
.
total_eval_profit_loss_price
)
self
.
total_earning_rate
=
float
(
self
.
total_earning_rate
)
self
.
estimated_deposit
=
in
t
(
self
.
estimated_deposit
)
self
.
change_total_purchase_price
=
self
.
change_forma
t
(
self
.
total_purchase_price
)
self
.
change_total_eval_price
=
self
.
change_forma
t
(
self
.
total_eval_price
)
self
.
change_total_eval_profit_loss_price
=
self
.
change_forma
t
(
self
.
total_eval_profit_loss_price
)
self
.
change_total_earning_rate
=
self
.
change_format2
(
self
.
total_earning_rate
)
self
.
change_estimated_deposit
=
self
.
change_forma
t
(
self
.
estimated_deposit
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
total_purchase_price
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
total_eval_price
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
total_eval_profit_loss_price
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
total_earning_rate
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
estimated_deposit
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
change_
total_purchase_price
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
change_
total_eval_price
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
change_
total_eval_profit_loss_price
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
change_
total_earning_rate
)
self
.
opw00018_output
[
'single'
]
.
append
(
self
.
change_
estimated_deposit
)
# 종목별 평가 잔고 데이터 - 멀티데이터 저장
rows
=
self
.
_get_repeat_cnt
(
sTrCode
,
sRQName
)
for
i
in
range
(
rows
):
code
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"종목번호"
)
code
=
code_pattern
.
search
(
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"종목번호"
))
.
group
(
0
)
name
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"종목명"
)
quantity
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"보유수량"
)
purchase_price
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"매입가"
)
...
...
@@ -938,13 +1278,12 @@ class Open_Api(QAxWidget):
earning_rate
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"수익률(
%
)"
)
item_total_purchase
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"매입금액"
)
code
=
code
[
1
:]
quantity
=
int
(
quantity
)
purchase_price
=
int
(
purchase_price
)
current_price
=
int
(
current_price
)
eval_profit_loss_price
=
int
(
eval_profit_loss_price
)
earning_rate
=
float
(
earning_rate
)
item_total_purchase
=
int
(
item_total_purchase
)
quantity
=
self
.
change_format
(
quantity
)
purchase_price
=
self
.
change_format
(
purchase_price
)
current_price
=
self
.
change_format
(
current_price
)
eval_profit_loss_price
=
self
.
change_format
(
eval_profit_loss_price
)
earning_rate
=
self
.
change_format2
(
earning_rate
)
item_total_purchase
=
self
.
change_format
(
item_total_purchase
)
self
.
opw00018_output
[
'multi'
]
.
append
(
[
name
,
quantity
,
purchase_price
,
current_price
,
eval_profit_loss_price
,
earning_rate
,
item_total_purchase
,
code
]
...
...
@@ -952,8 +1291,12 @@ class Open_Api(QAxWidget):
# 일자별 실현 손익 요청
def
_opt10074
(
self
,
sRQName
,
sTrCode
):
self
.
total_profit
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
0
,
"실현손익"
)
self
.
today_profit
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
0
,
"당일매도손익"
)
try
:
rows
=
self
.
_get_repeat_cnt
(
sTrCode
,
sRQName
)
self
.
total_profit
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
0
,
"실현손익"
)
self
.
today_profit
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
0
,
"당일매도손익"
)
except
Exception
as
e
:
logger
.
critical
(
e
)
# 위탁종합거래내역 요청 함수
def
_opw00015
(
self
,
sRQName
,
sTrCode
):
...
...
@@ -966,7 +1309,7 @@ class Open_Api(QAxWidget):
def
_opt10076
(
self
,
sRQName
,
sTrCode
):
outputs
=
[
'주문번호'
,
'종목명'
,
'주문구분'
,
'주문가격'
,
'주문수량'
,
'체결가'
,
'체결량'
,
'미체결수량'
,
'당일매매수수료'
,
'당일매매세금'
,
'주문상태'
,
'매매구분'
,
'원주문번호'
,
'주문시간'
,
'종목코드'
]
self
.
_data
=
{}
self
.
_data
=
{}
# 미체결 항목을 저장하는 변수
for
key
in
outputs
:
if
key
not
in
[
'주문번호'
,
'원주문번호'
,
'주문시간'
,
'종목코드'
]:
...
...
@@ -990,7 +1333,7 @@ class Open_Api(QAxWidget):
today_profit
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"당일매도손익"
)
earning_rate
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"손익율"
)
code
=
code
.
lstrip
(
'A'
)
code
=
self
.
change_format4
(
code
)
self
.
opt10073_output
[
'multi'
]
.
append
([
date
,
code
,
code_name
,
amount
,
today_profit
,
earning_rate
])
...
...
@@ -1013,6 +1356,78 @@ class Open_Api(QAxWidget):
self
.
ohlcv
[
'volume'
]
.
append
(
int
(
volume
))
self
.
ohlcv
[
'sum_volume'
]
.
append
(
int
(
0
))
# 데이터베이스로부터 보유하고 있는 종목의 보유량(holding amount)을 가져오는 함수
def
get_holding_amount
(
self
,
code
):
logger
.
debug
(
"-* get_holding_amount function *-"
)
query
=
f
"select holding_amount from possessed_item where code={code}"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
if
len
(
result
):
return
result
[
0
][
0
]
else
:
logger
.
debug
(
"Holding amount is empty."
)
return
False
# open_api로부터 받아온 데이터의 형식을 변형하는 함수
# 데이터 값 앞의 의미없는 0을 제거
def
change_format
(
self
,
data
):
try
:
strip_data
=
data
.
lstrip
(
'0'
)
# 유효한 값이 존재하지 않을 경우 0으로 대체
if
strip_data
==
""
:
strip_data
=
'0'
return
int
(
strip_data
)
except
Exception
as
e
:
logger
.
critical
(
e
)
# 수익률을 소수 형태로 변환하는 함수
def
change_format2
(
self
,
data
):
try
:
strip_data
=
data
.
lstrip
(
'-0'
)
# 유효한 값이 없을 경우 0으로 대체
if
strip_data
==
""
:
strip_data
=
'0'
else
:
strip_data
=
str
(
float
(
strip_data
)
/
self
.
mod_gubun
)
# 수익률< 1 일 경우
if
strip_data
.
startswith
(
'.'
):
strip_data
=
'0'
+
strip_data
# 수익률 < 0 일 경우
if
data
.
startswith
(
'-'
):
strip_data
=
'-'
+
strip_data
return
strip_data
except
Exception
as
e
:
logger
.
critical
(
e
)
# 특수문자(%), 앞뒤 공백 제거 함수
def
change_format3
(
self
,
data
):
try
:
strip_data
=
data
.
stript
(
'
%
'
)
strip_data
=
strip_data
.
strip
()
return
strip_data
except
Exception
as
e
:
logger
.
critical
(
e
)
# 코드 앞의 문자를 제거하는 함수수
def
change_format4
(
sel
,
data
):
try
:
strip_data
=
data
.
lstrip
(
'A'
)
return
strip_data
except
Exception
as
e
:
logger
.
critical
(
e
)
# open api 조회 요청 수를 체크하는 함수
# 최대 조회 요청 가능 횟수를 넘어서면, 프로그램을 종료
def
exit_check
(
self
):
rq_delay
=
datetime
.
timedelta
(
seconds
=
0.6
)
time_diff
=
datetime
.
datetime
.
now
()
-
self
.
call_time
if
rq_delay
>
time_diff
:
time
.
sleep
((
rq_delay
-
time_diff
)
.
total_seconds
())
self
.
rq_count
+=
1
logger
.
debug
(
self
.
rq_count
)
if
self
.
rq_count
==
cf
.
max_api_call
:
sys
.
exit
(
1
)
if
__name__
==
"__main__"
:
app
=
QApplication
(
sys
.
argv
)
...
...
Please
register
or
login
to post a comment