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-25 03:50:12 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
f1ae6cc2bcb113825f7744dd1a4c9f3254ff046a
f1ae6cc2
1 parent
e329ca69
simulator기능 구현
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1385 additions
and
84 deletions
proj/library/Simulator_Api.py
proj/library/config.py → proj/library/cf.py
proj/library/collector_api.py
proj/library/open_api.py
proj/library/Simulator_Api.py
View file @
f1ae6cc
import
datetime
from
sqlalchemy
import
*
import
pymysql
from
pandas
import
DataFrame
from
pandas
import
*
import
config
from
Logger
import
*
import
cf
class
Simulator_
Api
:
class
Simulator_
Func
:
def
__init__
(
self
,
simul_num
,
op
,
db_name
):
self
.
simul_num
=
int
(
simul_num
)
if
op
==
"real"
:
if
self
.
simul_num
==-
1
:
self
.
set_date
()
elif
op
==
'reset'
:
self
.
op
=
'reset'
self
.
simul_reset
=
True
self
.
set_variable
()
self
.
rotate_date
()
elif
op
==
'real'
:
self
.
op
=
'real'
self
.
simul_reset
=
False
self
.
db_name
=
db_name
self
.
set_variable
()
elif
op
==
'continue'
:
self
.
op
=
'continue'
self
.
simul_reset
=
False
self
.
set_variable
()
self
.
rotate_date
()
else
:
logger
.
error
(
"Invalid option"
)
# 오늘 날짜를 설정하는 함수
def
set_date
(
self
):
self
.
today
=
datetime
.
datetime
.
today
()
.
strftime
(
"
%
Y
%
m
%
d"
)
self
.
today_with_time
=
datetime
.
datetime
.
today
()
.
strftime
(
"
%
Y
%
m
%
d
%
H
%
M"
)
self
.
today_form
=
datetime
.
datetime
.
strptime
(
self
.
today
,
"
%
Y
%
m
%
d"
)
.
date
()
# 사용되는 변수를 설정하는 함수
def
set_variable
(
self
):
self
.
set_date
()
self
.
set_database
()
self
.
simul_end_date
=
self
.
today
# 시뮬레이션이 끝나는 날짜
self
.
start_min
=
"0900"
# 장 시작 시간 : 9시
self
.
use_min
=
False
# 분별 시뮬레이션을 사용하는 변수
self
.
use_nine
=
True
# 9시에만 거래를 수행하는 변수
self
.
buy_stop
=
False
# 거래를 중지하는 변수
self
.
trade_check_num
=
False
# 실시간 조건 매수 옵션. 분별 시뮬레이팅의 경우 True, 일별 시뮬레이팅의 경우 False
print
(
"simul_num : "
,
self
.
simul_num
)
if
self
.
simul_num
==
1
:
self
.
simul_start_date
=
"20190101"
# 매수/매도 알고리즘 설정
self
.
buy_algorithm
=
1
self
.
sell_algorithm
=
1
# 시뮬레이션 변수 설정
self
.
start_invest_price
=
1000000
# 초기 투자자금
self
.
invest_unit
=
100000
# 매수 금액 단위
self
.
limit_money
=
300000
# 자산 중 최소로 남겨 둘 금액
self
.
sell_point
=
10
# 익절 수익률 기준
self
.
losscut_point
=-
2
# 손절 수익률 기준
self
.
invest_limit_rate
=
1.01
# 매수하는 순간 종목의 최신 종가보다 가격이 n%이상 상승했을 때는 매수하지 않음
self
.
invest_min_limit_rate
=
0.98
# 매수하는 순간 종목의 최신 종가보다 가격이 n%이상 하락했을 경우 매수하지 않음
elif
self
.
simul_num
==
2
:
self
.
simul_start_date
=
"20190101"
self
.
buy_algorithm
=
2
self
.
sell_algorithm
=
2
self
.
start_invest_price
=
1000000
self
.
invest_unit
=
100000
self
.
limit_money
=
300000
self
.
sell_point
=
10
self
.
losscut_point
=-
2
self
.
invest_buy_limit_rate
=
1.01
self
.
invest_sell_limit_rate
=
0.98
elif
self
.
simul_num
==
3
:
self
.
simul_start_date
=
"20190101"
self
.
buy_algorithm
=
3
self
.
sell_algorithm
=
3
self
.
start_invest_price
=
1000000
self
.
invest_unit
=
100000
self
.
limit_money
=
300000
self
.
sell_point
=
10
self
.
losscut_point
=
-
2
self
.
invest_buy_limit_rate
=
1.01
self
.
invest_sell_limit_rate
=
0.98
else
:
logger
.
error
(
"Invalid simul_num"
)
self
.
set_db_control
()
if
self
.
op
!=
'real'
:
self
.
set_table
()
self
.
get_date_for_simul
()
self
.
total_valuation_profit
=
0
# 매도 종목들에 대한 총 수익
self
.
sum_valuation_profit
=
0
# 실제 수익 = 매도종목에 대한 수익 + 현재 보유 종목의 수익
self
.
total_invest_price
=
self
.
start_invest_price
# 총자산 : 투자금액 + 실제 수익
self
.
total_purchase_price
=
0
# 투자금
self
.
d2_deposit
=
self
.
start_invest_price
# 예수금 = 초기자본 + 매도수익 - 투자금
self
.
update_balance
()
# 일별 정산
self
.
tax_rate
=
0.0025
# 거래 세금
self
.
fees_rate
=
0.00015
# 거래 수수료
# 매수/매도 알고리즘 선택 -> 차후 알고리즘 별로 구현 및 재설정
self
.
buy_algorithm
=
1
self
.
sell_algorithm
=
1
self
.
simul_reset_lock
=
False
# 시뮬레이터를 멈춘 지점부터 다시 돌릴 것인지를 선택하는 변수
# 투자에서 사용할 변수 설정
self
.
per_invest
=
1000000
# 한 항목 당 구매할 금액
# database를 control하기 위한 eninge 및 connection을 저장하는 함수
def
set_db_control
(
self
):
# simul database에 접속하는 engine
if
self
.
op
==
'real'
:
self
.
engine_simul
=
create_engine
(
"mysql+pymysql://"
+
cf
.
db_id
+
":"
+
cf
.
db_pw
+
"@"
+
cf
.
db_ip
+
":"
+
cf
.
db_port
+
"/"
+
str
(
self
.
db_name
),
encoding
=
'utf-8'
)
else
:
self
.
db_name
=
"simul"
+
str
(
self
.
simul_num
)
self
.
engine_simul
=
create_engine
(
"mysql+pymysql://"
+
cf
.
db_id
+
":"
+
cf
.
db_pw
+
"@"
+
cf
.
db_ip
+
":"
+
cf
.
db_port
+
"/"
+
str
(
self
.
db_name
),
encoding
=
'utf-8'
)
# daily_craw database에 접속하는 engine
# daily_craw : 각 종목에 대해 날짜별 데이터를 저장하는 데이터베이스
self
.
engine_daily_craw
=
create_engine
(
"mysql+pymysql://"
+
cf
.
db_id
+
":"
+
cf
.
db_pw
+
"@"
+
cf
.
db_ip
+
":"
+
cf
.
db_port
+
"/daily_craw"
,
encoding
=
'utf-8'
)
# min_craw database에 접속하는 engine
# min_craw : 각 종목에 대해 분별 데이터를 저장하는 데디터베이스
self
.
engine_craw
=
create_engine
(
"mysql+pymysql://"
+
cf
.
db_id
+
":"
+
cf
.
db_pw
+
"@"
+
cf
.
db_ip
+
":"
+
cf
.
db_port
+
"/min_craw"
,
encoding
=
'utf-8'
)
# daily_buy_list database에 접속하는 engine
# daily_buy_list : 날짜별로 종목에 대한 데이터를 저장하는 데이터베이스
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'
)
# mysql에 접속하는 객체 생성
self
.
db_conn
=
pymysql
.
connect
(
host
=
cf
.
db_ip
,
port
=
int
(
cf
.
db_port
),
user
=
cf
.
db_id
,
password
=
cf
.
db_pw
,
charset
=
'utf8'
)
# 데이터베이스와 테이블을 설정
def
set_table
(
self
):
# simul_reset==True인 경우, 시뮬레이터를 초기화하고 다시 구축
if
self
.
simul_reset
:
self
.
init_database
()
# simul_reset==False인 경우, 시뮬레이터를 초기화하지 않고 마지막으로 끝난 시점 부터 다시 구동
else
:
# 시뮬레이터 데이터베이스, transaction 테이블, account_balance 테이블이 모두 존재하는 경우 이어서 시뮬레이션
if
(
self
.
is_simul_database_exist
()
and
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
)
and
self
.
is_simul_table_exist
(
self
.
db_name
,
"account_balance"
)):
self
.
init_df_transaction
()
self
.
init_df_account_balance
()
self
.
last_simul_date
=
self
.
get_last_date_account_balance
()
# 필요한 데이터베이스와 테이블이 모두 존재하지 않는 경우, 다시 생성
else
:
self
.
init_database
()
self
.
simul_reset
=
True
# 시뮬레이터 데이터베이스 초기화
def
init_database
(
self
):
self
.
drop_database
()
self
.
create_database
()
self
.
init_df_account_balance
()
self
.
init_df_transaction
()
self
.
sell_point
=
10
# 매도 수익률
self
.
limit_money
=
1000000
# 최소로 남겨놓을 금액
# 시뮬레이터 데이터베이스 삭제
def
drop_database
(
self
):
if
self
.
is_simul_database_exist
():
query
=
f
"drop DATABASE {self.db_name}"
self
.
db_conn
.
cursor
()
.
execute
(
query
)
self
.
db_conn
.
commit
()
# 특정 데이터베이스 내에 특정 테이블이 존재하는지 확인하는 함수
def
is_table_exist
(
self
,
db_name
,
table_name
):
query
=
"select 1 from information_schema.tables where table_schema='
%
s' and table_name='
%
s'"
result
=
self
.
engine_simul
.
execute
(
query
%
(
db_name
,
table_name
))
.
fetchall
()
# 시뮬레이터 데이터베이스 생성
def
create_database
(
self
):
if
not
self
.
is_simul_database_exist
():
query
=
f
"create DATABASE {self.db_name}"
self
.
db_conn
.
cursor
()
.
execute
(
query
)
self
.
db_conn
.
commit
()
# 시뮬레이터 데이터베이스가 존재하는지 확인하는 함수
def
is_simul_database_exist
(
self
):
query
=
f
"SELECT 1 FROM Information_schema.SCHEMATA WHERE SCHEMA_NAME = '{self.db_name}'"
result
=
self
.
engine_daily_buy_list
.
execute
(
query
)
.
fetchall
()
if
len
(
result
):
return
True
else
:
return
False
# 시뮬레이터 데이터베이스 안에 특정 이름을 가진 테이블이 존재하는지 확인하는 함수
def
is_simul_table_exist
(
self
,
db_name
,
table_name
):
query
=
f
"select 1 from information_schema.tables where table_schema = '{db_name}' and table_name = '{table_name}'"
result
=
self
.
engine_simul
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
==
1
:
return
True
else
:
return
False
# 데이터베이스 연결 설정
def
set_database
(
self
):
if
self
.
op
==
"real"
:
self
.
engine_simul
=
create_engine
(
"mysql+pymysql://"
+
config
.
db_id
+
":"
+
config
.
db_pw
+
"@"
+
config
.
db_ip
+
":"
+
config
.
db_port
+
"/"
+
str
(
self
.
db_name
),
encoding
=
'utf-8'
)
else
:
self
.
db_name
=
'simulator'
+
str
(
self
.
simul_num
)
self
.
engine_simul
=
create_engine
(
"mysql+pymysql://"
+
config
.
db_id
+
":"
+
config
.
db_pw
+
"@"
+
config
.
db_ip
+
":"
+
config
.
db_port
+
"/"
+
str
(
self
.
db_name
),
encoding
=
'utf-8'
)
self
.
engine_daily
=
create_engine
(
"mysql+pymysql://"
+
config
.
db_id
+
":"
+
config
.
db_pw
+
"@"
+
config
.
db_ip
+
":"
+
config
.
db_port
+
"/daily_info"
,
encoding
=
'utf-8'
)
self
.
engine_stock
=
create_engine
(
"mysql+pymysql://"
+
config
.
db_id
+
":"
+
config
.
db_pw
+
"@"
+
config
.
db_ip
+
":"
+
config
.
db_port
+
"/stock_info"
,
encoding
=
'utf-8'
)
self
.
engine_minute
=
create_engine
(
"mysql+pymysql://"
+
config
.
db_id
+
":"
+
config
.
db_pw
+
"@"
+
config
.
db_ip
+
":"
+
config
.
db_port
+
"/minute_info"
,
encoding
=
'utf-8'
)
self
.
conn
=
pymysql
.
connect
(
host
=
config
.
db_ip
,
port
=
int
(
config
.
db_port
),
user
=
config
.
db_id
,
password
=
config
.
db_pw
,
charset
=
'utf8'
)
# account_balance table 생성
def
init_df_account_balance
(
self
):
a_balance
=
{
'id'
:[]}
self
.
account_balance
=
DataFrame
(
a_balance
,
columns
=
[
'date'
,
'today_earning_rate'
,
'sum_valuation_profit'
,
'total_profit'
,
'today_profit'
,
'today_profitcut_count'
,
'today_losscut_count'
,
'today_profitcut'
,
'today_losscut'
,
'd2_deposit'
,
'total_possess_count'
,
'today_buy_count'
,
'total_invest'
,
'sum_item_total_purchase'
,
'total_evaluation'
,
'today_rate'
,
'today_invest_price'
,
'today_sell_price'
,
'volume_limit'
,
'sell_point'
,
'invest_unit'
,
'limit_money'
,
'total_profitcut'
,
'total_losscut'
,
'total_profitcut_count'
,
'total_losscut_count'
,
'today_buy_today_sell_count'
,
'today_buy_today_possess_count'
,
'today_buy_today_profitcut_count'
,
'today_buy_today_losscut_count'
,
'today_buy_today_profitcut_rate'
,
'today_buy_today_losscut_rate'
],
index
=
a_balance
[
'id'
])
# transaction table 생성
def
init_df_transaction
(
self
):
trs
=
{
'id'
:[]}
self
.
df_transaction
=
DataFrame
(
trs
,
columns
=
[
'id'
,
'order_num'
,
'code'
,
'code_name'
,
'rate'
,
'purchase_rate'
,
'purchase_price'
,
'present_price'
,
'valuation_price'
,
'valuation_profit'
,
'holding_amount'
,
'buy_date'
,
'item_total_purchase'
,
'chegyul_check'
,
'invest_unit'
,
'sell_date'
,
'sell_price'
,
'sell_rate'
,
'rate_std'
,
'rate_std_mod_val'
,
'rate_std_htr'
,
'rate_htr'
,
'rate_std_mod_val_htr'
,
'yes_close'
,
'close'
,
'd1_diff_rate'
,
'd1_diff'
,
'open'
,
'high'
,
'low'
,
'volume'
,
'clo5'
,
'clo10'
,
'clo20'
,
'clo60'
,
'clo120'
,
"clo5_diff_rate"
,
"clo10_diff_rate"
,
"clo20_diff_rate"
,
"clo60_diff_rate"
,
"clo120_diff_rate"
])
# account_balance(잔고 데이터)에 저장된 가장 최근의 날짜를 가져오는 함수
def
get_last_date_account_balance
(
self
):
query
=
"SELECT date from account_balance order by date desc limit 1"
result
=
self
.
engine_simul
.
execute
(
query
)
.
fechall
()
return
result
[
0
][
0
]
# 시뮬레이팅 할 날짜 리스트를 가져오는 함수
# 장이 열렸던 날을 self.date_rows에 담기 위해 gs글로벌의 date값을 이용
def
get_date_for_simul
(
self
):
query
=
f
"select date from `gs글로벌` "
\
f
"where date >= '{self.simul_start_date}' and date <= '{self.simul_end_date}' group by date"
self
.
date_rows
=
self
.
engine_daily_craw
.
execute
(
query
)
.
fetchall
()
# 거래한 데이터를 바탕으로 거래이력(transaction) 테이블을 정산하는 함수
def
update_balance
(
self
):
# transaction table이 존재하지 않을 경우 return
if
not
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
):
return
query
=
"select sum(valuation_profit) from transaction"
self
.
sum_valuation_profit
=
self
.
engine_simul
.
execute
(
query
)
.
fethcall
()[
0
][
0
]
# 총수익금 (종목별 평가 금액의 합)
self
.
total_invest_price
=
self
.
start_invest_price
+
self
.
sum_valuation_profit
# 총자산
query
=
"select sum(item_total_purchase) from transaction where sell_date='
%
s'"
self
.
total_purchase_price
=
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fethcall
()[
0
][
0
]
# 총투자금액
if
self
.
total_purchase_price
is
None
:
self
.
total_purchase_price
=
0
query
=
"select sum(valuation_profit) from transaction where sell_date!='
%
s'"
self
.
total_valuation_profit
=
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fetchall
()[
0
][
0
]
# 매도 종목들에 대한 수익
if
self
.
total_valuation_profit
is
None
:
self
.
total_valuation_profit
=
0
self
.
d2_deposit
=
self
.
start_invest_price
+
self
.
total_valuation_profit
-
self
.
total_purchase_price
# 예수금
# 날짜별로 돌아가면서 시뮬레이션을 실행하는 함수
def
rotate_date
(
self
):
for
i
in
range
(
self
.
date_rows
):
date_rows_today
=
self
.
date_rows
[
i
][
0
]
# 시뮬레이팅 할 날짜
date_rows_yesterday
=
self
.
date_rows
[
i
-
1
][
0
]
# 시뮬레이팅 하루 전 날짜
# simul_reset=False인 경우, 시뮬레이터를 멈춘 지점부터 다시 시작
if
not
self
.
simul_reset
and
not
self
.
simul_reset_lock
:
if
int
(
date_rows_today
)
<=
int
(
self
.
last_simul_date
):
continue
else
:
self
.
simul_reset_lock
=
True
# 분별 시뮬레이션
if
self
.
use_min
:
self
.
simul_by_min
(
date_rows_today
,
date_rows_yesterday
,
i
)
# 일별 시뮬레이션
else
:
self
.
simul_by_date
(
date_rows_today
,
date_rows_yesterday
,
i
)
# 시뮬레이션을 완료한 후 account_balance 테이블 업데이트
self
.
arrange_account_balance
()
# 하루에 대한 시뮬레이션이 끝난 뒤 해당 날짜의 잔고(account_balance)정보를 업데이트하는 함수
def
arrange_account_balance
(
self
):
if
self
.
engine_simul
.
dialect
.
has_table
(
self
.
engine_simul
,
"account_balance"
):
len_date
=
self
.
get_len_account_balance_data
()
query
=
"select date from account_balance"
rows
=
self
.
engine_simul
.
execute
(
query
)
.
fetchall
()
logger
.
debug
(
"account balance 최종 정산"
)
# 날짜별 주식 데이터를 저장해 놓은 데이터베이스에서 가장 최근 날짜를 가져오는 함수
def
get_latest_date
(
self
):
query
=
"select table_name from information_schema.tables where table_schema='daily_info' and "
\
"table_name like '
%
s' order by table_name desc limit 1"
result
=
self
.
engine_daily
.
execute
(
query
%
(
"20
%%
"
))
.
fetchall
()
if
len
(
result
)
==
0
:
for
i
in
range
(
len_date
):
# today_buy_count : 오늘 매수한 종목의 수
query
=
"update account_balance "
\
"set "
\
"today_buy_count=(select count(*) from (select code from transaction where buy_date like '
%
s')) "
\
"where date='
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
str
(
rows
[
i
][
0
])
+
"
%%
"
,
rows
[
i
][
0
]))
# today_buy_today_sell_count : 오늘 매수하고 오늘 매도한 종목의 수
query
=
"update account_balance "
\
"set "
\
"today_buy_today_sell_count="
\
"(select count(*) from "
\
"(select code from transaction where buy_date like '
%
s' and sell_date!=0 group by code)) "
\
"where date='
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
str
(
rows
[
i
][
0
])
+
"
%%
"
,
rows
[
i
][
0
]))
# today_buy_today_possess_count : 오늘 매수하였으나 매도하지 않은 종목의 수
query
=
"update account_balance "
\
"set"
\
"today_buy_today_possess_count="
\
"(select count(*) from "
\
"(select code from transaction where buy_date like '
%
s' and sell_date='
%
s' group by code)) "
\
"where date='
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
rows
[
i
][
0
]
+
"
%%
"
,
0
,
rows
[
i
][
0
]))
# today_buy_today_profitcut_count : 오늘 매수하고 익절한 종목의 수
query
=
"update account_balance "
\
"set "
\
"today_buy_today_profitcut_count="
\
"(select count(*) from "
\
"(select code from transaction "
\
"where buy_date like '
%
s' and sell_date like '
%
s' and sell_rate>'
%
s' group by code)) "
\
"where date='
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
rows
[
i
][
0
]
+
"
%%
"
,
"
%%
"
+
rows
[
i
][
0
]
+
"
%%
"
,
0
,
rows
[
i
][
0
]))
# today_buy_today_profitcut_rate : 오늘 매수하고 익절한 종목의 수익률
query
=
"update account_balance "
\
"set "
\
"today_buy_today_profitcut_rate=round(today_buy_today_profitcut_count /today_buy_count *100,2) "
\
"where date = '
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
rows
[
i
][
0
]))
# today_buy_today_losscut_count : 오늘 매수하고 손절한 종목의 수
query
=
"update account_balance "
\
"set "
\
"today_buy_today_losscut_count="
\
"(select count(*) from "
\
"(select code from transaction "
\
"where buy_date like '
%
s' and sell_date like '
%
s' and sell_rate < '
%
s' group by code)) "
\
"WHERE date='
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
rows
[
i
][
0
]
+
"
%%
"
,
"
%%
"
+
rows
[
i
][
0
]
+
"
%%
"
,
0
,
rows
[
i
][
0
]))
# today_buy_today_losscut_rate : 오늘 매수하고 손절한 종목의 수익률
query
=
"update account_balance "
\
"set "
\
"today_buy_today_losscut_rate=round(today_buy_today_losscut_count /today_buy_count *100,2) "
\
"WHERE date = '
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
rows
[
i
][
0
]))
# total_profitcut_count : 총 익절한 종목의 수
query
=
"update account_balance "
\
"set "
\
"total_profitcut_count="
\
"(select count(*) from "
\
"(select code from transaction where sell_rate >= '
%
s' group by code)) "
\
"WHERE date='
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
0
,
rows
[
i
][
0
]))
# total_profitcut : 총 익절한 금액 (매도가 - 매수가)
query
=
"update account_balance "
\
"set "
\
"total_profitcut=sum"
\
"(select sell_price-purchase_price from transaction "
\
"where sell_price>=purchase_price group by code))"
\
"WHERE date = '
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
rows
[
i
][
0
]))
# total_losscut_count : 총 손절한 종목의 수
query
=
"update account_balance "
\
"set "
\
"total_losscut_count="
\
"(select count(*) from "
\
"(select code from transaction where sell_rate < '
%
s' group by code )) "
\
"WHERE date='
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
0
,
rows
[
i
][
0
]))
# total_losscut : 총 손절한 금액 (매수가 - 매도가)
query
=
"update account_balance "
\
"set "
\
"total_losscut=sum"
\
"(select purchase_price-sell_price from transaction "
\
"where purchase_price>=sell_price)) "
\
"where date='
%
s'"
self
.
engine_simul
.
execute
(
query
%
(
rows
[
i
][
0
]))
print
(
"account balance 정산 완료"
)
# account_balance에 저장된 일자를 반환하는 함수
def
get_len_account_balance_data
(
self
):
query
=
"select date from account_balance"
rows
=
self
.
engine_simul
.
execute
(
query
)
.
fetchall
()
return
len
(
rows
)
# 분별 시뮬레이팅
def
simul_by_min
(
self
,
date_rows_today
,
date_rows_yesterday
,
i
):
print
(
"************************** date: "
+
date_rows_today
)
# 시뮬레이팅 전에 변수 초기화
self
.
set_daily_variable
()
# daily_buy_list에 시뮬레이팅 할 날짜에 해당하는 테이블과 전 날 테이블이 존재하는지 확인
if
self
.
is_date_exist
(
date_rows_today
)
and
self
.
is_date_exist
(
date_rows_yesterday
):
self
.
db_to_realtime_daily_buy_list
(
date_rows_today
,
date_rows_yesterday
,
i
)
# 매수리스트 확인
self
.
trading_by_min
(
date_rows_today
,
date_rows_yesterday
,
i
)
# 시뮬레이팅 시작
self
.
db_to_account_balance
(
date_rows_today
)
# 잔고 테이블 업데이트
# transaction 테이블이 존재하고, 현재 보유 중인 종목이 있는 경우, 해당 종목에 대해 데이터베이스 업데이트
if
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
)
and
len
(
self
.
get_data_from_possessed_item
())
!=
0
:
self
.
update_transaction_by_date
(
date_rows_today
,
option
=
'ALL'
)
else
:
print
(
"테이블이 존재하지 않습니다"
)
# 매일 시뮬레이션이 돌기 전에 변수를 초기화하는 함수
def
set_daily_variable
(
self
):
self
.
buy_stop
=
False
self
.
today_invest_price
=
0
# daily_buy_list에 특정 날짜의 이름을 가진 테이블이 존재하는지 확인하는 함수
def
is_date_exist
(
self
,
date
):
query
=
f
"select 1 from information_schema.tables where table_schema ='daily_buy_list' and table_name ='{date}'"
result
=
self
.
engine_daily_buy_list
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
==
1
:
return
True
else
:
return
False
# 매수 할 종목의 리스트를 선정하는 함수
def
db_to_realtime_daily_buy_list
(
self
,
date_rows_today
,
date_rows_yesterday
,
i
):
to_buy_list
=
None
# (5,20) 골든크로스
if
self
.
buy_algorithm
==
1
:
query
=
f
"select * from '{date_rows_yesterday}' "
\
f
"where yes_clo20>yes_clo5 and clo5>clo20 and close<'{self.invest_unit}' group by code"
to_buy_list
=
self
.
engine_daily_buy_list
.
execute
(
query
)
.
fetchall
()
# (20,60) 골든크로스
elif
self
.
buy_algorithm
==
2
:
query
=
f
"select * from '{date_rows_yesterday}' "
\
f
"where yes_clo40 > yes_clo5 and clo5 > clo40 and close < '{self.invest_unit}' group by code"
to_buy_list
=
self
.
engine_daily_buy_list
.
execute
(
query
)
.
fetchall
()
else
:
logger
.
error
(
"Invalid Algorithm Setting..."
)
# 알고리즘에 의해 선택된 항목이 존재한다면 데이터베이스에 해당 항목 업데이트
if
len
(
to_buy_list
)
>
0
:
df_to_buy_list
=
DataFrame
(
to_buy_list
,
columns
=
[
'index'
,
'index2'
,
'date'
,
'check_item'
,
'code'
,
'code_name'
,
'd1_diff'
,
'd1_diff_rate'
,
'close'
,
'open'
,
'high'
,
'low'
,
'volume'
,
'clo5'
,
'clo10'
,
'clo20'
,
'clo60'
,
'clo120'
,
"clo5_diff_rate"
,
"clo10_diff_rate"
,
"clo20_diff_rate"
,
"clo60_diff_rate"
,
"clo120_diff_rate"
,
'yes_clo5'
,
'yes_clo10'
,
'yes_clo20'
,
'yes_clo60'
,
'yes_clo120'
,
'vol5'
,
'vol10'
,
'vol20'
,
'vol60'
,
'vol120'
])
# to_buy_list 중 종목 code가 6자리의 정수로 된 항목만 선택
to_buy_list
[
'code'
]
=
to_buy_list
[
'code'
]
.
apply
(
lambda
x
:
"{:0>6d}"
.
format
(
int
(
x
)))
# 시뮬레이터
if
self
.
op
!=
'real'
:
to_buy_list
[
'check_item'
]
=
int
(
0
)
to_buy_list
.
to_sql
(
'realtime_daily_buy_list'
,
self
.
engine_simul
,
if_exists
=
'replace'
)
# 현재 보유 중인 종목은 매수 리스트(realtime_daily_buy_list) 에서 제거
if
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
):
query
=
"delete from realtime_daily_buy_list "
\
"where code in "
\
"(select code from transaction where sell_date = '0')"
self
.
engine_simul
.
execute
(
query
)
# realtime_daily_buy_list 테이블에 저장 된 종목들을 저장
self
.
get_realtime_daily_buy_list
()
# 모의투자 / 실전투자
else
:
to_buy_list
[
'check_item'
]
=
int
(
0
)
to_buy_list
.
to_sql
(
'realtime_daily_buy_list'
,
self
.
engine_simul
,
if_exists
=
'replace'
)
# 현재 보유 중인 종목들은 삭제
query
=
"delete from realtime_daily_buy_list where code in (select code from possessed_item)"
self
.
engine_simul
.
execute
(
sql
)
else
:
self
.
len_df_realtime_daily_buy_list
=
0
# realtime_daily_buy_list 테이블의 매수 리스트를 가져오는 함수
def
get_realtime_daily_buy_list
(
self
):
# check_item = 매수 했을 시 날짜. 매수 하지 않았을 때는 0
query
=
"select * from realtime_daily_buy_list where check_item = '0' group by code"
realtime_daily_buy_list
=
self
.
engine_simul
.
execute
(
query
)
.
fetchall
()
self
.
df_realtime_daily_buy_list
=
DataFrame
(
realtime_daily_buy_list
,
columns
=
[
'index'
,
'index2'
,
'date'
,
'check_item'
,
'code'
,
'code_name'
,
'd1_diff'
,
'd1_diff_rate'
,
'close'
,
'open'
,
'high'
,
'low'
,
'volume'
,
'clo5'
,
'clo10'
,
'clo20'
,
'clo60'
,
'clo120'
,
"clo5_diff_rate"
,
"clo10_diff_rate"
,
"clo20_diff_rate"
,
"clo60_diff_rate"
,
"clo120_diff_rate"
,
'yes_clo5'
,
'yes_clo10'
,
'yes_clo20'
,
'yes_clo60'
,
'yes_clo120'
,
'vol5'
,
'vol10'
,
'vol20'
,
'vol60'
,
'vol120'
])
self
.
len_df_realtime_daily_buy_list
=
len
(
self
.
df_realtime_daily_buy_list
)
# 분별 시뮬레이팅 함수
# 기능 : 새로운 종목 매수 / 보유종목 매도 / 보유종목 업데이트
def
trading_by_min
(
self
,
date_rows_today
,
date_rows_yesterday
,
i
):
self
.
show_info
(
date_rows_today
)
# 현재 보유중인 종목이 존재한다면, 보유 종목의 주가를 업데이트
if
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
):
self
.
update_transaction_by_date
(
date_rows_today
,
option
=
'OPEN'
)
# 분별 시간 데이터를 가져오기
self
.
get_min_data_for_simul
(
date_rows_today
)
if
len
(
self
.
min_data_rows
)
!=
0
:
# 분 단위로 시뮬레이팅
for
t
in
range
(
len
(
self
.
min_data_rows
)):
min
=
self
.
min_data_rows
[
t
][
0
]
# 현재 보유 종목이 있는 경우
if
self
.
is_simul_table_exist
(
self
.
db_name
,
"account_balance"
):
self
.
show_info
(
min
)
# 종목 데이터 업데이트
self
.
update_transaction_by_min
(
min
)
self
.
update_transaction_etc
()
# 매도
self
.
auto_trade_sell_stock
(
min
,
i
)
# 매수를 진행할 금액이 남아있는 경우
if
not
self
.
buy_stop
and
self
.
check_balance
():
# 매수할 종목리스트 저장
self
.
get_realtime_daily_buy_list
()
# 매수할 종목이 존재한다면 매수
if
self
.
len_df_realtime_daily_buy_list
>
0
:
self
.
auto_trade_buy_stock
(
min
,
date_rows_today
,
date_rows_yesterday
)
else
:
print
(
"금일 매수할 종목이 없습니다"
)
# 보유 종목이 없는 경우
else
:
if
not
self
.
buy_stop
and
self
.
check_balance
():
self
.
auto_trade_buy_stock
(
min
,
date_rows_today
,
date_rows_yesterday
)
if
not
self
.
buy_stop
and
self
.
use_nine
:
print
(
"9시 매수를 종료합니다"
)
self
.
buy_stop
=
True
# 시뮬레이팅 정보를 출력하는 함수
def
show_info
(
self
,
date
):
print
(
"simulator num : "
,
self
.
simul_num
)
if
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
):
print
(
"simulating 시간 : "
,
date
)
print
(
"보유종목 수 : "
,
self
.
get_count_possess_item
())
# 현재 보유하고 있는 종목수를 반환하는 함수
def
get_count_possess_item
(
self
):
query
=
"select count(*) from transaction where sell_date='0'"
result
=
self
.
engine_simul
.
execute
(
query
)
.
fetchall
()
return
result
[
0
][
0
]
# 보유 종목의 주가를 일별로 업데이트하는 함수
def
update_transaction_by_date
(
self
,
date
,
option
=
'ALL'
):
possess_item_list
=
self
.
get_data_from_possess_item
()
if
len
(
possess_item_list
)
==
0
:
print
(
"보유 종목이 없습니다"
)
for
i
in
range
(
len
(
possess_item_list
)):
code_name
=
possess_item_list
[
i
][
0
]
result
=
self
.
get_current_price_by_date
(
code_name
,
date
)
if
result
==
False
:
continue
d1_diff_rate
=
result
[
0
][
0
]
close
=
result
[
0
][
1
]
open
=
result
[
0
][
2
]
high
=
result
[
0
][
3
]
low
=
result
[
0
][
4
]
volume
=
result
[
0
][
5
]
clo5
=
result
[
0
][
6
]
clo10
=
result
[
0
][
7
]
clo20
=
result
[
0
][
8
]
clo60
=
result
[
0
][
9
]
clo120
=
result
[
0
][
10
]
if
open
:
self
.
db_to_transaction_update
(
code_name
,
d1_diff_rate
,
close
,
open
,
high
,
low
,
volume
,
clo5
,
clo10
,
clo20
,
clo60
,
clo120
,
option
)
else
:
continue
# 보유한 종목의 이름을 반환하는 함수
def
get_data_from_possess_item
(
self
):
query
=
"select code_name from transaction where sell_date='0'"
result
=
self
.
engine_simul
.
execute
(
query
)
.
fetchall
()
return
result
[
0
][
0
]
# daily_buy_list를 통해 특정 날짜에 해당하는 주가정보를 가져오는 함수
def
get_current_price_by_date
(
self
,
code_name
,
date
):
query
=
f
"select d1_diff_rate, close, open, high, low, volume, clo5, clo10, clo20, clo60, clo120 from `{date}` "
\
f
"where code_name = '{code_name}' group by code"
result
=
self
.
engine_daily_buy_list
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
==
1
:
return
result
else
:
return
False
# 현재의 주가를 거래이력(transaction)에 있는 보유 종목에 반영
def
db_to_transaction_update
(
self
,
code_name
,
d1_diff_rate
,
close
,
open
,
high
,
low
,
volume
,
clo5
,
clo10
,
clo20
,
clo60
,
clo120
,
option
=
'ALL'
):
# 모의투자 / 실전투자의 경우 현재가를 종가로 업데이트
if
self
.
op
==
'real'
:
present_price
=
close
# 시뮬레이터의 경우 현재가를 시가로 업데이트
else
:
present_price
=
open
# option==ALL이면 모든 데이터를 업데이트
if
option
==
"ALL"
:
query
=
f
"update transaction "
\
f
"set "
\
f
"d1_diff_rate = {d1_diff_rate}, "
\
f
"close = {close}, open = {open}, high = {high}, low = {low}, volume = {volume}, "
\
f
"present_price = {present_price}, "
\
f
"clo5 = {clo5}, clo10 = {clo10}, clo20 = {clo20}, clo60 = {clo60}, clo120 = {clo120} "
\
f
"where code_name = '{code_name}' and sell_date = {0}"
# option==open이면 open,present_price값만 업데이트
else
:
query
=
f
"update transaction "
\
f
"set "
\
f
"open = {open}, present_price = {present_price} "
\
f
"where code_name = '{code_name}' and sell_date = {0}"
self
.
engine_simul
.
execute
(
query
)
# 분별 데이터를 가져오는 함수
def
get_min_data_for_simul
(
self
,
simul_start_date
):
simul_start_date_min
=
simul_start_date
+
self
.
start_min
# 장 시작시간 = 9시
simul_end_date_min
=
simul_start_date
+
"1530"
# 장 마감시간 = 3시 30분
query
=
f
"select date from `gs글로벌` "
\
f
"where date >= '{simul_start_date_min}' and date <='{simul_end_date_min}' and open != 0 group by date"
self
.
min_data_rows
=
self
.
engine_craw
.
execute
(
query
)
.
fetchall
()
# 거래이력(transaction)의 시세(close) 데이터를 분 별로 업데이트
def
update_transaction_by_min
(
self
,
min
):
possess_item
=
self
.
get_data_from_possess_item
()
for
i
in
range
(
len
(
possess_item
)):
code_name
=
possess_item
[
i
][
0
]
current_close_price
=
self
.
get_current_close_price_by_min
(
code_name
,
min
)
if
current_close_price
:
self
.
db_to_transaction_update_present_price_by_min
(
code_name
,
current_close_price
)
else
:
continue
# 분별 현재 종가(close)를 가져오는 함수
# 분별 데이터에서 종가는 현재가를 의미하므로 1분마다 시세를 가져오는 함수
def
get_current_close_price_by_min
(
self
,
code_name
,
min
):
query
=
f
"select close from '{code_name}' "
\
f
"where date='{min}' and open!=0 and volume!=0 order by sum_volume desc limit 1"
result
=
self
.
engine_craw
.
execute
(
query
)
.
fethcall
()
if
len
(
result
)
==
1
:
return
result
[
0
][
0
]
else
:
return
False
# 보유한 종목에 현재가를 실시간으로 업데이트하는 함수
def
db_to_transaction_update_present_price_by_min
(
self
,
code_name
,
current_close_price
):
query
=
f
"update transaction set present_price={current_close_price} "
\
f
"where code_name={code_name} and sell_date='{0}'"
self
.
engine_simul
.
execute
(
query
)
# 잔고 테이블의 주가 이외의 기타 정보를 업데이트
def
update_transaction_etc
(
self
):
# valuation_price : 평가금액
# 평가금액 = (보유주 현재가 * 보유주 수량) - (총 구매금액 * 수수료) - (보유주 현재가 * 보유주 수량 * (수수료 + 세금))
query
=
f
"update transaction "
\
f
"set "
\
f
"valuation_price = "
\
f
"round((present_price * holding_amount) - item_total_purchase * {self.fees_rate} - "
\
f
"present_price*holding_amount*{self.fees_rate + self.tax_rate}) "
\
f
"where sell_date = '{0}'"
self
.
engine_simul
.
execute
(
query
)
# rate : 현재 실시간 수익률
# valuation_profit : 수익 금액
# 수익 금액 = 평가금액 - 총 구매금액
# 수익률 = 수익금액 / 구매금액 * 100
query
=
"update account_balance "
\
"set "
\
"rate= round((valuation_price - item_total_purchase)/item_total_purchase*100,2), "
\
"valuation_profit = valuation_price - item_total_purchase "
\
"where sell_date = '0';"
self
.
engine_simul
.
execute
(
query
)
# 매도 함수
def
auto_trade_sell_stock
(
self
,
date
,
i
):
# 매도할 리스트를 저장
sell_list
=
self
.
get_sell_list
(
i
)
for
j
in
range
(
len
(
sell_list
)):
sell_code
=
sell_list
[
j
][
0
]
sell_rate
=
sell_list
[
j
][
1
]
present_price
=
sell_list
[
j
][
2
]
valuation_profit
=
sell_list
[
j
][
3
]
if
sell_rate
<
0
:
print
(
"손절 매도!"
)
print
(
"========================================="
)
print
(
"종목 코드 : "
,
sell_code
)
print
(
"수익 : "
,
valuation_profit
)
print
(
"수익률 : "
,
sell_rate
)
print
(
"========================================="
)
else
:
print
(
"익절 매도!"
)
print
(
"========================================="
)
print
(
"종목 코드 : "
,
sell_code
)
print
(
"수익 : "
,
valuation_profit
)
print
(
"수익률 : "
,
sell_rate
)
print
(
"========================================="
)
# 매도 결과를 데이터베이스에 반영
self
.
send_sell_order
(
date
,
present_price
,
sell_rate
,
sell_code
)
# 매도한 결과를 transaction에 반영하는 함수
def
send_sell_order
(
self
,
min
,
sell_price
,
sell_rate
,
code
):
query
=
f
"update transaction "
\
f
"set "
\
f
"sell_date='{min}', sell_price='{sell_price}', sell_rate='{sell_rate}' "
\
f
"where code='{code}' and sell_date='{0}' order by buy_date desc limit 1"
self
.
engine_simul
.
execute
(
query
)
# 매도 후 정산
self
.
update_balance
()
# 매도함수를 이용하여 매도할 종목을 가져오는 함수
def
get_sell_list
(
self
,
i
):
sell_list
=
None
# (5,20) 데드크로스
# 또는 손절 기준 수익률 이하로 떨어졌을 경우 매도
if
self
.
sell_algorithm
==
1
:
query
=
f
"select code,rate, present_price,valuation_price from transaction "
\
f
"where sell_date='0' and (clo5<clo20 or rate<='{self.losscut_point}') group by code"
sell_list
=
self
.
engine_simul
.
execute
(
query
)
.
fetchall
()
# (20,60) 데드크로스
elif
self
.
sell_algorithm
==
2
:
query
=
f
"select code,rate, present_price,valuation_price from transaction "
\
f
"where sell_date='0' and (clo20<clo60 or rate<='{self.losscut_point}') group by code"
sell_list
=
self
.
engine_simul
.
execute
(
query
)
.
fetchall
()
# RSI
#elif self.sell_algorithm==3:
# RMI
#elif self.sell_algorithm==4:
else
:
logger
.
error
(
"Invalid sell algorithm setting..."
)
return
sell_list
# 남은 금액을 확인하는 함수
# 남은 금액이 최소 보유금 + 투자단위금액 이상이면 True, 아니면 False 반환
def
check_balance
(
self
):
if
int
(
self
.
d2_deposit
)
>=
int
(
self
.
limit_money
)
+
int
(
self
.
invest_unit
):
return
True
else
:
return
False
# 매수 함수
def
auto_trade_buy_stock
(
self
,
min
,
date_rows_today
,
date_rows_yesterday
):
# self.df_realtime_daily_buy_list에 있는 모든 종목을 매수
for
i
in
range
(
self
.
len_df_realtime_daily_buy_list
):
if
self
.
check_balance
():
code
=
self
.
df_realtime_daily_buy_list
.
loc
[
i
,
'code'
]
.
rjust
(
6
,
"0"
)
code_name
=
self
.
df_realtime_daily_buy_list
.
loc
[
i
,
'code_name'
]
# 분별 시뮬레이팅인 경우
if
self
.
use_min
:
# 분별 종목데이터가 존재하지 않는 항목이라면 매수하지 않음
if
not
self
.
is_min_craw_table_exist
(
code_name
):
continue
# 일별 시뮬레이팅인 경우
else
:
# 일별 종목데이터가 존재하지 않는 항목이라면 매수하지 않음
if
not
self
.
is_daily_craw_table_exist
(
code_name
):
continue
# 일별 시뮬레이팅인 경우
if
not
self
.
use_min
:
price
=
self
.
get_current_open_price_by_date
(
code
,
date_rows_today
)
else
:
price
=
self
.
get_current_close_price_by_min
(
code_name
,
min
)
# 전날 종가를 저장
yes_close
=
self
.
get_yes_close_price_by_date
(
code
,
date_rows_yesterday
)
# 종목명 또는 시작가가 존재하지 않는다면 매수하지 않음
if
code_name
==
False
or
price
==
0
or
price
==
False
:
continue
# 분별 시뮬레이팅인 경우
if
self
.
use_min
and
not
self
.
use_nine
and
self
.
trade_check_num
:
open
=
self
.
get_current_open_price_by_date
(
code
,
date_rows_today
)
# 시가
sum_volume
=
self
.
get_current_volume_by_min
(
code_name
,
min
)
# 당일 누적 거래량
if
open
and
sum_volume
:
# 실시간 매수조건에 부합하지 않는 경우 매수하지 않음
if
not
self
.
check_trade
(
self
.
df_realtime_daily_buy_list
.
loc
[
i
],
open
,
price
,
sum_volume
):
continue
self
.
send_buy_order
(
min
,
code
,
code_name
,
price
,
yes_close
,
i
)
else
:
break
# min_craw 데이터베이스에 code_name 테이블이 존재하는지 확인하는 함수
def
is_min_craw_table_exist
(
self
,
code_name
):
query
=
f
"select 1 from information_schema.tables where table_schema = 'min_craw' and table_name = '{code_name}'"
result
=
self
.
engine_craw
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
==
1
:
return
True
else
:
return
False
# daily_craw 데이터베이스에 code_name 테이블이 존재하는지 확인하는 함수
def
is_daily_craw_table_exist
(
self
,
code_name
):
query
=
f
"select 1 from information_schema.tables where table_schema = 'daily_craw' and table_name = '{code_name}'"
result
=
self
.
engine_daily_craw
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
==
1
:
return
True
else
:
return
False
# 특정 날짜의 테이블에서 특정 종목의 시가를 가져오는 함수
def
get_current_open_price_by_date
(
self
,
code
,
date
):
query
=
f
"select open from `{date}` where code = '{code}' group by code"
open
=
self
.
engine_daily_buy_list
.
execute
(
query
)
.
fetchall
()
if
len
(
open
)
==
1
:
return
open
[
0
][
0
]
else
:
return
False
# 전날 종가(close)를 가져오는 함수
def
get_yes_close_price_by_date
(
self
,
code
,
date
):
query
=
f
"select close from `{date}` where code = '{code}' group by code"
result
=
self
.
engine_daily_buy_list
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
==
1
:
return
result
[
0
][
0
]
else
:
return
False
# 분별 현재 누적 거래량을 가져오는 함수
def
get_current_volume_by_min
(
self
,
code_name
,
min
):
query
=
f
"select sum_volume from `{code_name}` "
\
f
"where date = '{min}' and open != 0 and volume !=0 order by sum_volume desc limit 1"
result
=
self
.
engine_craw
.
execute
(
query
)
.
fetchall
()
if
len
(
result
)
==
1
:
return
result
[
0
][
0
]
else
:
return
False
# 실시간 주가를 분석하여 매수 여부를 결정하는 함수
# param : df_row - 매수 종목 리스트
# open_price - 시가
# current_price - 현재가
# current_sum_volume - 현재 누적 거래량
# return : True인 경우 매수, False인 경우 매수하지 않음
def
check_trade
(
self
,
df_row
,
open_price
,
current_price
,
current_sum_volume
):
code_name
=
df_row
[
'code_name'
]
yes_vol20
=
df_row
[
'vol20'
]
yes_close
=
df_row
[
'close'
]
yes_high
=
df_row
[
'high'
]
yes_low
=
df_row
[
'low'
]
yes_volume
=
df_row
[
'volume'
]
# 실시간 거래 대금 체크 알고리즘
# 어제 종가 보다 현재가가 증가했고, 거래 대금이 어제 거래대금에 비해서 x배 올라갔을 때 매수
if
self
.
trade_check_num
==
1
:
yes_total_tr_price
=
yes_close
*
yes_volume
# 전날 거래 대금
current_total_tr_price
=
current_price
*
current_sum_volume
# 현재 거래 대금
if
current_price
>
yes_close
and
current_total_tr_price
>
yes_total_tr_price
*
self
.
volume_up
:
return
True
else
:
return
False
# 현재가가 매수 가격 최저 범위와 매수 가격 최고 범위 안에 들어와 있다면 매수
elif
self
.
trade_check_num
==
2
:
min_buy_limit
=
int
(
yes_close
)
*
self
.
invest_min_limit_rate
# 매수가격 최저 범위
max_buy_limit
=
int
(
yes_close
)
*
self
.
invest_limit_rate
# 매수가격 최고 범위
if
min_buy_limit
<
current_price
<
max_buy_limit
:
return
True
else
:
return
False
# 래리 윌리엄스 변동성 돌파 알고리즘(매수)
elif
self
.
trade_check_num
==
3
:
# 변동폭(range): 전일 고가(yes_high)에서 전일 저가(yes_low)를 뺀 가격
# 매수시점 : 현재가 > 시작가 + (변동폭 * k) [k는 0~1 사이 수]
range
=
yes_high
-
yes_low
if
open_price
+
range
*
self
.
rarry_k
<
current_price
:
return
True
else
:
return
False
# transaction_history 테이블의 Dataframe 생성
def
df_transaction_history
(
self
):
df_temp
=
{
'id'
:[]}
self
.
df_th
=
DataFrame
(
df_temp
,
columns
=
[
'id'
,
'order_num'
,
'code'
,
'code_name'
,
'rate'
,
'purchase_rate'
,
'purchase_price'
,
'present_price'
,
'valuation_price'
,
'valuation_profit'
,
'holding_amount'
,
'buy_date'
,
'total_purchase_price'
,
'contract_check'
,
'per_invest'
,
'sell_date'
,
'sell_price'
,
'sell_rate'
])
# daily_info 데이터베이스에서 특정 날짜에서 특정 코드에 해당하는 정보만 가져오는 함수수
def
get_daily_info_by_code
(
self
,
code
,
date
):
query
=
"select * from {} where code='{}' group by code"
daily_info
=
self
.
engine_daily
.
execute
(
query
.
format
(
date
,
code
))
.
fetchall
()
df_daily_info
=
DataFrame
(
daily_info
,
columns
=
[
'index'
,
'index2'
,
'date'
,
'check_item'
,
'code'
,
'code_name'
,
'dff_rate'
,
'close'
,
'open'
,
'high'
,
'low'
,
'volume'
,
'avg5'
,
'avg10'
,
'avg20'
,
'avg60'
,
'avg120'
,
'prev_avg5'
,
'prev_avg10'
,
'prev_avg20'
,
'prev_avg60'
,
'prev_avg120'
,
'avg5_diff_rate'
,
'avg10_diff_rate'
,
'avg20_diff_rate'
,
'avg60_diff_rate'
,
'avg120_diff_rate'
,
'vol5'
,
'vol10'
,
'vol20'
,
'vol60'
,
'vol120'
])
return
df_daily_info
\ No newline at end of file
else
:
logger
.
error
(
"Invalid trade_check_num"
)
# 데이터베이스에 매수 내역 업데이트
def
send_buy_order
(
self
,
date
,
code
,
code_name
,
price
,
yes_close
,
j
):
# 가격이 invest_unit보다 작은 경우 매수
if
price
<
self
.
invest_unit
:
# 매수하는 경우 account_balance에 해당 내역을 추가
self
.
db_to_transaction
(
date
,
self
.
df_realtime_daily_buy_list
,
j
,
code
,
code_name
,
price
,
yes_close
)
# 매수를 성공적으로 했으면 realtime_daily_buy_list 테이블의 check_item 에 매수 시간을 설정
self
.
update_realtime_daily_buy_list
(
code
,
date
)
# 정산
self
.
update_balance
()
# transaction 테이블에 추가하는 함수
def
db_to_transaction
(
self
,
min
,
df
,
index
,
code
,
code_name
,
purchase_price
,
yesterday_close
):
self
.
df_transaction
.
loc
[
0
,
'code'
]
=
code
self
.
df_transaction
.
loc
[
0
,
'code_name'
]
=
code_name
self
.
df_transaction
.
loc
[
0
,
'rate'
]
=
float
(
-
0.33
)
if
yesterday_close
:
self
.
df_transaction
.
loc
[
0
,
'purchase_rate'
]
=
round
(
(
float
(
purchase_price
)
-
float
(
yesterday_close
))
/
float
(
yesterday_close
)
*
100
,
2
)
self
.
df_transaction
.
loc
[
0
,
'purchase_price'
]
=
purchase_price
self
.
df_transaction
.
loc
[
0
,
'present_price'
]
=
purchase_price
self
.
df_transaction
.
loc
[
0
,
'holding_amount'
]
=
int
(
self
.
invest_unit
/
purchase_price
)
self
.
df_transaction
.
loc
[
0
,
'buy_date'
]
=
min
self
.
df_transaction
.
loc
[
0
,
'item_total_purchase'
]
=
self
.
df_transaction
.
loc
[
0
,
'purchase_price'
]
*
\
self
.
df_transaction
.
loc
[
0
,
'holding_amount'
]
self
.
today_invest_price
=
self
.
today_invest_price
+
self
.
df_transaction
.
loc
[
0
,
'item_total_purchase'
]
self
.
df_transaction
.
loc
[
0
,
'chegyul_check'
]
=
0
self
.
df_transaction
.
loc
[
0
,
'id'
]
=
0
self
.
df_transaction
.
loc
[
0
,
'invest_unit'
]
=
self
.
invest_unit
self
.
df_transaction
.
loc
[
0
,
'yes_close'
]
=
yesterday_close
self
.
df_transaction
.
loc
[
0
,
'close'
]
=
df
.
loc
[
index
,
'close'
]
self
.
df_transaction
.
loc
[
0
,
'open'
]
=
df
.
loc
[
index
,
'open'
]
self
.
df_transaction
.
loc
[
0
,
'high'
]
=
df
.
loc
[
index
,
'high'
]
self
.
df_transaction
.
loc
[
0
,
'low'
]
=
df
.
loc
[
index
,
'low'
]
self
.
df_transaction
.
loc
[
0
,
'volume'
]
=
df
.
loc
[
index
,
'volume'
]
self
.
df_transaction
.
loc
[
0
,
'd1_diff_rate'
]
=
float
(
df
.
loc
[
index
,
'd1_diff_rate'
])
self
.
df_transaction
.
loc
[
0
,
'clo5'
]
=
df
.
loc
[
index
,
'clo5'
]
self
.
df_transaction
.
loc
[
0
,
'clo10'
]
=
df
.
loc
[
index
,
'clo10'
]
self
.
df_transaction
.
loc
[
0
,
'clo20'
]
=
df
.
loc
[
index
,
'clo20'
]
self
.
df_transaction
.
loc
[
0
,
'clo60'
]
=
df
.
loc
[
index
,
'clo40'
]
self
.
df_transaction
.
loc
[
0
,
'clo120'
]
=
df
.
loc
[
index
,
'clo60'
]
if
df
.
loc
[
index
,
'clo5_diff_rate'
]
is
not
None
:
self
.
df_transaction
.
loc
[
0
,
'clo5_diff_rate'
]
=
float
(
df
.
loc
[
index
,
'clo5_diff_rate'
])
if
df
.
loc
[
index
,
'clo10_diff_rate'
]
is
not
None
:
self
.
df_transaction
.
loc
[
0
,
'clo10_diff_rate'
]
=
float
(
df
.
loc
[
index
,
'clo10_diff_rate'
])
if
df
.
loc
[
index
,
'clo20_diff_rate'
]
is
not
None
:
self
.
df_transaction
.
loc
[
0
,
'clo20_diff_rate'
]
=
float
(
df
.
loc
[
index
,
'clo20_diff_rate'
])
if
df
.
loc
[
index
,
'clo60_diff_rate'
]
is
not
None
:
self
.
df_transaction
.
loc
[
0
,
'clo40_diff_rate'
]
=
float
(
df
.
loc
[
index
,
'clo40_diff_rate'
])
if
df
.
loc
[
index
,
'clo120_diff_rate'
]
is
not
None
:
self
.
df_transaction
.
loc
[
0
,
'clo60_diff_rate'
]
=
float
(
df
.
loc
[
index
,
'clo60_diff_rate'
])
self
.
df_transaction
.
loc
[
0
,
'valuation_profit'
]
=
int
(
0
)
self
.
df_transaction
=
self
.
df_transaction
.
fillna
(
0
)
# 거래이력 테이블이 이미 존재한다면 데이터 추가
if
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
):
self
.
df_transaction
.
to_sql
(
'transaction'
,
self
.
engine_simul
,
if_exists
=
'append'
)
# 테이블이 존재하지 않는다면 생성
else
:
self
.
df_transaction
.
to_sql
(
'transaction'
,
self
.
engine_simul
,
if_exists
=
'replace'
)
# 매수할 리스트(realtime_daily_buy_list)에서 특정 종목을 매수한 경우 check_item칼럼에 매수한 날짜를 저장하는 함수
def
update_realtime_daily_buy_list
(
self
,
code
,
min
):
query
=
f
"update realtime_daily_buy_list set check_item = '{min}' where code = '{code}'"
self
.
engine_simul
.
execute
(
query
)
# account_balance(잔고) 테이블을 생성 및 데이터를 추가하는 함수
def
db_to_account_balance
(
self
,
date_rows_today
):
self
.
update_balance
()
# 거래이력(transaction)테이블이 존재하지 않는다면 return
if
not
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
):
return
columns
=
[
'date'
,
'today_earning_rate'
,
'sum_valuation_profit'
,
'total_profit'
,
'today_profit'
,
'today_profitcut_count'
,
'today_losscut_count'
,
'today_profitcut'
,
'today_losscut'
,
'd2_deposit'
,
'total_possess_count'
,
'today_buy_count'
,
'total_invest'
,
'sum_item_total_purchase'
,
'total_evaluation'
,
'today_rate'
,
'today_invest_price'
,
'today_sell_price'
,
'volume_limit'
,
'sell_point'
,
'invest_unit'
,
'limit_money'
,
'total_profitcut'
,
'total_losscut'
,
'total_profitcut_count'
,
'total_losscut_count'
]
self
.
account_balance
.
loc
[
0
,
'date'
]
=
date_rows_today
# 구매일
self
.
account_balance
.
loc
[
0
,
'sum_valuation_profit'
]
=
self
.
sum_valuation_profit
# 총평가금액
self
.
account_balance
.
loc
[
0
,
'total_profit'
]
=
self
.
total_valuation_profit
# 총수익
self
.
account_balance
.
loc
[
0
,
'today_profit'
]
=
self
.
get_today_profit
(
date_rows_today
)
# 당일수익
self
.
account_balance
.
loc
[
0
,
'today_profitcut_count'
]
=
self
.
get_today_profitcut_count
(
date_rows_today
)
# 당일 익절종목 수
self
.
account_balance
.
loc
[
0
,
'today_losscut_count'
]
=
self
.
get_today_losscut_count
(
date_rows_today
)
# 당일 손절종목 수
self
.
account_balance
.
loc
[
0
,
'today_profitcut'
]
=
self
.
get_sum_today_profitcut
(
date_rows_today
)
# 당일 익절금액
self
.
account_balance
.
loc
[
0
,
'today_losscut'
]
=
self
.
get_sum_today_losscut
(
date_rows_today
)
# 당일 손절금액
self
.
account_balance
.
loc
[
0
,
'd2_deposit'
]
=
self
.
d2_deposit
# 예수금
self
.
account_balance
.
loc
[
0
,
'total_possess_count'
]
=
self
.
get_total_possess_count
()
# 보유종목 수
self
.
account_balance
.
loc
[
0
,
'today_buy_count'
]
=
0
# 오늘 구매한 종목수
self
.
account_balance
.
loc
[
0
,
'total_invest'
]
=
self
.
total_invest_price
# 총 투자금액
self
.
account_balance
.
loc
[
0
,
'sum_item_total_purchase'
]
=
self
.
get_sum_item_total_purchase
()
# 총매입금액
self
.
account_balance
.
loc
[
0
,
'total_evaluation'
]
=
self
.
get_sum_valuation_price
()
# 총평가금액
try
:
self
.
account_balance
.
loc
[
0
,
'today_rate'
]
=
round
(
(
float
(
self
.
account_balance
.
loc
[
0
,
'total_evaluation'
])
-
float
(
self
.
account_balance
.
loc
[
0
,
'sum_item_total_purchase'
]))
/
float
(
self
.
account_balance
.
loc
[
0
,
'sum_item_total_purchase'
])
*
(
100
-
0.33
),
2
)
# 당일 기준 수익률
except
ZeroDivisionError
:
pass
self
.
account_balance
.
loc
[
0
,
'today_invest_price'
]
=
float
(
self
.
today_invest_price
)
# 당일 투자금액
self
.
account_balance
.
loc
[
0
,
'today_sell_price'
]
=
self
.
get_sum_today_sell_price
(
date_rows_today
)
self
.
account_balance
.
loc
[
0
,
'volume_limit'
]
=
self
.
volume_limit
self
.
account_balance
.
loc
[
0
,
'sell_point'
]
=
self
.
sell_point
self
.
account_balance
.
loc
[
0
,
'invest_unit'
]
=
self
.
invest_unit
self
.
account_balance
.
loc
[
0
,
'limit_money'
]
=
self
.
limit_money
self
.
account_balance
.
loc
[
0
,
'total_profitcut'
]
=
self
.
get_sum_total_profitcut
()
self
.
account_balance
.
loc
[
0
,
'total_losscut'
]
=
self
.
get_sum_total_losscut
()
self
.
account_balance
.
loc
[
0
,
'total_profitcut_count'
]
=
self
.
get_sum_total_profitcut_count
()
self
.
account_balance
.
loc
[
0
,
'total_losscut_count'
]
=
self
.
get_sum_total_losscut_count
()
# 데이터베이스에 테이블 추가
self
.
account_balance
.
to_sql
(
'account_balance'
,
self
.
engine_simul
,
if_exists
=
'append'
)
# 매도종목에 대한 당일 수익
query
=
f
"update account_balance "
\
f
"set "
\
f
"today_earning_rate =round(today_profit / total_invest * 100, 2) WHERE date='{date_rows_today}'"
self
.
engine_simul
.
execute
(
query
)
# 당일 수익을 계산하는 함수
def
get_today_profit
(
self
,
date
):
query
=
"SELECT sum(valuation_profit) from transaction where sell_date like '
%
s'"
result
=
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
date
+
"
%%
"
))
.
fetchall
()
return
result
[
0
][
0
]
# 당일 익절 종목 수를 반환하는 함수
def
get_today_profitcut_count
(
self
,
date
):
query
=
"SELECT count(code) from transaction where sell_date like '
%
s' and sell_rate>='
%
s'"
return
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
date
+
"
%%
"
,
0
))
.
fetchall
()[
0
][
0
]
# 당일 손절 종목 수를 반환하는 함수
def
get_today_losscut_count
(
self
,
date
):
query
=
"SELECT count(code) from transaction where sell_date like '
%
s' and sell_rate<'
%
s'"
return
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
date
+
"
%%
"
,
0
))
.
fetchall
()[
0
][
0
]
# 당일 익절 금액을 반환하는 함수
def
get_sum_today_profitcut
(
self
,
date
):
query
=
"SELECT sum(valuation_profit) from transaction where sell_date like '
%
s' and valuation_profit >= '
%
s' "
return
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
date
+
"
%%
"
,
0
))
.
fetchall
()[
0
][
0
]
# 당일 손절 금액을 반환하는 함수
def
get_sum_today_losscut
(
self
,
date
):
query
=
"SELECT sum(valuation_profit) from transaction where sell_date like '
%
s' and valuation_profit < '
%
s' "
return
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
date
+
"
%%
"
,
0
))
.
fetchall
()[
0
][
0
]
# 총 보유한 종목 수를 반환하는 함수
def
get_total_possess_count
(
self
):
query
=
"select count(code) from transaction where sell_date = '
%
s'"
return
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fetchall
()[
0
][
0
]
# 총 매입금액을 계산하는 함수
def
get_sum_item_total_purchase
(
self
):
query
=
"SELECT sum(item_total_purchase) from transaction where sell_date = '
%
s'"
result
=
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fetchall
()[
0
][
0
]
if
result
is
not
None
:
return
result
else
:
return
0
# 총평가금액을 계산하는 함수
def
get_sum_valuation_price
(
self
):
query
=
"SELECT sum(valuation_price) from transaction where sell_date = '
%
s'"
result
=
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fetchall
()[
0
][
0
]
if
result
is
not
None
:
return
result
else
:
return
0
# 당일 매도금액을 계산하는 함수
def
get_sum_today_sell_price
(
self
,
date
):
query
=
"SELECT sum(valuation_price) from transaction where sell_date like '
%
s'"
return
self
.
engine_simul
.
execute
(
query
%
(
"
%%
"
+
date
+
"
%%
"
))
.
fetchall
()[
0
][
0
]
# 총 익절금액을 계산하는 함수
def
get_sum_total_profitcut
(
self
):
query
=
"SELECT sum(valuation_profit) from transaction where sell_date != 0 and valuation_profit >= '
%
s' "
return
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fetchall
()[
0
][
0
]
# 총 손절금액을 계산하는 함수
def
get_sum_total_losscut
(
self
):
query
=
"SELECT sum(valuation_profit) from transaction where sell_date != 0 and valuation_profit < '
%
s' "
return
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fetchall
()[
0
][
0
]
# 총 익절종목수를 반환하는 함수
def
get_sum_total_profitcut_count
(
self
):
query
=
"select count(code) from transaction where sell_date != 0 and valuation_profit >= '
%
s'"
return
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fetchall
()[
0
][
0
]
# 총 손절종목수를 반환하는 함수
def
get_sum_total_losscut_count
(
self
):
query
=
"select count(code) from transaction where sell_date != 0 and valuation_profit < '
%
s' "
return
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fetchall
()[
0
][
0
]
# 보유종목의 종목명을 반환하는 함수
def
get_data_from_possessed_item
(
self
):
query
=
"SELECT code_name from transaction where sell_date = '
%
s'"
return
self
.
engine_simul
.
execute
(
query
%
(
0
))
.
fetchall
()
# 날짜별 시뮬레이팅 함수
def
simul_by_date
(
self
,
date_rows_today
,
date_rows_yesterday
,
i
):
# 시뮬레이팅 전 변수 초기화
self
.
set_daily_variable
()
# daily_buy_list에 시뮬레이팅 할 날짜에 해당하는 테이블과 전 날 테이블이 존재하는지 확인
if
self
.
is_date_exist
(
date_rows_today
)
and
self
.
is_date_exist
(
date_rows_yesterday
):
# 당일 매수 할 종목 저장
self
.
db_to_realtime_daily_buy_list
(
date_rows_today
,
date_rows_yesterday
,
i
)
# 매수/매도
self
.
trading_by_date
(
date_rows_today
,
date_rows_yesterday
,
i
)
if
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
)
and
len
(
self
.
get_data_from_possessed_item
())
!=
0
:
# 보유 중인 종목들의 주가를 일별로 업데이트
self
.
update_transaction_by_date
(
date_rows_today
,
option
=
"ALL"
)
# 정산
self
.
db_to_account_balance
(
date_rows_today
)
else
:
print
(
"날짜 테이블이 존재하지 않습니다."
)
# 날짜별 거래 함수
def
trading_by_date
(
self
,
date_rows_today
,
date_rows_yesterday
,
i
):
self
.
show_info
(
date_rows_today
)
# 보유주 정보 업데이트
if
self
.
is_simul_table_exist
(
self
.
db_name
,
"transaction"
)
and
len
(
self
.
get_data_from_possessed_item
())
!=
0
:
self
.
update_transaction_by_date
(
date_rows_today
,
option
=
"OPEN"
)
self
.
update_transaction_etc
()
# 매도
self
.
auto_trade_sell_stock
(
date_rows_today
,
i
)
# 매수할 잔액이 존재한다면 매수
if
self
.
check_balance
():
self
.
auto_trade_buy_stock
(
str
(
date_rows_today
)
+
"0900"
,
date_rows_today
,
date_rows_yesterday
)
# 매도 리스트가 존재하지 않는다면 매수만 진행
else
:
if
self
.
check_balance
():
self
.
auto_trade_buy_stock
(
str
(
date_rows_today
)
+
"0900"
,
date_rows_today
,
date_rows_yesterday
)
\ No newline at end of file
...
...
proj/library/c
onfig
.py
→
proj/library/c
f
.py
View file @
f1ae6cc
File moved
proj/library/collector_api.py
View file @
f1ae6cc
from
Open_Api
import
*
from
collections
import
OrderedDict
from
pandas
import
DataFrame
import
time
from
Daily_Info
import
*
from
Stock_Info
import
*
...
...
@@ -23,27 +24,40 @@ class Collector_Api():
"today_buy_list,stock_info,min_info,daily_info from setting_data"
result
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
today
=
self
.
open_api
.
today
# 오늘 날짜에 종목리스트가 업데이트 되지 않았다면 업데이트를 실행
if
result
[
0
][
0
]
!=
self
.
open_api
.
today
:
if
result
[
0
][
0
]
!=
today
:
self
.
open_api
.
get_balance
()
self
.
get_code_list
()
# 계좌정보 업데이트
if
result
[
0
][
1
]
!=
self
.
open_api
.
today
or
result
[
0
][
2
]
!=
self
.
open_api
.
today
:
if
result
[
0
][
1
]
!=
today
or
result
[
0
][
2
]
!=
today
:
self
.
check_balance
()
self
.
open_api
.
set_per_invest
()
# 현재 보유종목 테이블 업데이트
if
result
[
0
][
2
]
!=
self
.
open_api
.
today
:
if
result
[
0
][
2
]
!=
today
:
self
.
open_api
.
get_posses_item
()
self
.
open_api
.
setting_data_posses_stock
()
if
result
[
0
][
3
]
!=
self
.
open_api
.
today
:
# 수익률 테이블 업데이트
if
result
[
0
][
3
]
!=
today
:
self
.
update_today_profit_list
()
if
result
[
0
][
7
]
!=
self
.
open_api
.
today
:
# stock_info 테이블 업데이트
if
result
[
0
][
7
]
!=
today
:
self
.
check_stock_info
()
if
result
[
0
][
9
]
!=
today
:
self
.
check_daily_info
()
if
result
[
0
][
4
]
!=
today
:
self
.
open_api
.
check_contract
()
self
.
open_api
.
final_check_contract
()
if
result
[
0
][
6
]
!=
today
:
self
.
realtime_daily_info_check
()
# 코스피, 코스닥 리스트 확인 및 데이터베이스 업데이트
...
...
@@ -256,7 +270,7 @@ class Collector_Api():
query
=
"UPDATE setting_data SET today_profit='
%
s' limit 1"
self
.
engine_bot
.
execute
(
query
%
(
self
.
open_api
.
today
))
def
check_
daily
_info
(
self
):
def
check_
stock
_info
(
self
):
self
.
update_daily_info
()
query
=
"update setting_data set daily_info='
%
s'"
self
.
engine_bot
.
execute
(
query
%
(
self
.
open_api
.
today
))
...
...
@@ -273,12 +287,102 @@ class Collector_Api():
code
=
code_list
[
i
][
0
]
code_name
=
code_list
[
i
][
1
]
check_item_sort
=
self
.
set_
minute
_info_table
(
code
,
code_name
)
check_item_sort
=
self
.
set_
stock
_info_table
(
code
,
code_name
)
self
.
open_api
.
engine_daily
.
execute
(
query
%
(
check_item_sort
,
code
))
def
set_minute_info_table
(
self
,
code
,
code_name
):
df
=
self
.
open_api
.
# stock_info 데이터베이스에 테이블 생성 및 추가
def
set_stock_info_table
(
self
,
code
,
code_name
):
df
=
self
.
open_api
.
get_date_data
(
code
,
code_name
,
self
.
open_api
.
today
)
df
=
DataFrame
(
df
,
columns
=
[
'date'
,
'check_item'
,
'code'
,
'code_name'
,
'd1_diff_rate'
,
'close'
,
'open'
,
'high'
,
'low'
,
'volume'
,
'clo5'
,
'clo10'
,
'clo20'
,
'clo60'
,
'clo120'
,
'pre_clo5'
,
'pre_clo10'
,
'pre_clo20'
,
'pre_clo60'
,
'pre_clo120'
,
'vol5'
,
'vol10'
,
'vol20'
,
'vol60'
,
'vol120'
])
df
=
df
.
sort_values
(
by
=
[
'date'
],
ascending
=
True
)
df
[
'code'
]
=
code
df
[
'code_name'
]
=
code_name
df
[
'd1_diff_rate'
]
=
float
((
df
[
'close'
]
-
df
[
'close'
]
.
shift
(
1
))
/
df
[
'close'
]
.
shift
(
1
)
*
100
)
df
[
'clo5'
]
=
df
[
'close'
]
.
rolling
(
window
=
5
)
.
mean
()
df
[
'clo10'
]
=
df
[
'close'
]
.
rolling
(
window
=
10
)
.
mean
()
df
[
'clo20'
]
=
df
[
'close'
]
.
rolling
(
window
=
20
)
.
mean
()
df
[
'clo60'
]
=
df
[
'close'
]
.
rolling
(
window
=
60
)
.
mean
()
df
[
'clo120'
]
=
df
[
'close'
]
.
rolling
(
window
=
120
)
.
mean
()
df
[
'pre_col5'
]
=
df
[
'clo5'
]
.
shift
(
1
)
df
[
'pre_col10'
]
=
df
[
'clo10'
]
.
shift
(
1
)
df
[
'pre_col20'
]
=
df
[
'clo20'
]
.
shift
(
1
)
df
[
'pre_col60'
]
=
df
[
'clo60'
]
.
shift
(
1
)
df
[
'pre_col120'
]
=
df
[
'clo120'
]
.
shift
(
1
)
df
[
'vlo5'
]
=
df
[
'volume'
]
.
rolling
(
window
=
5
)
.
mean
()
df
[
'vlo10'
]
=
df
[
'volume'
]
.
rolling
(
window
=
10
)
.
mean
()
df
[
'vlo20'
]
=
df
[
'volume'
]
.
rolling
(
window
=
20
)
.
mean
()
df
[
'vlo60'
]
=
df
[
'volume'
]
.
rolling
(
window
=
60
)
.
mean
()
df
[
'vlo120'
]
=
df
[
'volume'
]
.
rolling
(
window
=
120
)
.
mean
()
# 이미 테이블이 존재한다면 저장된 가장 최신의 날짜 이후의 데이터만 저장
if
self
.
engine_bot
.
dialect
.
has_table
(
self
.
open_api
.
engine_stock
,
code_name
):
df
=
df
[
df
.
date
>
self
.
open_api
.
get_latest_date_from_stock_info
(
code_name
)]
df
[[
'date'
,
'check_item'
,
'code'
,
'code_name'
,
'd1_diff_rate'
,
'close'
,
'open'
,
'high'
,
'low'
,
'volume'
,
'clo5'
,
'clo10'
,
'clo20'
,
'clo60'
,
'clo120'
,
'pre_clo5'
,
'pre_clo10'
,
'pre_clo20'
,
'pre_clo60'
,
'yes_clo120'
,
'vol5'
,
'vol10'
,
'vol20'
,
'vol60'
,
'vol120'
]]
=
\
df
[[
'date'
,
'check_item'
,
'code'
,
'code_name'
,
'd1_diff_rate'
,
'close'
,
'open'
,
'high'
,
'low'
,
'volume'
,
'clo5'
,
'clo10'
,
'clo20'
,
'clo60'
,
'clo120'
,
'pre_clo5'
,
'pre_clo10'
,
'pre_clo20'
,
'pre_clo60'
,
'yes_clo120'
,
'vol5'
,
'vol10'
,
'vol20'
,
'vol60'
,
'vol120'
]]
.
fillna
(
0
)
.
astype
(
int
)
df
.
to_sql
(
name
=
code_name
,
con
=
self
.
open_api
.
engine_stock
,
if_exists
=
'append'
)
check_item_sort
=
1
return
check_item_sort
def
check_daily_info
(
self
):
self
.
daily_info
.
create_daily_table
()
query
=
"update setting_data set daily_info='
%
s'"
self
.
engine_bot
.
execute
(
query
%
(
self
.
open_api
.
today
))
def
realtime_daily_info_check
(
self
):
if
self
.
open_api
.
simul_api
.
is_date_exist
(
self
.
open_api
.
today
):
self
.
open_api
.
simul_api
.
get_date_for_simul
()
self
.
open_api
.
simul_api
.
choose_to_buy_list
(
self
.
open_api
.
today
,
self
.
open_api
.
today
,
len
(
self
.
open_api
.
simul_api
.
date_rows
))
if
self
.
open_api
.
sf
.
is_date_exist
(
self
.
open_api
.
today
):
logger
.
debug
(
"daily_buy_list DB에 {} 테이블이 있습니다. jackbot DB에 realtime_daily_buy_list 테이블을 생성합니다"
.
format
(
self
.
open_api
.
today
))
self
.
open_api
.
sf
.
get_date_for_simul
()
# 첫 번째 파라미터는 여기서는 의미가 없다.
# 두 번째 파라미터에 오늘 일자를 넣는 이유는 매수를 하는 시점인 내일 기준으로 date_rows_yesterday가 오늘 이기 때문
self
.
open_api
.
sf
.
db_to_realtime_daily_buy_list
(
self
.
open_api
.
today
,
self
.
open_api
.
today
,
len
(
self
.
open_api
.
sf
.
date_rows
))
# all_item_db에서 open, clo5~120, volume 등을 오늘 일자 데이터로 업데이트 한다.
self
.
open_api
.
sf
.
update_all_db_by_date
(
self
.
open_api
.
today
)
self
.
open_api
.
rate_check
()
# realtime_daily_buy_list(매수 리스트) 테이블 세팅을 완료 했으면 아래 쿼리를 통해 setting_data의 today_buy_list에 오늘 날짜를 찍는다.
sql
=
"UPDATE setting_data SET today_buy_list='
%
s' limit 1"
self
.
engine_JB
.
execute
(
sql
%
(
self
.
open_api
.
today
))
else
:
logger
.
debug
(
"""daily_buy_list DB에 {} 테이블이 없습니다. jackbot DB에 realtime_daily_buy_list 테이블을 생성 할 수 없습니다.
realtime_daily_buy_list는 daily_buy_list DB 안에 오늘 날짜 테이블이 만들어져야 생성이 됩니다.
realtime_daily_buy_list 테이블을 생성할 수 없는 이유는 아래와 같습니다.
1. 장이 열리지 않은 날 혹은 15시 30분 ~ 23시 59분 사이에 콜렉터를 돌리지 않은 경우
2. 콜렉터를 오늘 날짜 까지 돌리지 않아 daily_buy_list의 오늘 날짜 테이블이 없는 경우
"""
.
format
(
self
.
open_api
.
today
))
app
=
QApplication
(
sys
.
argv
)
...
...
proj/library/open_api.py
View file @
f1ae6cc
...
...
@@ -329,13 +329,13 @@ class Open_Api(QAxWidget):
def
create_setting_data
(
self
):
df_data
=
{
"limit_money"
:[],
"per_invest"
:[],
"max_per_invest"
:[],
"min_per_invest"
:[],
"set_per_invest"
:[],
"code_update"
:[],
"today_finish"
:[],
"balance_to_db"
:[],
"posses_stocks"
:[],
"today_profit"
:[],
"contract_check"
:[],
"
db_to_daily_info"
:[],
"today_buy_list"
:[],
"stock_info"
:[],
"min_info
"
:[],
"daily_info"
:[]}
"contract_check"
:[],
"
final_contract_check"
:[],
"db_to_daily_info"
:[],
"today_buy_list
"
:[],
"
stock_info"
:[],
"min_info"
:[],
"
daily_info"
:[]}
df_setting_data
=
DataFrame
(
df_data
,
columns
=
[
'limit_money'
,
'per_invest'
,
'max_per_invest'
,
'min_per_invest'
,
'set_per_invest'
,
'code_update'
,
'today_finish'
,
'balance_to_db'
,
'posses_stocks'
,
'today_profit'
,
'contract_check'
,
'
db_to_daily_info'
,
'today_buy_list'
,
'stock_info'
,
'min_info
'
,
'daily_info'
])
'contract_check'
,
'
final_contract_check'
,
'db_to_daily_info'
,
'today_buy_list
'
,
'
stock_info'
,
'min_info'
,
'
daily_info'
])
df_setting_data
.
loc
[
0
,
'limit_money'
]
=
int
(
0
)
df_setting_data
.
loc
[
0
,
'per_invest'
]
=
int
(
0
)
...
...
@@ -350,11 +350,12 @@ class Open_Api(QAxWidget):
df_setting_data
.
loc
[
0
,
'today_profit'
]
=
float
(
0
)
df_setting_data
.
loc
[
0
,
'contract_check'
]
=
str
(
0
)
df_setting_data
.
loc
[
0
,
'final_contract_check'
]
=
str
(
0
)
df_setting_data
.
loc
[
0
,
'db_to_daily_info'
]
=
str
(
0
)
df_setting_data
.
loc
[
0
,
'today_buy_list'
]
=
str
(
0
)
df_setting_data
.
loc
[
0
,
'stock_info'
]
=
str
(
0
)
df_setting_data
.
loc
[
0
,
'min_info'
]
=
str
(
0
)
df_setting_data
.
loc
[
0
,
'min_info'
]
=
str
(
0
)
df_setting_data
.
loc
[
0
,
'daily_info'
]
=
str
(
0
)
df_setting_data
.
to_sql
(
"setting_data"
,
self
.
engine_bot
,
if_exists
=
"replace"
)
...
...
@@ -588,9 +589,113 @@ class Open_Api(QAxWidget):
self
.
opt10073_output
[
'multi'
]
.
append
([
date
,
code
,
code_name
,
amount
,
today_profit
,
earning_rate
])
# 특정 종목의 일자별 거래 데이터 조회 함수
def
get_date_data
(
self
,
code
,
code_name
,
date
):
self
.
ohlcv
=
defaultdict
(
list
)
self
.
set_input_value
(
"종목코드"
,
code
)
self
.
set_input_value
(
"기준일자"
,
date
)
self
.
set_input_value
(
"수정주가구분"
,
1
)
# 한번에 600일치의 데이터를 가져온다
self
.
comm_rq_data
(
"opt10081_req"
,
"opt10081"
,
0
,
"0101"
)
# stock_info 테이블이 존재하지 않는다면 600일치 이상의 전체 데이터를 가져와야 하므로 다음 페이지가 존재하지 않을 때까지 조회
if
not
self
.
is_stock_table_exist
(
code_name
):
while
self
.
remained_data
==
True
:
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
# stock_info 데이터베이스가 존재하는지 확인하는 함수
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
:
return
True
else
:
return
False
# 주식 일봉차트 조회 요청
# 주식의 날짜별 데이터를 저장하는 함수
def
collector_opt10081
(
self
,
sRQName
,
sTrCode
):
ohlcv_cnt
=
self
.
_get_repeat_cnt
(
sTrCode
,
sRQName
)
for
i
in
range
(
ohlcv_cnt
):
date
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"일자"
)
open
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"시가"
)
high
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"고가"
)
low
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"저가"
)
close
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"현재가"
)
volume
=
self
.
_get_comm_data
(
sTrCode
,
sRQName
,
i
,
"거래량"
)
self
.
ohlcv
[
'date'
]
.
append
(
date
)
self
.
ohlcv
[
'open'
]
.
append
(
int
(
open
))
self
.
ohlcv
[
'high'
]
.
append
(
int
(
high
))
self
.
ohlcv
[
'low'
]
.
append
(
int
(
low
))
self
.
ohlcv
[
'close'
]
.
append
(
int
(
close
))
self
.
ohlcv
[
'volume'
]
.
append
(
int
(
volume
))
# stock_info의 특정 종목 테이블에서 마지막으로 저장된 날짜를 가져오는 함수
# 저장된 데이터가 없다면 '0'문자를 반환
def
get_latest_date_from_stock_info
(
self
,
code_name
):
query
=
"select date from {} order by date desc limit 1"
result
=
self
.
engine_stock
.
execute
(
query
.
format
(
code_name
))
.
fetchall
()
if
len
(
result
):
return
result
[
0
][
0
]
else
:
return
str
(
0
)
def
check_contract
(
self
):
query
=
"select code from transaction_history where contract_check='1' and (sell date='0' or sell_date='')"
rows
=
self
.
engine_bot
.
execute
(
query
)
.
fetchall
()
for
r
in
rows
:
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
=
"update transaction_history set contract_check='0' where code='{}' and sell_date='0'"
# 거래가 완료된 항목은 주문번호가 존재하지 않음
# 거래가 완료된 항목에 대해서 contract_check항목을 '0'으로 업데이트
if
not
self
.
not_contract
[
'주문번호'
]:
self
.
engine_bot
.
execute
(
query
.
format
(
r
.
code
))
# 미체결 수량이 없을 경우 contract_check항목을 '0'으로 업데이트
elif
self
.
not_contract
[
'미체결수량'
]
==
0
:
logger
.
debug
(
"미체결 항목이 없습니다"
)
self
.
engine_bot
.
execute
(
query
.
format
(
r
.
code
))
else
:
logger
.
debug
(
"미체결 종목이 존재합니다"
)
# 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
))
# 가지고 있던 종목을 판매하여 posses_item테이블에 내역이 존재하지 않지만 transaction_history에 매도처리가 되지 않은 항목 업데이트
def
sell_check
(
self
,
code
):
query
=
"update transaction_history"
\
"set"
\
"contract_check='
%
s', sell_date='
%
s'"
\
"where code='
%
s' and sell_date='
%
s'"
self
.
engine_bot
.
execute
(
query
%
(
0
,
self
.
today_time
,
code
,
0
))
if
__name__
==
"__main__"
:
...
...
Please
register
or
login
to post a comment