이하영

collector 추가

import pymysql
pymysql.install_as_MySQLdb()
import sys
from library.collector_api import *
class Collector:
def __init__(self):
self.collector_api=collector_api()
def collecting(self):
self.collector_api.code_update_check()
if __name__=="__main__":
app=QApplication(sys.argv)
c=Collector()
c.collecting()
\ No newline at end of file
import pymysql
pymysql.install_as_MySQLdb()
class Collector:
def __init__(self):
\ No newline at end of file
def errors(err_code):
err_dict={0:('OP_ERR_NONE','정상처리'),
-10:('OP_ERR_FAIL','실패'),
-100:('OP_ERR_LOGIN','사용자정보교환실패'),
-101:('OP_ERR_CONNECT','서버접속실패'),
-102:('OP_ERR_VERSION','버전처리실패'),
-103:('OP_ERR_FAIRWALL','개인방화벽실패'),
-104:('OP_ERR_MEMORY','메모리보호실패'),
-105:('OP_ERR_INPUT','함수입력값오류'),
-106:('OP_ERR_SOCKET_CLOSED','통신연결종료'),
-200:('OP_ERR_SISE_OVERFLOW','시세조회과부화'),
-201:('OP_ERR_RQ_STRUCT_FAIL','전문작성초기화실패'),
-202:('OP_ERR_RQ_STRING_FAIL','전문작성입력값오류'),
-203:('OP_ERR_NO_DATA','데이터없음'),
-204:('OP_ERR_OVER_MAX_DATA','조회가능한종목수초과'),
-205:('OP_ERR_DATA_RCV_FAIL','데이터수신실패'),
-206:('OP_ERR_OVER_MAX_FID','조회가능한FID수초과'),
-207:('OP_ERR_REAL_CANCEL','실시간해제오류'),
-300:('OP_ERR_ORD_WRONG_INPUT','입력값오류'),
-301:('OP_ERR_ORD_WRONG_ACCNO','계좌비밀번호없음'),
-302:('OP_ERR_OTHER_ACC_USE','타인계좌사용오류'),
-303:('OP_ERR_MIS_2BILL_EXC','주문가격이20억원을초과'),
-304:('OP_ERR_MIS_5BILL_EXC','주문가격이50억원을초과'),
-305:('OP_ERR_MIS_1PER_EXC','주문수량이총발행주수의1 % 초과오류'),
-306:('OP_ERR_MIS_3PER_EXC','주문수량이총발행주수의3 % 초과오류'),
-307:('OP_ERR_SEND_FAIL','주문전송실패'),
-308:('OP_ERR_ORD_OVERFLOW','주문전송과부화'),
-309:('OP_ERR_MIS_300CNT_EXC','주문수량300계약초과'),
-310:('OP_ERR_MIS_500CNT_EXC','주문수량500계약초과'),
-340:('OP_ERR_ORD_WRONG_ACCINFO','계좌정보없음'),
-500:('OP_ERR_ORD_SYMCODE_EMPTY','종목코드없음')
}
result=err_dict[err_code]
return result
\ No newline at end of file
import datetime
from sqlalchemy import *
from sqlalchemy import event
import pymysql
from pandas import *
from Logger import *
import cf
from library.Logger import *
import library.cf
from library.open_api import *
class Simulator_Api:
class simulator_api:
def __init__(self,simul_num,op,db_name):
self.cf=library.cf
self.simul_num=int(simul_num)
if self.simul_num==-1:
self.set_date()
self.date_setting()
elif op=='reset':
self.op='reset'
self.simul_reset=True
self.set_variable()
self.variable_setting()
self.rotate_date()
elif op=='real':
self.op='real'
self.simul_reset=False
self.db_name=db_name
self.set_variable()
self.variable_setting()
elif op=='continue':
self.op='continue'
self.simul_reset=False
self.set_variable()
self.variable_setting()
self.rotate_date()
else:
logger.error("Invalid option")
# 오늘 날짜를 설정하는 함수
def set_date(self):
def date_setting(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()
self.today_detail=datetime.datetime.today().strftime("%Y%m%d%H%M")
self.today_date_form=datetime.datetime.strptime(self.today,"%Y%m%d").date()
# 사용되는 변수를 설정하는 함수
def set_variable(self):
self.set_date()
def variable_setting(self):
self.date_setting()
self.simul_end_date=self.today # 시뮬레이션이 끝나는 날짜
self.start_min="0900" # 장 시작 시간 : 9시
self.use_min=False # 분별 시뮬레이션을 사용하는 변수
self.use_nine=True # 9시에만 거래를 수행하는 변수
self.only_nine_buy=True # 9시에만 거래를 수행하는 변수
self.buy_stop=False # 거래를 중지하는 변수
self.trade_check_num=False # 실시간 조건 매수 옵션. 분별 시뮬레이팅의 경우 True, 일별 시뮬레이팅의 경우 False
print("simul_num : ",self.simul_num)
self.volume_limit=1000
if self.simul_num==1:
self.simul_start_date="20190101"
# 매수/매도 알고리즘 설정
self.buy_algorithm=1
self.sell_algorithm=1
self.db_to_realtime_daily_buy_list_num=1 # 매수리스트 설정 알고리즘
self.sell_list_num=1 # 매도리스트 설정 알고리즘
# 시뮬레이션 변수 설정
self.start_invest_price=1000000 # 초기 투자자금
......@@ -73,8 +77,8 @@ class Simulator_Api:
elif self.simul_num==2:
self.simul_start_date="20190101"
self.buy_algorithm=2
self.sell_algorithm=2
self.db_to_realtime_daily_buy_list_num=2
self.sell_list_num=2
self.start_invest_price=1000000
self.invest_unit=100000
......@@ -82,14 +86,14 @@ class Simulator_Api:
self.sell_point=10
self.losscut_point=-2
self.invest_buy_limit_rate=1.01
self.invest_sell_limit_rate=0.98
self.invest_limit_rate=1.01
self.invest_min_limit_rate=0.98
elif self.simul_num==3:
self.simul_start_date = "20190101"
self.buy_algorithm = 3
self.sell_algorithm = 3
self.db_to_realtime_daily_buy_list_num = 3
self.sell_list_num = 3
self.start_invest_price = 1000000
self.invest_unit = 100000
......@@ -97,16 +101,18 @@ class Simulator_Api:
self.sell_point = 10
self.losscut_point = -2
self.invest_buy_limit_rate = 1.01
self.invest_sell_limit_rate = 0.98
self.invest_limit_rate = 1.01
self.invest_min_limit_rate = 0.98
else:
logger.error("Invalid simul_num")
self.set_db_control()
self.db_name_setting()
if self.op!='real':
self.set_table()
# database, table 초기화
self.table_setting()
# 시뮬레이팅 할 날짜 저장
self.get_date_for_simul()
self.total_valuation_profit=0 # 매도 종목들에 대한 총 수익
......@@ -115,47 +121,54 @@ class Simulator_Api:
self.total_purchase_price=0 # 투자금
self.d2_deposit=self.start_invest_price # 예수금 = 초기자본 + 매도수익 - 투자금
self.update_balance() # 일별 정산
# 일별 정산
self.check_balance()
self.tax_rate=0.0025 # 거래 세금
self.fees_rate=0.00015 # 거래 수수료
self.simul_reset_lock=False # 시뮬레이터를 멈춘 지점부터 다시 돌릴 것인지를 선택하는 변수
# database를 control하기 위한 eninge 및 connection을 저장하는 함수
def set_db_control(self):
# database를 control하기 위한 engine 및 connection을 저장하는 함수
def db_name_setting(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')
self.engine_simul=create_engine("mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" +
self.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')
self.engine_simul=create_engine("mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" +
self.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')
self.engine_daily_craw = create_engine("mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" +
self.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')
self.engine_craw = create_engine("mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" +
self.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')
self.engine_daily_buy_list = create_engine("mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" +
self.cf.db_port + "/daily_buy_list", encoding='utf-8')
from library.open_api import escape_percentage
event.listen(self.engine_simul, 'before_execute', escape_percentage, retval=True)
event.listen(self.engine_daily_craw, 'before_execute', escape_percentage, retval=True)
event.listen(self.engine_craw, 'before_execute', escape_percentage, retval=True)
event.listen(self.engine_daily_buy_list, 'before_execute', escape_percentage, retval=True)
# mysql에 접속하는 객체 생성
self.db_conn = pymysql.connect(
host=cf.db_ip,
port=int(cf.db_port),
user=cf.db_id,
password=cf.db_pw,
host=self.cf.db_ip,
port=int(self.cf.db_port),
user=self.cf.db_id,
password=self.cf.db_pw,
charset='utf8'
)
# 데이터베이스와 테이블을 설정
def set_table(self):
def table_setting(self):
# simul_reset==True인 경우, 시뮬레이터를 초기화하고 다시 구축
if self.simul_reset:
self.init_database()
......@@ -164,11 +177,11 @@ class Simulator_Api:
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()
self.is_simul_table_exist(self.db_name,"all_stocks") and
self.is_simul_table_exist(self.db_name,"jango_data")):
self.init_df_jango()
self.init_df_all_stocks()
self.last_simul_date=self.get_jango_data_last_date()
# 필요한 데이터베이스와 테이블이 모두 존재하지 않는 경우, 다시 생성
else:
self.init_database()
......@@ -178,8 +191,8 @@ class Simulator_Api:
def init_database(self):
self.drop_database()
self.create_database()
self.init_df_account_balance()
self.init_df_transaction()
self.init_df_jango() # 잔고 내역 테이블
self.init_df_all_stocks() # 모든 거래 내역을 저장하는 테이블
# 시뮬레이터 데이터베이스 삭제
def drop_database(self):
......@@ -213,27 +226,27 @@ class Simulator_Api:
else:
return False
# 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 생성
# jango table 생성 : 잔고 내역을 저장하는 테이블
def init_df_jango(self):
jango_temp={'id':[]}
self.jango=DataFrame(jango_temp,
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', 'today_buy_list_count', 'total_invest',
'sum_item_total_purchase', 'total_evaluation', 'today_rate',
'today_invest_price','today_sell_price', 'volume_limit', 'sell_point',
'invest_limit_rate','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=jango_temp['id'])
# all_stocks table 생성 : 모든 거래내역을 저장하는 테이블
def init_df_all_stocks(self):
all_stocks={'id':[]}
self.df_all_stocks=DataFrame(all_stocks,
all_stocks_temp={'id':[]}
self.df_all_stocks=DataFrame(all_stocks_temp,
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',
......@@ -244,9 +257,9 @@ class Simulator_Api:
"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"
#jango(잔고 테이블)에 저장된 가장 최근의 날짜를 가져오는 함수
def get_jango_data_last_date(self):
query = "SELECT date from jango_data order by date desc limit 1"
result=self.engine_simul.execute(query).fechall()
return result[0][0]
......@@ -257,32 +270,32 @@ class Simulator_Api:
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"):
# 거래한 데이터를 바탕으로 거래이력(all_stocks) 테이블을 정산하는 함수
def check_balance(self):
# all_stocks table이 존재하지 않을 경우 return
if not self.is_simul_table_exist(self.db_name,"all_stocks"):
return
query="select sum(valuation_profit) from transaction"
query="select sum(valuation_profit) from all_stocks"
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'"
query="select sum(item_total_purchase) from all_stocks 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'"
query="select sum(valuation_profit) from all_stocks 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 # 예수금
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):
for i in range(1,len(self.date_rows)):
date_rows_today=self.date_rows[i][0] # 시뮬레이팅 할 날짜
date_rows_yesterday=self.date_rows[i-1][0] # 시뮬레이팅 하루 전 날짜
......@@ -299,118 +312,118 @@ class Simulator_Api:
# 일별 시뮬레이션
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"
# 시뮬레이션을 완료한 후 jango_data 테이블 업데이트
self.arrange_jango_data()
# 하루에 대한 시뮬레이션이 끝난 뒤 해당 날짜의 잔고(jango_data)정보를 업데이트하는 함수
def arrange_jango_data(self):
if self.engine_simul.dialect.has_table(self.engine_simul,"jango_data"):
len_date=self.get_len_jango_data_date()
query="select date from jango_data"
rows=self.engine_simul.execute(query).fetchall()
logger.debug("account balance 최종 정산")
for i in range(len_date):
# today_buy_count : 오늘 매수한 종목의 수
query="update account_balance " \
query="update jango_data " \
"set " \
"today_buy_count=(select count(*) from (select code from transaction where buy_date like '%s')) "\
"today_buy_count=(select count(*) from (select code from all_stocks 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 " \
query="update jango_data " \
"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)) " \
"(select code from all_stocks 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 " \
query="update jango_data " \
"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)) " \
"(select code from all_stocks 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 " \
query="update jango_data " \
"set " \
"today_buy_today_profitcut_count=" \
"(select count(*) from " \
"(select code from transaction " \
"(select code from all_stocks " \
"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 " \
query = "update jango_data " \
"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 " \
query = "update jango_data " \
"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)) " \
"(select code from all_stocks " \
"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 " \
query = "update jango_data " \
"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 " \
query = "update jango_data " \
"set " \
"total_profitcut_count=" \
"(select count(*) from " \
"(select code from transaction where sell_rate >= '%s' group by code)) "\
"(select code from all_stocks 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 " \
query = "update jango " \
"set " \
"total_profitcut=sum" \
"(select sell_price-purchase_price from transaction " \
"(select sell_price-purchase_price from all_stocks " \
"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 " \
query = "update jango_data " \
"set " \
"total_losscut_count=" \
"(select count(*) from " \
"(select code from transaction where sell_rate < '%s' group by code )) " \
"(select code from all_stocks 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 " \
query = "update jango_data " \
"set " \
"total_losscut=sum" \
"(select purchase_price-sell_price from transaction " \
"(select purchase_price-sell_price from all_stocks " \
"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"
# jango_data에 저장된 일자를 반환하는 함수
def get_len_jango_data_date(self):
query="select date from jango_data"
rows=self.engine_simul.execute(query).fetchall()
return len(rows)
......@@ -418,22 +431,22 @@ class Simulator_Api:
def simul_by_min(self, date_rows_today, date_rows_yesterday, i):
print("************************** date: " + date_rows_today)
# 시뮬레이팅 전에 변수 초기화
self.set_daily_variable()
self.daily_variable_setting()
# 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) # 잔고 테이블 업데이트
self.db_to_jango(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')
# all_stocks 테이블이 존재하고, 현재 보유 중인 종목이 있는 경우, 해당 종목에 대해 데이터베이스 업데이트
if self.is_simul_table_exist(self.db_name, "all_stocks") and len(self.get_data_from_possessed_item()) != 0:
self.update_all_db_by_date(date_rows_today, option='ALL')
else:
print("테이블이 존재하지 않습니다")
# 매일 시뮬레이션이 돌기 전에 변수를 초기화하는 함수
def set_daily_variable(self):
def daily_variable_setting(self):
self.buy_stop=False
self.today_invest_price=0
......@@ -446,50 +459,50 @@ class Simulator_Api:
else:
return False
# 매수 할 종목의 리스트를 선정하는 함수
# 다음날 매수 할 종목의 리스트를 선정하는 함수
def db_to_realtime_daily_buy_list(self,date_rows_today,date_rows_yesterday,i):
to_buy_list=None
realtime_daily_buy_list=None # 다음날 매수할 종목 리스트를 저장하는 변수
# (5,20) 골든크로스
if self.buy_algorithm == 1:
if self.db_to_realtime_daily_buy_list_num == 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()
realtime_daily_buy_list=self.engine_daily_buy_list.execute(query).fetchall()
# (20,60) 골든크로스
elif self.buy_algorithm == 2:
elif self.db_to_realtime_daily_buy_list_num == 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()
realtime_daily_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 len(realtime_daily_buy_list) > 0:
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'])
# 다음날 매수할 종목 중 code가 6자리의 정수로 된 항목만 선택
df_realtime_daily_buy_list['code'] = df_realtime_daily_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')
df_realtime_daily_buy_list['check_item'] = int(0)
df_realtime_daily_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"):
if self.is_simul_table_exist(self.db_name, "all_stocks"):
query = "delete from realtime_daily_buy_list " \
"where code in " \
"(select code from transaction where sell_date = '0')"
"(select code from all_stocks where sell_date = '0')"
self.engine_simul.execute(query)
# realtime_daily_buy_list 테이블에 저장 된 종목들을 저장
......@@ -497,12 +510,12 @@ class Simulator_Api:
# 모의투자 / 실전투자
else:
to_buy_list['check_item'] = int(0)
to_buy_list.to_sql('realtime_daily_buy_list', self.engine_simul, if_exists='replace')
df_realtime_daily_buy_list['check_item'] = int(0)
df_realtime_daily_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)
self.engine_simul.execute(query)
else:
self.len_df_realtime_daily_buy_list = 0
......@@ -530,8 +543,8 @@ class Simulator_Api:
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')
if self.is_simul_table_exist(self.db_name,"all_stocks"):
self.update_all_db_by_date(date_rows_today,option='OPEN')
# 분별 시간 데이터를 가져오기
self.get_min_data_for_simul(date_rows_today)
......@@ -540,84 +553,87 @@ class Simulator_Api:
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"):
if self.is_simul_table_exist(self.db_name,"all_stocks") and len(self.get_data_from_possessed_item())!=0:
self.show_info(min)
# 종목 데이터 업데이트
self.update_transaction_by_min(min)
self.update_transaction_etc()
self.update_all_db_by_min(min)
self.update_all_db_etc()
# 매도
self.auto_trade_sell_stock(min,i)
# 매수를 진행할 금액이 남아있는 경우
if not self.buy_stop and self.check_balance():
if not self.buy_stop and self.jango_check():
# 매수할 종목리스트 저장
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)
self.auto_trade_stock_realtime(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.jango_check():
self.auto_trade_stock_realtime(min,date_rows_today,date_rows_yesterday)
if not self.buy_stop and self.use_nine:
if not self.buy_stop and self.only_nine_buy:
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"):
if self.is_simul_table_exist(self.db_name,"all_stocks"):
print("simulating 시간 : ",date)
print("보유종목 수 : ",self.get_count_possess_item())
# 현재 보유하고 있는 종목수를 반환하는 함수
def get_count_possess_item(self):
query="select count(*) from transaction where sell_date='0'"
query="select count(*) from all_stocks 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()
def update_all_db_by_date(self,date,option='ALL'):
possessed_item_list=self.get_data_from_possessed_item()
if len(possess_item_list)==0:
if len(possessed_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)
for i in range(len(possessed_item_list)):
code_name=possessed_item_list[i][0]
result=self.get_now_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]
d1_diff=result[0][0]
d1_diff_rate = result[0][1]
close = result[0][2]
open = result[0][3]
high = result[0][4]
low = result[0][5]
volume = result[0][6]
clo5 = result[0][7]
clo10 = result[0][8]
clo20 = result[0][9]
clo60 = result[0][10]
clo120 = result[0][11]
if open:
self.db_to_transaction_update(code_name,d1_diff_rate,close,open,high,low,volume,
clo5,clo10,clo20,clo60,clo120,option)
self.db_to_all_stocks_present_price_update(code_name,d1_diff,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'"
def get_data_from_possessed_item(self):
query="select code_name from all_stocks 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}` " \
def get_now_price_by_date(self,code_name,date):
query = f"select d1_diff,d1_diff_rate, close, open, high, low, volume, clo5, clo10, clo20, clo60, clo120 " \
f"from '{date}' " \
f"where code_name = '{code_name}' group by code"
result=self.engine_daily_buy_list.execute(query).fetchall()
......@@ -626,9 +642,9 @@ class Simulator_Api:
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'):
# 현재의 주가를 거래이력(all_stocks)에 있는 보유 종목에 반영
def db_to_all_stocks_present_price_update(self,code_name,d1_diff,d1_diff_rate,close,open,high,low,volume,
clo5,clo10,clo20,clo60,clo120,option='ALL'):
# 모의투자 / 실전투자의 경우 현재가를 종가로 업데이트
if self.op=='real':
present_price=close
......@@ -638,36 +654,36 @@ class Simulator_Api:
# option==ALL이면 모든 데이터를 업데이트
if option=="ALL":
query = f"update transaction " \
query = f"update all_stocks " \
f"set " \
f"d1_diff_rate = {d1_diff_rate}, " \
f"d1_diff={d1_diff}, 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}"
f"where code_name = '{code_name}' and sell_date = '{0}'"
# option==open이면 open,present_price값만 업데이트
else:
query = f"update transaction " \
query = f"update all_stocks " \
f"set " \
f"open = {open}, present_price = {present_price} " \
f"where code_name = '{code_name}' and sell_date = {0}"
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):
# 분 데이터를 가져오는 함수
def get_date_min_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()
self.min_date_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]
# 거래이력(all_stocks)의 시세(close) 데이터를 분 별로 업데이트
def update_all_db_by_min(self,min):
possessed_code_name=self.get_data_from_possessed_item()
for i in range(len(possessed_code_name)):
code_name=possessed_code_name[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)
......@@ -686,16 +702,16 @@ class Simulator_Api:
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} " \
def db_to_all_stocks_present_price_update_by_min(self,code_name,current_close_price):
query=f"update all_stocks 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):
# 보유중인 종목들의 주가 이외의 기타 정보를 업데이트
def update_all_db_etc(self):
# valuation_price : 평가금액
# 평가금액 = (보유주 현재가 * 보유주 수량) - (총 구매금액 * 수수료) - (보유주 현재가 * 보유주 수량 * (수수료 + 세금))
query = f"update transaction " \
query = f"update all_stocks " \
f"set " \
f"valuation_price = " \
f"round((present_price * holding_amount) - item_total_purchase * {self.fees_rate} - " \
......@@ -707,11 +723,11 @@ class Simulator_Api:
# valuation_profit : 수익 금액
# 수익 금액 = 평가금액 - 총 구매금액
# 수익률 = 수익금액 / 구매금액 * 100
query = "update account_balance " \
query = "update all_stocks " \
"set " \
"rate= round((valuation_price - item_total_purchase)/item_total_purchase*100,2), " \
"valuation_profit = valuation_price - item_total_purchase " \
"where sell_date = '0';"
"where sell_date = '0'"
self.engine_simul.execute(query)
# 매도 함수
......@@ -742,17 +758,17 @@ class Simulator_Api:
print("=========================================")
# 매도 결과를 데이터베이스에 반영
self.send_sell_order(date,present_price,sell_rate,sell_code)
self.sell_send_order(date,present_price,sell_rate,sell_code)
# 매도한 결과를 transaction에 반영하는 함수
def send_sell_order(self,min,sell_price,sell_rate,code):
query=f"update transaction " \
# 매도한 결과를 all_stocks에 반영하는 함수
def sell_send_order(self,min,sell_price,sell_rate,code):
query=f"update all_stocks " \
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()
self.check_balance()
# 매도함수를 이용하여 매도할 종목을 가져오는 함수
def get_sell_list(self,i):
......@@ -760,14 +776,14 @@ class Simulator_Api:
# (5,20) 데드크로스
# 또는 손절 기준 수익률 이하로 떨어졌을 경우 매도
if self.sell_algorithm==1:
query=f"select code,rate, present_price,valuation_price from transaction " \
if self.sell_list_num==1:
query=f"select code,rate, present_price,valuation_price from all_stocks " \
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 " \
elif self.sell_list_num==2:
query=f"select code,rate, present_price,valuation_price from all_stocks " \
f"where sell_date='0' and (clo20<clo60 or rate<='{self.losscut_point}') group by code"
sell_list=self.engine_simul.execute(query).fetchall()
......@@ -783,17 +799,18 @@ class Simulator_Api:
# 남은 금액을 확인하는 함수
# 남은 금액이 최소 보유금 + 투자단위금액 이상이면 True, 아니면 False 반환
def check_balance(self):
def jango_check(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):
def auto_trade_stock_realtime(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():
# 매수할 잔액이 남아있다면
if self.jango_check():
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']
......@@ -810,9 +827,10 @@ class Simulator_Api:
# 일별 시뮬레이팅인 경우
if not self.use_min:
price=self.get_current_open_price_by_date(code,date_rows_today)
price=self.get_now_open_price_by_date(code,date_rows_today)
# 분별 시뮬레이팅인 경우
else:
price=self.get_current_close_price_by_min(code_name,min)
price=self.get_now_close_price_by_min(code_name,min)
# 전날 종가를 저장
yes_close=self.get_yes_close_price_by_date(code,date_rows_yesterday)
......@@ -822,16 +840,17 @@ class Simulator_Api:
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 self.use_min and not self.only_nine_buy and self.trade_check_num:
open=self.get_now_open_price_by_date(code,date_rows_today) # 시가
sum_volume=self.get_now_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):
if not self.trade_check(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)
# 매수주문
self.invest_send_order(min,code,code_name,price,yes_close,i)
else:
break
......@@ -854,8 +873,8 @@ class Simulator_Api:
return False
# 특정 날짜의 테이블에서 특정 종목의 시가를 가져오는 함수
def get_current_open_price_by_date(self,code,date):
query=f"select open from `{date}` where code = '{code}' group by code"
def get_now_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]
......@@ -864,7 +883,7 @@ class Simulator_Api:
# 전날 종가(close)를 가져오는 함수
def get_yes_close_price_by_date(self,code,date):
query = f"select close from `{date}` where code = '{code}' group by code"
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]
......@@ -872,8 +891,8 @@ class Simulator_Api:
return False
# 분별 현재 누적 거래량을 가져오는 함수
def get_current_volume_by_min(self,code_name,min):
query= f"select sum_volume from `{code_name}` " \
def get_now_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:
......@@ -887,7 +906,7 @@ class Simulator_Api:
# current_price - 현재가
# current_sum_volume - 현재 누적 거래량
# return : True인 경우 매수, False인 경우 매수하지 않음
def check_trade(self,df_row,open_price,current_price,current_sum_volume):
def trade_check(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']
......@@ -896,6 +915,7 @@ class Simulator_Api:
yes_volume = df_row['volume']
# 실시간 거래 대금 체크 알고리즘
# 어제 종가 보다 현재가가 증가했고, 거래 대금이 어제 거래대금에 비해서 x배 올라갔을 때 매수
if self.trade_check_num == 1:
yes_total_tr_price = yes_close * yes_volume # 전날 거래 대금
......@@ -930,180 +950,173 @@ class Simulator_Api:
logger.error("Invalid trade_check_num")
# 데이터베이스에 매수 내역 업데이트
def send_buy_order(self,date,code,code_name,price,yes_close,j):
def invest_send_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)
# 매수하는 경우 all_stocks에 해당 내역을 추가
self.db_to_all_stocks(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()
self.check_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)
# all_stocks 테이블에 추가하는 함수
def db_to_all_stocks(self,min,df,index,code,code_name,purchase_price,yesterday_close):
self.df_all_stocks.loc[0,'code']=code
self.df_all_stocks.loc[0,'code_name']=code_name
self.df_all_stocks.loc[0,'rate']=float(-0.33)
if yesterday_close:
self.df_transaction.loc[0, 'purchase_rate'] = round(
self.df_all_stocks.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_all_stocks.loc[0, 'purchase_price'] = purchase_price
self.df_all_stocks.loc[0, 'present_price'] = purchase_price
self.df_all_stocks.loc[0, 'holding_amount'] = int(self.invest_unit / purchase_price)
self.df_all_stocks.loc[0, 'buy_date'] = min
self.df_all_stocks.loc[0, 'item_total_purchase'] = self.df_all_stocks.loc[0, 'purchase_price'] * \
self.df_all_stocks.loc[0, 'holding_amount']
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_all_stocks.loc[0, 'item_total_purchase']
self.today_invest_price = self.today_invest_price + self.df_transaction.loc[0, 'item_total_purchase']
self.df_all_stocks.loc[0, 'chegyul_check'] = 0
self.df_all_stocks.loc[0, 'id'] = 0
self.df_all_stocks.loc[0, 'invest_unit'] = self.invest_unit
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_all_stocks.loc[0, 'yes_close'] = yesterday_close
self.df_all_stocks.loc[0, 'close'] = df.loc[index, 'close']
self.df_transaction.loc[0, 'yes_close'] = yesterday_close
self.df_transaction.loc[0, 'close'] = df.loc[index, 'close']
self.df_all_stocks.loc[0, 'open'] = df.loc[index, 'open']
self.df_all_stocks.loc[0, 'high'] = df.loc[index, 'high']
self.df_all_stocks.loc[0, 'low'] = df.loc[index, 'low']
self.df_all_stocks.loc[0, 'volume'] = df.loc[index, 'volume']
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_all_stocks.loc[0,'d1_diff']=int(df.loc[index,'d1_diff'])
self.df_all_stocks.loc[0, 'd1_diff_rate'] = float(df.loc[index, 'd1_diff_rate'])
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']
self.df_all_stocks.loc[0, 'clo5'] = df.loc[index, 'clo5']
self.df_all_stocks.loc[0, 'clo10'] = df.loc[index, 'clo10']
self.df_all_stocks.loc[0, 'clo20'] = df.loc[index, 'clo20']
self.df_all_stocks.loc[0, 'clo60'] = df.loc[index, 'clo40']
self.df_all_stocks.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'])
self.df_all_stocks.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'])
self.df_all_stocks.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'])
self.df_all_stocks.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'])
self.df_all_stocks.loc[0, 'clo40_diff_rate'] = float(df.loc[index, 'clo60_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_all_stocks.loc[0, 'clo60_diff_rate'] = float(df.loc[index, 'clo120_diff_rate'])
self.df_transaction.loc[0, 'valuation_profit'] = int(0)
self.df_all_stocks.loc[0, 'valuation_profit'] = int(0)
self.df_transaction=self.df_transaction.fillna(0)
self.df_all_stocks=self.df_all_stocks.fillna(0)
# 거래이력 테이블이 이미 존재한다면 데이터 추가
if self.is_simul_table_exist(self.db_name, "transaction"):
self.df_transaction.to_sql('transaction', self.engine_simul, if_exists='append')
if self.is_simul_table_exist(self.db_name, "all_stocks"):
self.df_all_stocks.to_sql('all_stocks', self.engine_simul, if_exists='append')
# 테이블이 존재하지 않는다면 생성
else:
self.df_transaction.to_sql('transaction', self.engine_simul, if_exists='replace')
self.df_all_stocks.to_sql('all_stocks', 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()
# jango 테이블을 생성 및 데이터를 추가하는 함수
def db_to_jango(self,date_rows_today):
self.check_balance()
# 거래이력(transaction)테이블이 존재하지 않는다면 return
if not self.is_simul_table_exist(self.db_name,"transaction"):
if not self.is_simul_table_exist(self.db_name,"all_stocks"):
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() # 총평가금액
self.jango.loc[0,'date']=date_rows_today # 구매일
self.jango.loc[0, 'sum_valuation_profit'] = self.sum_valuation_profit # 총평가금액
self.jango.loc[0, 'total_profit'] = self.total_valuation_profit # 총수익
self.jango.loc[0, 'today_profit'] = self.get_today_profit(date_rows_today) # 당일수익
self.jango.loc[0, 'today_profitcut_count'] = self.get_today_profitcut_count(date_rows_today) # 당일 익절종목 수
self.jango.loc[0, 'today_losscut_count'] = self.get_today_losscut_count(date_rows_today) # 당일 손절종목 수
self.jango.loc[0, 'today_profitcut'] = self.get_sum_today_profitcut(date_rows_today) # 당일 익절금액
self.jango.loc[0, 'today_losscut'] = self.get_sum_today_losscut(date_rows_today) # 당일 손절금액
self.jango.loc[0, 'd2_deposit'] = self.d2_deposit # 예수금
self.jango.loc[0, 'total_possess_count'] = self.get_total_possess_count() # 보유종목 수
self.jango.loc[0, 'today_buy_count'] = 0 # 오늘 구매한 종목수
self.jango.loc[0, 'total_invest'] = self.total_invest_price # 총 투자금액
self.jango.loc[0, 'sum_item_total_purchase'] = self.get_sum_item_total_purchase() # 총매입금액
self.jango.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) # 당일 기준 수익률
self.jango.loc[0, 'today_rate'] = round(
(float(self.jango.loc[0, 'total_evaluation']) -
float(self.jango.loc[0, 'sum_item_total_purchase'])) /
float(self.jango.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.jango.loc[0, 'today_invest_price'] = float(self.today_invest_price) # 당일 투자금액
self.jango.loc[0, 'today_sell_price'] = self.get_sum_today_sell_price(date_rows_today)
self.jango.loc[0, 'volume_limit'] = self.volume_limit
self.jango.loc[0, 'sell_point'] = self.sell_point
self.jango.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.jango.loc[0, 'limit_money'] = self.limit_money
self.jango.loc[0, 'total_profitcut'] = self.get_sum_total_profitcut()
self.jango.loc[0, 'total_losscut'] = self.get_sum_total_losscut()
self.jango.loc[0, 'total_profitcut_count'] = self.get_sum_total_profitcut_count()
self.jango.loc[0, 'total_losscut_count'] = self.get_sum_total_losscut_count()
# 데이터베이스에 테이블 추가
self.account_balance.to_sql('account_balance', self.engine_simul, if_exists='append')
self.jango.to_sql('jango_data', self.engine_simul, if_exists='append')
# 매도종목에 대한 당일 수익
query = f"update account_balance " \
query = f"update jango_data " \
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'"
query="SELECT sum(valuation_profit) from all_stocks 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'"
query = "SELECT count(code) from all_stocks 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'"
query = "SELECT count(code) from all_stocks 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' "
query = "SELECT sum(valuation_profit) from all_stocks 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' "
query = "SELECT sum(valuation_profit) from all_stocks 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'"
query = "select count(code) from all_stocks 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'"
query = "SELECT sum(item_total_purchase) from all_stocks where sell_date = '%s'"
result = self.engine_simul.execute(query % (0)).fetchall()[0][0]
if result is not None:
return result
......@@ -1112,7 +1125,7 @@ class Simulator_Api:
# 총평가금액을 계산하는 함수
def get_sum_valuation_price(self):
query = "SELECT sum(valuation_price) from transaction where sell_date = '%s'"
query = "SELECT sum(valuation_price) from all_stocks where sell_date = '%s'"
result = self.engine_simul.execute(query % (0)).fetchall()[0][0]
if result is not None:
return result
......@@ -1121,38 +1134,33 @@ class Simulator_Api:
# 당일 매도금액을 계산하는 함수
def get_sum_today_sell_price(self, date):
query = "SELECT sum(valuation_price) from transaction where sell_date like '%s'"
query = "SELECT sum(valuation_price) from all_stocks 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' "
query = "SELECT sum(valuation_profit) from all_stocks 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' "
query = "SELECT sum(valuation_profit) from all_stocks 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'"
query = "select count(code) from all_stocks 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' "
query = "select count(code) from all_stocks 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()
self.daily_variable_setting()
# daily_buy_list에 시뮬레이팅 할 날짜에 해당하는 테이블과 전 날 테이블이 존재하는지 확인
if self.is_date_exist(date_rows_today) and self.is_date_exist(date_rows_yesterday):
......@@ -1161,12 +1169,12 @@ class Simulator_Api:
# 매수/매도
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:
if self.is_simul_table_exist(self.db_name, "all_stocks") and len(self.get_data_from_possessed_item()) != 0:
# 보유 중인 종목들의 주가를 일별로 업데이트
self.update_transaction_by_date(date_rows_today,option="ALL")
self.update_all_db_by_date(date_rows_today,option="ALL")
# 정산
self.db_to_account_balance(date_rows_today)
self.db_to_jango(date_rows_today)
else:
print("날짜 테이블이 존재하지 않습니다.")
......@@ -1176,21 +1184,21 @@ class Simulator_Api:
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()
if self.is_simul_table_exist(self.db_name, "all_stocks") and len(self.get_data_from_possessed_item()) != 0:
self.update_all_db_by_date(date_rows_today,option="OPEN")
self.update_all_db_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)
if self.jango_check():
self.auto_trade_stock_realtime(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)
if self.jango_check():
self.auto_trade_stock_realtime(str(date_rows_today) + "0900", date_rows_today, date_rows_yesterday)
# daily_buy_list 데이터베이스에서 가장 최근의 날짜 테이블을 가져오는 함수
def get_recent_daily_buy_list_date(self):
......@@ -1204,7 +1212,7 @@ class Simulator_Api:
# 최근 daily_buy_list의 날짜 테이블에서 code에 해당하는 데이터만 가져오는 함수
def get_daily_buy_list_by_code(self,code,date):
query = f"select * from `{date}` where code = '{code}' group by code"
query = f"select * from '{date}' where code = '{code}' group by code"
daily_buy_list = self.engine_daily_buy_list.execute(query).fetchall()
......@@ -1217,4 +1225,41 @@ class Simulator_Api:
"clo60_diff_rate", "clo120_diff_rate",
'yes_clo5', 'yes_clo10', 'yes_clo20', 'yes_clo60','yes_clo120',
'vol5', 'vol10', 'vol20', 'vol60', 'vol120'])
return df_daily_buy_list
\ No newline at end of file
return df_daily_buy_list
# 현재 특정 종목의 종가를 가져오는 함수
def get_now_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 delete_table_data(self):
if self.is_simul_table_exist(self.db_name,"all_stocks"):
query="drop table all_stocks"
self.engine_simul.execute(query)
if self.is_simul_table_exist(self.db_name,"jango_data"):
query="drop table jango_data"
self.engine_simul.execute(query)
if self.is_simul_table_exist(self.db_name,"realtime_daily_buy_list"):
query="drop table realtime_daily_buy_list"
self.engine_simul.execute(query)
# 코드값으로 해당하는 종목명을 가져오는 함수
def get_name_by_code(self,code):
query=f"select code_name from stock_item_all where code='{code}'"
code_name=self.engine_daily_buy_list.execute(query)
if code_name:
return code_name[0][0]
else:
return False
# 몇개의 주를 살지 계산하는 함수
def buy_num_count(self,invest_unit,present_price):
return int(int(invest_unit)/int(present_price))
\ No newline at end of file
......
No preview for this file type
......@@ -8,7 +8,7 @@ db_ip="localhost"
test_account_no="8147766711"
test_num=1
test_bot_name="AutoBot"+str(test_num)+"_Test"
test_bot_name="autobot"+str(test_num)+"_Test"
# 실전투자 정보
real_account_no=""
......
......@@ -7,8 +7,8 @@ import time
from PyQt5.QtWidgets import *
from pandas import DataFrame
from open_api import *
from daily_buy_list import *
from library.open_api import *
from library.daily_buy_list import *
# open_api를 이용하여 데이터베이스에 정보를 저장하는 클래스
class collector_api():
......@@ -20,51 +20,55 @@ class collector_api():
# 변수설정
def variable_setting(self):
self.open_api.py_gubun = "collector" # 용도를 저장하는 변수. collector : 데이터 저장 / trader : 종목 거래
self.dc = daily_crawler(self.open_api.cf.real_db_name, self.open_api.cf.real_daily_craw_db_name,
self.dc = daily_crawler(self.open_api.cf.real_bot_name, self.open_api.cf.real_daily_craw_db_name,
self.open_api.cf.real_daily_buy_list_db_name)
self.dbl = daily_buy_list()
# 콜렉팅을 실행하는 함수
def code_update_check(self):
logger.debug("code_update_check function")
query = "select jango_data_db_check, possessed_item, today_profit, final_chegyul_check, " \
"db_to_buy_list,today_buy_list, daily_crawler , min_crawler, daily_buy_list from setting_data limit 1"
logger.debug("code_update_check 함수에 들어왔습니다.")
rows = self.engine_bot.execute(query).fetchall()
sql = "select code_update,jango_data_db_check, possessed_item, today_profit, final_chegyul_check, " \
"db_to_buy_list,today_buy_list, daily_crawler , min_crawler, daily_buy_list from setting_data limit 1"
rows = self.engine_bot.execute(sql).fetchall()
# 종목 업데이트
if rows[0][0] != self.open_api.today:
self.open_api.check_balance()
# 잔고/보유종목 업데이트 확인
if rows[0][0] != self.open_api.today or rows[0][1] != self.open_api.today:
if rows[0][1] != self.open_api.today or rows[0][2] != self.open_api.today:
self.py_check_balance()
self.open_api.set_invest_unit()
# possessed_item(현재 보유종목) 테이블 업데이트
if rows[0][1] != self.open_api.today:
self.open_api.db_to_possesed_item()
self.open_api.setting_data_possesed_item()
if rows[0][2] != self.open_api.today:
self.open_api.db_to_possessed_item()
self.open_api.setting_data_possessed_item()
# 당일 종목별 실현 손익 내역 테이블 업데이트
if rows[0][2] != self.open_api.today:
if rows[0][3] != self.open_api.today:
self.db_to_today_profit_list()
# daily_craw 데이터베이스 업데이트
if rows[0][6] != self.open_api.today:
if rows[0][7] != self.open_api.today:
self.daily_crawler_check()
# daily_buy_list 데이터베이스 업데이트
if rows[0][8] != self.open_api.today:
if rows[0][9] != self.open_api.today:
self.daily_buy_list_check()
# 매수/매도 후 daily_buy_list 데이터베이스 업데이트
if rows[0][3] != self.open_api.today:
self.open_api.chegyul_check() # 매수 후 all_stocks에 저장되지 않은 종목 처리
self.open_api.final_chegyul_check() # # 매도 후 all_stocks에 sell_date가 업데이트 되지 않은 항목 처리
if rows[0][4] != self.open_api.today:
self.open_api.check_chegyul() # 매수 후 all_item_db에 저장되지 않은 종목 처리
self.open_api.final_chegyul_check() # 매도 후 all_item_db에 sell_date가 업데이트 되지 않은 항목 처리
# 다음날 매수 종목 테이블(realtime_daily_buy_list) 업데이트
if rows[0][5] != self.open_api.today:
if rows[0][6] != self.open_api.today:
self.realtime_daily_buy_list_check()
# min_craw db (분별 데이터) 업데이트
if rows[0][7] != self.open_api.today:
if rows[0][8] != self.open_api.today:
self.min_crawler_check()
logger.debug("collecting 작업을 모두 정상적으로 마쳤습니다.")
......@@ -179,7 +183,7 @@ class collector_api():
logger.debug("daily_crawler success !!!")
sql = "UPDATE setting_data SET daily_crawler='%s' limit 1"
self.engine_JB.execute(sql % (self.open_api.today))
self.engine_bot.execute(sql % (self.open_api.today))
# 틱(1분 별) 데이터를 가져오는 함수
def set_min_crawler_table(self, code, code_name):
......@@ -271,7 +275,7 @@ class collector_api():
df_temp.to_sql(name=code_name, con=self.open_api.engine_craw, if_exists='append')
# 콜렉팅하다가 max_api_call 횟수까지 가게 된 경우
# 이후 콜렉팅 하지 못한 정보를 가져오기 위해 check_item_gubun=0
if self.open_api.rq_count == cf.max_api_call - 1:
if self.open_api.rq_count == self.open_api.cf.max_api_call - 1:
check_item_gubun = 0
# 정상완료한 경우 check_item_gubun=1
else:
......@@ -289,7 +293,7 @@ class collector_api():
# 특정 종목명(code_name)의 테이블이 존재하는 경우
if self.engine_bot.dialect.has_table(self.open_api.engine_daily_craw, code_name):
query=f"select * from '{code_name}' where date='{oldest_row['date']}' limit 1"
query=f"select * from {code_name} where date='{oldest_row['date']}' limit 1"
check_row = self.open_api.engine_daily_craw.execute(query).fetchall()
# 종목명 테이블이 존재하지 않는 경우, 종목 리스트(stock_item_all) 테이블에 check_daily_crawler=4 업데이트
else:
......@@ -372,12 +376,12 @@ class collector_api():
return check_item_gubun
df_temp[['close', 'open', 'high', 'low', 'volume', 'clo5', 'clo10', 'clo20', 'clo60','clo120',
'yes_clo5', 'yes_clo10', 'yes_clo20','yes_clo60', 'yes_clo80','yes_clo120',
'vol5', 'vol10', 'vol20', 'vol40', 'vol60', 'vol80', 'vol100', 'vol120']] = \
'yes_clo5', 'yes_clo10', 'yes_clo20','yes_clo60', 'yes_clo120',
'vol5', 'vol10', 'vol20','vol60','vol120']] = \
df_temp[
['close', 'open', 'high', 'low', 'volume', 'clo5', 'clo10', 'clo20','clo60','clo120',
'yes_clo5', 'yes_clo10', 'yes_clo20', 'yes_clo60','yes_clo120',
'vol5', 'vol10', 'vol20', 'vol40', 'vol60', 'vol80', 'vol100', 'vol120']].fillna(0).astype(int)
'vol5', 'vol10', 'vol20', 'vol60', 'vol120']].fillna(0).astype(int)
df_temp.to_sql(name=code_name, con=self.open_api.engine_daily_craw, if_exists='append')
......@@ -388,7 +392,7 @@ class collector_api():
logger.info('daily_buy_list 업데이트 중..')
query="SELECT table_name as tname FROM information_schema.tables " \
"WHERE table_schema ='daily_buy_list' AND table_name REGEXP '[0-9]{8}"
"WHERE table_schema ='daily_buy_list' AND table_name REGEXP '[0-9]{8}'"
dbl_dates = self.open_api.engine_daily_buy_list.execute(query).fetchall()
for row in dbl_dates:
......@@ -410,14 +414,14 @@ class collector_api():
def db_to_today_profit_list(self):
self.open_api.reset_opt10073_output()
self.open_api.set_input_value("계좌번호", self.open_api.account_number)
self.open_api.set_input_value("계좌번호", self.open_api.account_no)
self.open_api.set_input_value("시작일자", self.open_api.today)
self.open_api.set_input_value("종료일자", self.open_api.today)
self.open_api.comm_rq_data("opt10073_req", "opt10073", 0, "0328")
while self.open_api.remained_data:
self.open_api.set_input_value("계좌번호", self.open_api.account_number)
self.open_api.set_input_value("계좌번호", self.open_api.account_no)
self.open_api.comm_rq_data("opt10073_req", "opt10073", 2, "0328")
today_profit_item_temp = {'date': [], 'code': [], 'code_name': [], 'amount': [], 'today_profit': [],
......@@ -500,13 +504,13 @@ class collector_api():
# 총 익절 종목 수(total_profitcut_count)
query = "select count(*) " \
"from (select code from all_stocks where sell_rate >='%s' and sell_date like '%s' group by code)"
"from (select code from all_stocks where sell_rate >='%s' and sell_date like '%s' group by code) temp"
rows = self.engine_bot.execute(query % (0, self.open_api.today + "%%")).fetchall()
jango.loc[0, 'total_profitcut_count'] = int(rows[0][0])
# 총 손절 종목 수(total_losscut_count)
query = "select count(*) " \
"from (select code from all_stocks where sell_rate < '%s' and sell_date like '%s' group by code)"
"from (select code from all_stocks where sell_rate < '%s' and sell_date like '%s' group by code) temp"
rows = self.engine_bot.execute(query % (0, self.open_api.today + "%%")).fetchall()
jango.loc[0, 'total_losscut_count'] = int(rows[0][0])
......@@ -525,7 +529,7 @@ class collector_api():
# 당일 구매 종목 수 (today_buy_count)
query = "UPDATE jango_data SET " \
"today_buy_count=" \
"(select count(*) from (select code from all_stocks where buy_date like '%s' group by code)) " \
"(select count(*) from (select code from all_stocks where buy_date like '%s' group by code) temp) " \
"WHERE date='%s'"
self.engine_bot.execute(query % (rows[i][0] + "%%", rows[i][0]))
......@@ -539,8 +543,8 @@ class collector_api():
# 총 보유 종목 수 (total_possess_count)
query = "UPDATE jango_data SET " \
"today_buy_total_possess_count=" \
"(select count(*) from (select code from all_stocks where sell_date = '0' group by code )) " \
"total_possess_count=" \
"(select count(*) from (select code from all_stocks where sell_date = '0' group by code ) temp) " \
"WHERE date='%s'"
self.engine_bot.execute(query % (rows[i][0]))
......@@ -554,27 +558,27 @@ class collector_api():
# 예수금상세현황
self.open_api.reset_opw00018_output()
self.open_api.set_input_value("계좌번호", self.open_api.account_number)
self.open_api.set_input_value("계좌번호", self.open_api.account_no)
self.open_api.set_input_value("비밀번호입력매체구분", 00)
self.open_api.set_input_value("조회구분", 1)
self.open_api.comm_rq_data("opw00001_req", "opw00001", 0, "2000")
# 계좌평가잔고내역
self.open_api.set_input_value("계좌번호", self.open_api.account_number)
self.open_api.set_input_value("계좌번호", self.open_api.account_no)
self.open_api.comm_rq_data("opw00018_req", "opw00018", 0, "2000")
while self.open_api.remained_data:
self.open_api.set_input_value("계좌번호", self.open_api.account_number)
self.open_api.set_input_value("계좌번호", self.open_api.account_no)
self.open_api.comm_rq_data("opw00018_req", "opw00018", 2, "2000")
# 일자별실현손익
self.open_api.set_input_value("계좌번호", self.open_api.account_number)
self.open_api.set_input_value("계좌번호", self.open_api.account_no)
self.open_api.set_input_value("시작일자", "20170101")
self.open_api.set_input_value("종료일자", self.open_api.today)
self.open_api.comm_rq_data("opt10074_req", "opt10074", 0, "0329")
while self.open_api.remained_data:
self.open_api.set_input_value("계좌번호", self.open_api.account_number)
self.open_api.set_input_value("계좌번호", self.open_api.account_no)
self.open_api.set_input_value("시작일자", "20170101")
self.open_api.set_input_value("종료일자", "20180930")
......
......@@ -2,31 +2,32 @@ from sqlalchemy import *
from pandas import DataFrame
import datetime
from daily_crawler import *
import cf
from library.daily_crawler import *
from library.cf import *
# -* daily_buy_list *-
# 일자별로 주식종목에 대한 데이터를 저장하는 데이터베이스
class daily_buy_list():
def __init__(self):
self.cf=library.cf
self.variable_setting()
# 변수 설정
def variable_setting(self):
self.today = datetime.datetime.today().strftime("%Y%m%d")
self.today_detail = datetime.datetime.today().strftime("%Y%m%d%H%M")
self.start_date = cf.start_daily_buy_list
self.start_date = self.cf.start_daily_buy_list
self.engine_daily_craw = create_engine(
"mysql+pymysql://" + cf.db_id + ":" + cf.db_pw + "@" + cf.db_ip + ":" + cf.db_port + "/daily_craw",
"mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" + self.cf.db_port + "/daily_craw",
encoding='utf-8')
self.engine_daily_buy_list = create_engine(
"mysql+pymysql://" + cf.db_id + ":" + cf.db_pw + "@" + cf.db_ip + ":" + cf.db_port + "/daily_buy_list",
"mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" + self.cf.db_port + "/daily_buy_list",
encoding='utf-8')
# 설정한 날짜부터 현재까지 날짜 리스트를 저장하는 함수
def date_rows_setting(self):
query = "select date from `gs글로벌` where date >= '%s' group by date"
query = "select date from 대한항공 where date >= '%s' group by date"
self.date_rows = self.engine_daily_craw.execute(query % self.start_date).fetchall()
# daily_buy_list 데이터베이스에 특정 이름(date)을 가진 테이블이 존재하는지 확인하는 함수
......@@ -63,14 +64,15 @@ class daily_buy_list():
if not self.is_table_exist_daily_craw(code, code_name):
continue
query = f"select * from '{self.stock_item_all[i][0]}' where date = '{self.date_rows[k][0]}' " \
query = f"select * from {self.stock_item_all[i][0]} where date = '{self.date_rows[k][0]}' " \
f"group by date"
rows = self.engine_daily_craw.execute(query).fetchall()
multi_list += rows
if len(multi_list) != 0:
df_temp = DataFrame(multi_list,
columns=['index', 'date', 'check_item', 'code', 'code_name', 'd1_diff_rate',
columns=['index', '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",
......
......@@ -5,7 +5,7 @@ from sqlalchemy import create_engine
import pandas as pd
from PyQt5.QtCore import *
import cf
import library.cf
pymysql.install_as_MySQLdb()
......@@ -14,6 +14,7 @@ pymysql.install_as_MySQLdb()
class daily_crawler():
def __init__(self, db_name, daily_craw_db_name, daily_buy_list_db_name):
self.cf=library.cf
# db_name==0인 경우는 simulator
if db_name != 0:
self.db_name = db_name
......@@ -22,7 +23,7 @@ class daily_crawler():
self.daily_buy_list_db_name = daily_buy_list_db_name
self.engine = create_engine(
"mysql+pymysql://" + cf.db_id + ":" + cf.db_pw + "@" + cf.db_ip + ":" + cf.db_port + "/daily_craw",
"mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" + self.cf.db_port + "/daily_craw",
encoding='utf-8')
self.daily_craw_db_con = self.engine.connect()
......
......@@ -15,14 +15,15 @@ from sqlalchemy.pool import Pool
import pymysql
pymysql.install_as_MySQLdb()
from Logger import *
import cf
from Simulator_Api import *
from library.Logger import *
import library.cf
from library.simulator_api import *
# 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:
......@@ -33,14 +34,18 @@ def escape_percentage(conn,clauseelement,multiparmas,parmas):
clauseelement=replaced
return clauseelement,multiparmas,parmas
# MySQL의 default sql_mode 설정
def setup_sql_mod(dbapi_connection):
def setup_sql_mod(dbapi_connection,connection_record):
cursor=dbapi_connection.cursor()
cursor.execute("SET sql_mode=''")
event.listen(Pool,'connect',setup_sql_mod)
event.listen(Pool,'first_connect',setup_sql_mod)
# 키움증권 open_api를 사용하기 위한 클래스
class open_api(QAxWidget):
def __init__(self):
super().__init__()
......@@ -51,49 +56,51 @@ class open_api(QAxWidget):
# open_api 호출 횟수를 저장
self.rq_count=0
self.set_date()
self.tr_loop_count=0
self.call_time=datetime.datetime.now()
# 날짜 설정
self.date_setting()
# open_api 연동
self._create_instance()
self._create_open_api_instance()
self._set_signal_slots()
self.comm_connect()
# 계좌정보 출력
self.get_account_info()
self.account_info()
# 변수 설정
self.set_variable()
self.sf=Simulator_Api(self.simul_num,"real",self.db_name)
logger.debug("알고리즘 번호 : %s",self.simul_api.simul_num)
logger.debug("매수 알고리즘 번호 : %s",self.simul_api.buy_algorithm)
logger.debug("매도 알고리즘 번호 : %s",self.simul_api.sell_algorithm)
self.variable_setting()
self.sf=simulator_api(self.simul_num,"real",self.db_name)
logger.debug("알고리즘 번호 : %s", self.sf.simul_num)
logger.debug("다음날 매수종목 선택 알고리즘 번호 : %s", self.sf.db_to_realtime_daily_buy_list_num)
logger.debug("매도 알고리즘 번호 : %s", self.sf.sell_list_num)
# 시뮬레이션 데이터베이스에 setting_data 테이블이 존재하지 않는다면 생성
if not self.sf.is_simul_table_exist(self.db_name,"setting_data"):
self.init_setting_data()
self.init_db_setting_data()
else:
logger.debug("setting_data 테이블이 존재합니다.")
# invest unit 설정
self.set_simul_variable()
self.ohlcv=defaultdict(list)
self.sf_variable_setting()
self.ohlcv=defaultdict(list) # o(open)h(high)l(low)c(close)v(volume)를 저장하는 데이터프레임 변수
# 날짜 설정
# -* date_setting
def set_date(self):
self.today=datetime.datetime.today().strftime("%Y%m%d")
self.today_time=datetime.datetime.today().strftime("%Y%m%d%H%M")
# 오늘 날짜를 저장하는 함수
def date_setting(self):
self.today=datetime.datetime.today().strftime("%Y%m%d") # 년월일
self.today_detail=datetime.datetime.today().strftime("%Y%m%d%H%M") # 년월일시분
# 키움 open_api 를 사용하기 위한 ocx controller 생성
# -* create_open_api_instance
def _create_instance(self):
# 키움 open_api 를 사용하기 위한 ocx controller 생성 함수
def _create_open_api_instance(self):
try:
self.setControl("KHOPENAPI.KHOpenAPICtrl.1")
except Exception as e:
logger.critical(e)
# 이벤트 처리를 위한 slots
# 이벤트 처리를 위한 slots 연동 함수
def _set_signal_slots(self):
try:
# 로그인 처리 이벤트
......@@ -121,11 +128,11 @@ class open_api(QAxWidget):
logger.critical(e)
# 사용자의 계좌정보 저장 및 출력
def get_account_info(self):
def account_info(self):
logger.debug("-* get_account_info 함수 *-")
account_no=self.get_login_info("ACCNO")
self.account_no=account_no.split(";")[0]
logger.debug("계좌번호 : ", self.account_no)
logger.debug("계좌번호 : "+ self.account_no)
# 원하는 사용자 정보 반환
# param : tag - ACCNO - 보유계좌리스트
......@@ -165,10 +172,10 @@ class open_api(QAxWidget):
self.remained_data=False
# Request 요청에 따른 함수 처리
if sRQName == "opt10081_req" and self.purpose == "trader":
if sRQName == "opt10081_req" and self.py_gubun == "trader":
logger.debug("주식일봉차트조회요청")
self._opt10081(sRQName,sTrCode)
elif sRQName == "opt10081_req" and self.purpose == "collector":
elif sRQName == "opt10081_req" and self.py_gubun == "collector":
logger.debug("주식일봉차트조회요청")
self.collector_opt10081(sRQName,sTrCode)
elif sRQName == "opw00001_req":
......@@ -225,31 +232,31 @@ class open_api(QAxWidget):
return
chegyul_fail_amount=self.get_chejan_data(902) # 미체결 수량
order_gubun=self.get_chejan_data(905) # 주문구분
order_gubun=self.get_chejan_data(905) # 주문구분 (+매수 / -매도)
purchase_price=self.get_chejan_data(10) # 체결가
# 종목코드가 존재한다면
if code:
if chegyul_fail_amount!="":
# 해당 종목을 보유하고 있지 않은 경우
if not self.is_all_stock_check(code):
if not self.is_all_stocks_db_check(code):
# 해당 종목의 체결 실패 내역이 없다면
# transaction 테이블에 업데이트. 정상 체결 시 chegyul_check=0
# all_stocks 테이블에 업데이트. 정상 체결 시 chegyul_check=0
if chegyul_fail_amount=="0":
logger.debug(code, "체결 완료")
self.db_to_all_stocks(order_num,code,0,purchase_price,0)
# 체결 실패 내역이 존재한다면
# transaction 테이블에 업데이트. 미체결 시 chegyul_check=1
# all_stocks 테이블에 업데이트. 미체결 시 chegyul_check=1
else:
logger.debug(code,"미체결")
self.db_to_all_stocks(order_num,code,1,purchase_price,0)
# 매수하는 경우
elif order_gubun=="+매수":
if chegyul_fail_amount!="0" and self.check_stock_chegyul(code):
if chegyul_fail_amount!="0" and self.stock_chegyul_check(code):
logger.debug("미체결. 매수 진행중!")
pass
elif chegyul_fail_amount=="0" and self.check_stock_chegyul(code):
elif chegyul_fail_amount=="0" and self.stock_chegyul_check(code):
logger.debug("매수 완료")
self.end_invest_count_check(code)
else:
......@@ -262,14 +269,14 @@ class open_api(QAxWidget):
self.sell_final_check(code)
else:
logger.debug("부분 매도")
self.check_sell_chegyul_fail(code)
self.sell_chegyul_fail_check(code)
else:
logger.debug("Invalid order_gubun")
else:
logger.debug("Invalid chegyul_fail_amount value")
else:
logger.debug("can't receive code value")
logger.debug("can't receive code value from get_chejan_data(9001)")
# 국내주식 잔고전달
elif sGubun=="1":
......@@ -280,7 +287,8 @@ class open_api(QAxWidget):
logger.debug("Invlid _receive_chejan_data")
# 해당 종목이 체결되었는지 확인하는 함수
def check_stock_chegyul(self,code):
# 미체결 항목이 존재하면 True를 반환
def stock_chegyul_check(self,code):
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()
......@@ -289,9 +297,9 @@ class open_api(QAxWidget):
else:
return False
# 매도 완료 후 DB 업데이트
def check_sell_end(self,code):
query="select valuation_profit,rate,item_total_urchase,present_price" \
# 매도 완료 후 DB 업데이트
def sell_final_check(self,code):
query="select valuation_profit,rate,item_total_purchase,present_price" \
"from possessed_item" \
"where code={} limit 1"
get_list=self.engine_bot.execute(query.format(code)).fetchall()
......@@ -299,7 +307,7 @@ class open_api(QAxWidget):
# 매도 완료 종목에 대해 DB 업데이트
if get_list:
item = get_list[0]
query = f"""UPDATE transaction
query = f"""UPDATE all_stocks
SET
item_total_purchase = {item.item_total_purchase}, chegyul_check = 0,
sell_date = '{self.today_detail}', valuation_profit = {item.valuation_profit},
......@@ -313,7 +321,7 @@ class open_api(QAxWidget):
logger.debug("보유 종목이 없습니다.")
# 매도 체결 실패시 DB 업데이트
def check_sell_chegyul_fail(self,code):
def sell_chegyul_fail_check(self,code):
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)
......@@ -330,9 +338,10 @@ class open_api(QAxWidget):
except Exception as e:
logger.critical(e)
# 거래이력(transaction)테이블에 현재 보유중인 종목이 있는지 확인하는 함수
def is_transaction_check(self,code):
query = "select code from transaction " \
# 거래이력(all_stocks)테이블에 현재 보유중인 종목이 있는지 확인하는 함수
# 보유한 종목이 있는 경우 True 반환
def is_all_stocks_db_check(self,code):
query = "select code from all_stocks " \
"where code='%s' and (sell_date ='%s' or sell_date='%s') ORDER BY buy_date desc LIMIT 1"
rows = self.engine_bot.execute(query % (code, 0, "")).fetchall()
if len(rows) != 0:
......@@ -357,7 +366,6 @@ class open_api(QAxWidget):
def comm_rq_data(self,sRQName,sTrData,nPrevNext,sScrNo):
self.exit_check()
ret=self.dynamicCall("CommRqData(QString, QString, int, QString", sRQName, sTrData, nPrevNext, sScrNo)
if ret==-200:
logger.critical("요청 제한 횟수 초과")
......@@ -388,40 +396,39 @@ class open_api(QAxWidget):
# 변수 설정
# 실전투자인지 모의투자인지 여부를 확인하고 그에 해당하는 데이터베이스를 생성하는 함수
def set_variable(self):
def variable_setting(self):
logger.debug("-* set variable 함수 *-")
self.cf=cf
self.cf=library.cf
self.get_today_buy_list_code=0
self.reset_opw00018_output()
if self.account_no==self.cf.real_account_no:
logger.debug("실전투자 - 계좌번호 : ",self.account_no)
logger.debug("실전투자 - 계좌번호 : "+self.account_no)
self.simul_num=self.cf.real_num
self.set_database(cf.real_bot_name)
self.db_name_setting(self.cf.real_bot_name)
self.mod_gubun=100 # 실전투자와 모의투자를 구분하는 변수
elif self.account_no==self.cf.test_account_no:
logger.debug("모의투자 - 계좌번호 : ",self.account_no)
logger.debug("모의투자 - 계좌번호 : "+self.account_no)
self.simul_num=self.cf.test_num
self.set_database(cf.test_bot_name)
self.db_name_setting(self.cf.test_bot_name)
self.mod_gubun=1
else:
logger.debug("Invalid Account Number. Check the Config.py")
exit(1)
self.jango_is_null=True
self.py_gubun=False
self.jango_is_null=True # 더이상 투자할 금액이 남았는지 확인하는 변수
self.py_gubun=False # collector/trader을 구분하는 변수
# 데이터베이스 생성 및 엔진 설정
# -* db_name_setting
def set_database(self,db_name):
def db_name_setting(self,db_name):
self.db_name=db_name
conn=pymysql.connect(
host=cf.db_ip,
port=int(cf.db_port),
user=cf.db_id,
password=cf.db_pw,
host=self.cf.db_ip,
port=int(self.cf.db_port),
user=self.cf.db_id,
password=self.cf.db_pw,
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
......@@ -430,17 +437,17 @@ class open_api(QAxWidget):
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.create_basic_database(cursor)
self.basic_db_check(cursor)
conn.commit()
conn.close()
self.engine_craw = create_engine("mysql+pymysql://" + cf.db_id + ":" + cf.db_pw + "@" + cf.db_ip + ":" +
cf.db_port + "/min_craw",encoding='utf-8')
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')
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')
self.engine_craw = create_engine("mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" +
self.cf.db_port + "/min_craw",encoding='utf-8')
self.engine_daily_craw = create_engine("mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":" +
self.cf.db_port + "/daily_craw",encoding='utf-8')
self.engine_daily_buy_list = create_engine("mysql+pymysql://" + self.cf.db_id + ":" + self.cf.db_pw + "@" + self.cf.db_ip + ":"
+ self.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)
......@@ -462,8 +469,7 @@ class open_api(QAxWidget):
# daily_craw(종목의 날짜별 데이터), daily_buy_list(날짜별 종목 데이터), min_craw(종목의 분별 데이터) 가 존재하는지 확인하는 함수
# 존재하지 않는다면 새로 생성
# -* basic_db_check
def create_basic_database(self,cursor):
def basic_db_check(self,cursor):
check_list = ['daily_craw', 'daily_buy_list', 'min_craw']
query = "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA"
cursor.execute(query)
......@@ -478,10 +484,10 @@ class open_api(QAxWidget):
cursor.execute(create_db_query.format(check_name))
if has_created and self.engine_bot.has_table('setting_data'):
self.engine_bot.execute("UPDATE setting_data SET code_update = '0';")
self.engine_bot.execute("UPDATE setting_data SET code_update = '0'")
# setting_data 테이블 생성 및 초기화하는 함수
def init_setting_data(self):
def init_db_setting_data(self):
logger.debug("-* init_setting_data 함수 *-")
df_setting_data_temp = {'limit_money': [], 'invest_unit': [], 'max_invest_unit': [],
......@@ -517,10 +523,10 @@ class open_api(QAxWidget):
df_setting_data.loc[0, 'min_crawler'] = str(0) # min_crawler(종목의 분별 데이터) 업데이트 날자
df_setting_data.loc[0, 'daily_buy_list'] = str(0) # daily_buy_list(일별 종목 데이터) 업데이트 날짜
df_setting_data.to_sql('setting_data', self.engine_JB, if_exists='replace')
df_setting_data.to_sql('setting_data', self.engine_bot, if_exists='replace')
# simulator_fun 에서 설정한 변수를 가져오는 함수
def set_simul_variable(self):
# simulator_api 에서 설정한 변수를 가져오는 함수
def sf_variable_setting(self):
logger.debug("-* set simul variable function *-")
# daily_buy_list에 저장된 가장 최신 날짜
self.date_rows_yesterday=self.sf.get_recent_daily_buy_list_date()
......@@ -531,8 +537,8 @@ class open_api(QAxWidget):
logger.debug("all_stocks 테이블을 생성합니다")
# 테이블 생성 후 초기화
self.invest_unit=0
self.db_to_transaction(0,0,0,0,0)
self.delete_all_stock("0")
self.db_to_all_stocks(0,0,0,0,0)
self.delete_all_stocks("0")
# setting_data에 invest_unit값이 없다면 설정
if not self.check_set_invest_unit():
......@@ -550,15 +556,16 @@ class open_api(QAxWidget):
self.sf.init_df_all_stocks() # all_stocks 테이블 데이터프레임 생성
# dataframe에 값 할당
self.sf.df_transaction.loc[0, 'order_num'] = order_num # 주문번호
self.sf.df_transaction.loc[0, 'code'] = str(code) # 종목코드
self.sf.df_transaction.loc[0, 'rate'] = float(rate) # 수익률
self.sf.df_transaction.loc[0, 'buy_date'] = self.today_detail # 구매날짜
self.sf.df_all_item.loc[0, 'chegyul_check'] = chegyul_check # 체결확인
self.sf.df_all_stocks.loc[0, 'order_num'] = order_num # 주문번호
self.sf.df_all_stocks.loc[0, 'code'] = str(code) # 종목코드
self.sf.df_all_stocks.loc[0, 'rate'] = float(rate) # 수익률
self.sf.df_all_stocks.loc[0, 'buy_date'] = self.today_detail # 구매날짜
self.sf.df_all_stocks.loc[0, 'chegyul_check'] = chegyul_check # 체결확인
self.sf.df_all_item.loc[0, 'invest_unit'] = self.invest_unit # 투자기준금액
self.sf.df_all_item.loc[0, 'purchase_price'] = purchase_price # 구매금액
self.sf.df_all_stocks.loc[0, 'invest_unit'] = self.invest_unit # 투자기준금액
self.sf.df_all_stocks.loc[0, 'purchase_price'] = purchase_price # 구매금액
# 신규매수
if order_num != 0:
recent_daily_buy_list_date=self.sf.get_recent_daily_buy_list_date()
# 구매 내역이 존재하는 경우 해당 데이터를 추가
......@@ -566,37 +573,36 @@ class open_api(QAxWidget):
# 특정 날짜, 특정 종목의 주가 데이터
df=self.sf.get_daily_buy_list_by_code(code,recent_daily_buy_list_date)
if not df.empty:
self.sf.df_transaction.loc[0, 'code_name'] = df.loc[0, 'code_name'] # 종목명
self.sf.df_all_stocks.loc[0, 'code_name'] = df.loc[0, 'code_name'] # 종목명
self.sf.df_transaction.loc[0, 'close'] = df.loc[0, 'close'] # 종가
self.sf.df_transaction.loc[0, 'open'] = df.loc[0, 'open'] # 시가
self.sf.df_transaction.loc[0, 'high'] = df.loc[0, 'high'] # 고가
self.sf.df_transaction.loc[0, 'low'] = df.loc[0, 'low'] # 저가
self.sf.df_transaction.loc[0, 'volume'] = df.loc[0, 'volume'] # 거래량
self.sf.df_all_stocks.loc[0, 'close'] = df.loc[0, 'close'] # 종가
self.sf.df_all_stocks.loc[0, 'open'] = df.loc[0, 'open'] # 시가
self.sf.df_all_stocks.loc[0, 'high'] = df.loc[0, 'high'] # 고가
self.sf.df_all_stocks.loc[0, 'low'] = df.loc[0, 'low'] # 저가
self.sf.df_all_stocks.loc[0, 'volume'] = df.loc[0, 'volume'] # 거래량
self.sf.df_transaction.loc[0,'d1_diff']=float(df.loc[0,'d1_diff']) # 전날대비 가격변동
self.sf.df_transaction.loc[0, 'd1_diff_rate'] = float(df.loc[0, 'd1_diff_rate']) # 전날대비 가격변동률
self.sf.df_all_stocks.loc[0,'d1_diff']=float(df.loc[0,'d1_diff']) # 전날대비 가격변동
self.sf.df_all_stocks.loc[0, 'd1_diff_rate'] = float(df.loc[0, 'd1_diff_rate']) # 전날대비 가격변동률
self.sf.df_transaction.loc[0, 'clo5'] = df.loc[0, 'clo5'] # 5일 이동평균선
self.sf.df_transaction.loc[0, 'clo10'] = df.loc[0, 'clo10'] # 10일 이동평균선
self.sf.df_transaction.loc[0, 'clo20'] = df.loc[0, 'clo20'] # 20일 이동평균선
self.sf.df_transaction.loc[0, 'clo60'] = df.loc[0, 'clo60'] # 60일 이동평균선
self.sf.df_transaction.loc[0, 'clo120'] = df.loc[0, 'clo120'] # 120일 이동평균선
self.sf.df_all_stocks.loc[0, 'clo5'] = df.loc[0, 'clo5'] # 5일 이동평균선
self.sf.df_all_stocks.loc[0, 'clo10'] = df.loc[0, 'clo10'] # 10일 이동평균선
self.sf.df_all_stocks.loc[0, 'clo20'] = df.loc[0, 'clo20'] # 20일 이동평균선
self.sf.df_all_stocks.loc[0, 'clo60'] = df.loc[0, 'clo60'] # 60일 이동평균선
self.sf.df_all_stocks.loc[0, 'clo120'] = df.loc[0, 'clo120'] # 120일 이동평균선
if df.loc[0, 'clo5_diff_rate'] is not None:
self.sf.df_transaction.loc[0, 'clo5_diff_rate'] = float(df.loc[0, 'clo5_diff_rate']) # 5일 이동평균선 변동률
self.sf.df_all_stocks.loc[0, 'clo5_diff_rate'] = float(df.loc[0, 'clo5_diff_rate']) # 5일 이동평균선 변동률
if df.loc[0, 'clo10_diff_rate'] is not None:
self.sf.df_transaction.loc[0, 'clo10_diff_rate'] = float(df.loc[0, 'clo10_diff_rate'])
self.sf.df_all_stocks.loc[0, 'clo10_diff_rate'] = float(df.loc[0, 'clo10_diff_rate'])
if df.loc[0, 'clo20_diff_rate'] is not None:
self.sf.df_transaction.loc[0, 'clo20_diff_rate'] = float(df.loc[0, 'clo20_diff_rate'])
self.sf.df_all_stocks.loc[0, 'clo20_diff_rate'] = float(df.loc[0, 'clo20_diff_rate'])
if df.loc[0, 'clo60_diff_rate'] is not None:
self.sf.df_transaction.loc[0, 'clo60_diff_rate'] = float(df.loc[0, 'clo60_diff_rate'])
self.sf.df_all_stocks.loc[0, 'clo60_diff_rate'] = float(df.loc[0, 'clo60_diff_rate'])
if df.loc[0, 'clo120_diff_rate'] is not None:
self.sf.df_transaction.loc[0, 'clo120_diff_rate'] = float(df.loc[0, 'clo120_diff_rate'])
self.sf.df_all_stocks.loc[0, 'clo120_diff_rate'] = float(df.loc[0, 'clo120_diff_rate'])
# null값을 0으로 변환
self.sf.df_all_item = self.sf.df_all_item.fillna(0)
self.sf.df_all_item.to_sql('transaction', self.engine_bot, if_exists='append', dtype={
self.sf.df_all_stocks = self.sf.df_all_stocks.fillna(0) # null값을 0으로 변환
self.sf.df_all_stocks.to_sql('all_stocks', self.engine_bot, if_exists='append', dtype={
'code_name': Text,
'rate': Float,
'sell_rate': Float,
......@@ -612,13 +618,13 @@ class open_api(QAxWidget):
})
# all_stocks(거래내역) 테이블에서 특정 종목을 삭제하는 함수
def delete_transaction_item(self,code):
def delete_all_stocks(self,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 limit 1"
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]
......@@ -629,31 +635,32 @@ class open_api(QAxWidget):
# 데이터베이스에서 invest_unit값을 가져오는 함수
def get_invest_unit(self):
logger.debug("-* get_invest_unit function *-")
query="select invest_unit from setting_data"
query="select invest_unit from setting_data limit 1"
result=self.engine_bot.execute(query).fetchall()
return result[0][0]
# invest_unit 항목 업데이트
# 업데이트 완료 후 set_invest_unit에 업데이트 날짜 저장
def set_invest_unit(self):
self.get_deposit()
self.get_balance()
self.total_invest=self.change_format(str(int(self.deposit)+int(self.total_purchase_price)))
self.get_d2_deposit()
self.check_balance()
self.total_invest=self.change_format(str(int(self.d2_deposit_before_format)+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}'"
self.engine_bot.execute(query)
# 예수금 조회 및 저장
def get_deposit(self):
def get_d2_deposit(self):
self.set_input_value("계좌번호",self.account_no)
self.set_input_value("비밀번호입력매체구분",00)
self.set_input_value("조회구분",1)
self.comm_rq_data("opw00001_req","opw00001",0,"2000")
# 잔고 조회 및 저장
def get_balance(self):
def check_balance(self):
self.reset_opw00018_output()
self.set_input_value("계좌번호",self.account_no)
self.comm_rq_data("opw00018_req","opw00018",0,"2000")
# 다음페이지가 존재할 경우 계속해서 조회
......@@ -669,8 +676,8 @@ class open_api(QAxWidget):
'present_price':[],'valuation_profit':[],'rate':[],'item_total_purchase':[]}
possessed_item=DataFrame(possessed_item_data,
columns=['date','code','code_name','holding_amount','purchase_price',
'present_price','valuation_profit','rate','item_total_purchase'])
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]
......@@ -708,20 +715,20 @@ class open_api(QAxWidget):
else:
chegyul_check=1
elif self._data['주문구분']=='':
self.db_to_transaction(self.today,item.code,0,0,item.rate)
self.db_to_all_stocks(self.today,item.code,0,0,item.rate)
continue
else:
continue
self.db_to_all_stocks(self.not_contract['주문번호'],item.code,chegyul_check,self.not_contract['체결가'],item.rate)
self.db_to_all_stocks(self._data['주문번호'],item.code,chegyul_check,self._data['체결가'],item.rate)
# posses_item 테이블을 업데이트 했을 경우 setting data 테이블에 업데이트 한 날짜를 표시
def setting_data_posses_stock(self):
query="update setting_data set posses_stocks='%s'"
self.engine_bot.execute(query%self.today)
# setting_data에 possessed_item 항목을 업데이트
def setting_data_possessed_item(self):
query=f"update setting_data set possessed_item={self.today} limit 1"
self.engine_bot.execute(query)
# 특정 종목의 일자별 거래 데이터 조회 함수
def get_date_data(self,code,code_name,date):
def get_total_data(self,code,code_name,date):
self.ohlcv=defaultdict(list)
self.set_input_value("종목코드",code)
self.set_input_value("기준일자",date)
......@@ -730,8 +737,8 @@ class open_api(QAxWidget):
# 한번에 600일치의 데이터를 가져온다
self.comm_rq_data("opt10081_req","opt10081",0,"0101")
# stock_info 테이블이 존재하지 않는다면 600일치 이상의 전체 데이터를 가져와야 하므로 다음 페이지가 존재하지 않을 때까지 조회
if not self.is_stock_table_exist(code_name):
# 종목 테이블이 존재하지 않는다면 600일치 이상의 전체 데이터를 가져와야 하므로 다음 페이지가 존재하지 않을 때까지 조회
if not self.is_craw_table_exist(code_name):
while self.remained_data==True:
self.set_input_value("종목코드",code)
self.set_input_value("기준일자",date)
......@@ -747,20 +754,20 @@ class open_api(QAxWidget):
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()
# daily_craw 데이터베이스에 종목 테이블이 존재하는지 확인하는 함수
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)).fetchall()
if result:
return True
else:
return False
# stock_info의 특정 종목 테이블에서 마지막으로 저장된 날짜를 가져오는 함수
# daily_craw의 특정 종목 테이블에서 마지막으로 저장된 날짜를 가져오는 함수
# 저장된 데이터가 없다면 '0'문자를 반환
def get_latest_date_from_stock_info(self,code_name):
def get_daily_craw_db_last_date(self,code_name):
query="select date from {} order by date desc limit 1"
result=self.engine_stock.execute(query.format(code_name)).fetchall()
result=self.engine_daily_craw.execute(query.format(code_name)).fetchall()
if len(result):
return result[0][0]
else:
......@@ -768,7 +775,7 @@ class open_api(QAxWidget):
# 체결이 완료되었는지 확인하고 all_stocks(거래내역)테이블을 업데이트
def check_chegyul(self):
query="select code from all_stocks where chegyul_check='1' and (sell_date='0' or sell_date=''"
query="select code from all_stocks where chegyul_check='1' and (sell_date='0' or sell_date='')"
result=self.engine_bot.execute(query).fetchall()
for r in result:
......@@ -779,40 +786,24 @@ class open_api(QAxWidget):
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"
# 거래가 완료된 항목은 주문번호 등 데이터가 존재하지 않음
# 과거에 거래한 내역이 존재하는 경우 opt10076 조회 시 주문번호 등의 데이터가 존재하지 않음
# 거래가 완료된 항목에 대해서 contract_check항목을 '0'으로 업데이트
if not self.not_contract['주문번호']:
if not self._data['주문번호']:
self.engine_bot.execute(query)
# 미체결 수량이 없을 경우 contract_check항목을 '0'으로 업데이트
elif self.not_contract['미체결수량']==0:
elif self._data['미체결수량']==0:
logger.debug("미체결 항목이 없습니다")
self.engine_bot.execute(query)
else:
logger.debug("미체결 종목이 존재합니다")
# 매도한 후, 보유종목(possessed_item) 내역과 거래내역(all_stocks) 내역의 데이터를 맞추는 함수
# 거래내역 테이블에서 매도처리되지 않은 항목을 업데이트
def sell_final_check2(self, code):
query = "UPDATE all_stocks SET " \
"chegyul_check='%s', sell_date ='%s' WHERE code='%s' and sell_date ='%s' ORDER BY buy_date desc LIMIT 1"
# 매도했을 경우 possessed_item(보유종목) 테이블에서 항목을 삭제
def delete_possessed_item(self,code):
query=f"delete from possessed_item where code={code}"
self.engine_bot.execute(query)
# 매도한 후 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)
# 매도한 항목을 possessed_item(보유종목) 테이블에서 삭제
self.engine_bot.execute(f"DELETE FROM possessed_item WHERE code = '{code}'")
self.engine_bot.execute(query % (0, self.today_detail, code, 0))
# 매도했을 때, possessed_item에서 삭제되었지만 all_stocks에 sell_date 칼럼이 업데이트 되지 않은 항목들을 처리하는 함수
def final_chegyul_check(self):
......@@ -830,25 +821,12 @@ class open_api(QAxWidget):
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):
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))
# 현재 보유하고 있는 종목의 수를 반환하는 함수
def get_count_possessed_item(self):
query="select count(*) from possessed_item"
result=self.engine_bot.execute(query).fetchall()
return result[0][0]
# setting_data에 possessed_item 항목을 업데이트
def set_setting_data_possessed_item(self):
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)
......@@ -876,12 +854,18 @@ class open_api(QAxWidget):
self.set_input_value("수정주가구분",1)
self.comm_rq_data("opt10080_req","opt10080",2,"1999")
if self.ohlcv['date'][-1]<self.craw_db_last_min:
if self.ohlcv['date'][-1] < self.craw_db_last_min:
break
"""
if self.craw_table_exist:
if self.ohlcv['date'][-1]<self.craw_db_last_min:
break
else:
break
"""
time.sleep(TR_REQ_TIME_INTERVAL)
if len(self.ohlcv['date']==0 or self.ohlcv['date'][0]==''):
if len(self.ohlcv['date'])==0 or self.ohlcv['date'][0]=='':
return []
if self.ohlcv['date']=='':
return []
......@@ -890,41 +874,6 @@ 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 = '{}'"
......@@ -945,7 +894,7 @@ class open_api(QAxWidget):
# min_craw 테이블에서 마지막에 저장한 행의 시간(분) 정보를 가져오는 함수
def get_craw_db_last_min(self,code_name):
query = f"SELECT date from `{code_name}` order by date desc limit 1"
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]
......@@ -953,15 +902,6 @@ class open_api(QAxWidget):
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)
......@@ -1040,24 +980,24 @@ class open_api(QAxWidget):
self.engine_bot.execute(query)
# possessed_item 테이블에 중복으로 데이터가 반영되는 것을 막기 위해 possessed_item에서 해당 종목 삭제
query = f"delete from possessed_item where code ={code}"
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):
# 잔액이 생겨서 다시 매수할 수 있는 상황이 되었을 경우, setting_data의 today_buy_stop 옵션을 0으로 변경
def buy_check_reset(self):
query = "UPDATE setting_data SET today_buy_stop='0' WHERE id='1'"
self.engine_bot.execute(query)
# 투자 가능한 잔액이 부족하거나, 매수할 종목이 더 이상 없는 경우 setting_data의 today_buy_stop옵션을 0으로 변경
# 더이상 매수하지 않음
# 투자 가능한 잔액이 부족하거나, 매수할 종목이 더 이상 없는 경우 setting_data의 today_buy_stop 옵션을 당일 날짜로 변경
# 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()
# 잔액이 부족하여 더이상 투자를 진행할 수 없는 경우, jango_is_null을 True로 설정한 후 False 반환
def jango_check(self):
self.get_d2_deposit()
try:
if int(self.d2_deposit_before_format) > (int(self.sf.limit_money)):
self.jango_is_null = False # trade 루프를 돌다가 잔액이 부족해졌을 때 루프를 빠져나오기 위한 변수
......@@ -1069,10 +1009,10 @@ class open_api(QAxWidget):
logger.critical(e)
# today_buy_stop 칼럼을 확인하는 함수
# setting_data테이블의 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]
result = self.engine_bot.execute(query).fetchall()[0][0]
if result != self.today:
return True
......@@ -1083,7 +1023,7 @@ class open_api(QAxWidget):
def buy_num_count(self,invest_unit,present_price):
return int(invest_unit/present_price)
# 거래 함수
# 매수 함수
def trade(self):
# 실시간 현재가(close)를 저장
# 현재시점의 종가(close)는 현재가와 같다
......@@ -1099,22 +1039,23 @@ class open_api(QAxWidget):
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-",
"매수 - 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,
self.send_order("send_order_req", "0101", self.account_no, 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:
if not self.jango_check() and self.sf.only_nine_buy:
# 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"):
......@@ -1145,10 +1086,10 @@ class open_api(QAxWidget):
self.trade()
# 모든 매수를 마쳤으면 더이상 매수 하지 않도록 설정
if self.sf.use_nine:
if self.sf.only_nine_buy:
self.buy_check_stop()
# 보유하고 있는 종목에 대해 all_stocks(거래내역) 테이블을 업데이트
# 보유하고 있는 종목에 대해 all_stocks(거래내역) 테이블의 rate(수익률) 관련 칼럼을 업데이트
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"
......@@ -1159,8 +1100,8 @@ class open_api(QAxWidget):
code = result[k][0]
holding_amount = result[k][1]
purchase_price = result[k][2]
present_price =result[k][3]
valuation_profit=result[k][4]
present_price = result[k][3]
valuation_profit = result[k][4]
rate = result[k][5]
item_total_purchase = result[k][6]
......@@ -1171,24 +1112,6 @@ class open_api(QAxWidget):
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, "종목코드")
......@@ -1313,8 +1236,11 @@ class open_api(QAxWidget):
for key in outputs:
if key not in ['주문번호','원주문번호','주문시간','종목코드']:
self._data[key]=int(self._get_comm_data(sTrCode,sRQName,0,key))
continue
try:
self._data[key]=int(self._get_comm_data(sTrCode,sRQName,0,key))
continue
except ValueError:
pass
self._data[key]=self._get_comm_data(sTrCode,sRQName,0,key)
# _opt10073 결과를 담는 변수를 초기화하는 함수
......@@ -1359,12 +1285,11 @@ class open_api(QAxWidget):
# 데이터베이스로부터 보유하고 있는 종목의 보유량(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}"
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로부터 받아온 데이터의 형식을 변형하는 함수
......@@ -1426,9 +1351,9 @@ class open_api(QAxWidget):
self.rq_count+=1
logger.debug(self.rq_count)
if self.rq_count==cf.max_api_call:
if self.rq_count==self.cf.max_api_call:
sys.exit(1)
if __name__=="__main__":
app=QApplication(sys.argv)
a=Open_Api()
\ No newline at end of file
a=open_api()
\ No newline at end of file
......
from PyQt5.QtWidgets import *
from PyQt5.QAxContainer import *
from PyQt5.QtCore import *
from PyQt5.QtTest import *
from pandas import DataFrame
import sys
import errCode
TR_REQ_TIME_INTERVAL = 3600
class OpenApi(QAxWidget):
def __init__(self):
super().__init__()
# event_loop list
self.tr_event_loop=QEventLoop()
self.login_event_loop=QEventLoop()
# variable list
self.account_no=None # 계좌번호
self.ohlcv = None # 거래정보(시가,종가,고가,저가,거래량)
self.remained_data=None # 다음페이지 존재여부
# screen number list
self.screen_data_req="0101" # 거래 데이터
self.create_instance()
self._signal_slots()
self.comm_connect() # 로그인
self.get_account_info() # 계좌정보 가져오기
# 주식일봉차트조회요청
def _opt10081(self,sRQName,sTrCode):
QTest.qWait(TR_REQ_TIME_INTERVAL)
cnt=self._get_repeat_cnt(sTrCode,sRQName)
for i in range(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['volumn'].append(int(volume))
# TR 요청을 처리하는 slot
# param sScrNo: 스크린번호
# sRQName: 요청했을 때 지은 이름
# sTrCode: 요청 id, tr코드
# sRecordName: 레코드 이름
# sPrevNext: 다음 페이지가 있는지 여부. "2" : 다음페이지 존재, "0" or "" : 다음페이지 없음
def _receive_tr_data(self,sScrNo,sRQName,sTrCode,sRecordName,sPrevNext):
if sPrevNext=='2':
self.remained_data=True
else:
self.remained_data=False
if sRQName=="opt10081":
print("==============주식일봉차트조회요청================")
self._opt10081(sRQName,sTrCode)
elif sRQName=="opw0001_req":
return
elif sRQName=="opw00018_req":
return
elif sRQName=="opt10074_req":
return
elif sRQName=="opw00015_req":
return
elif sRQName=="opt10076_req":
return
elif sRQName=="opt10073_req":
return
try:
self.tr_event_loop.exit()
except AttributeError:
pass
# 특정 종목의 일자별 거래 데이터 조회 함수
# param : code - 종목코드
# start - 기준일자
# return : df - 특정종목의 일자별 거래 데이터 목록
def get_total_data(self,code,start):
self.ohlcv = {'date': [], 'open': [], 'high': [], 'low': [], 'close': [], 'volume': []}
self._set_input_value("종목코드",code)
self._set_input_value("기준일자",start)
self._set_input_value("수정주가구분",1)
self._comm_rq_data("opt10081_req","opt10081",0,self.screen_data_req)
while self.remained_data:
self._set_input_value("종목코드",code)
self._set_input_value("기준일자",start)
self._set_input_value("수정주가구분",1)
self._comm_rq_data("opt10081_req","opt10081",2,self.screen_data_req)
# 데이터가 없거나, date=''일 경우 empty list를 반환
if len(self.ohlcv)==0:
return []
if self.ohlcv['date']=='':
return []
# 데이터를 DataFrame형태로 저장 및 반환
df=DataFrame(self.ohlcv,columns=['open','high','low','close','volume'],index=self.ohlcv['date'])
return df
# 특정 종목의 특정 날짜의 시가,종가,고가,저가,거래량 중 특정한 데이터를 반환하는 함수
# param : code - 종목코드
# : date - 조회날짜
# : option - open(시가)/close(종가)/high(고가)/low(저가)/volume(거래량)
# return : 조회한 데이터에 해당하는 값
# 값이 없거나, option이 오류일 경우 return False
def get_oneday_option_data(self,code,date,option):
self.ohlcv = {'date': [], 'open': [], 'high': [], 'low': [], 'close': [], 'volume': []}
self._set_input_value("종목코드",code)
self._set_input_value("기준일자",date)
self._set_input_value("수정주가구분",1)
self._comm_rq_data("opt10081_req","opt10081",0,self.screen_data_req)
if self.ohlcv['date']=="":
return False
df = DataFrame(self.ohlcv, columns=['open', 'high', 'low', 'close', 'volume'], index=self.ohlcv['date'])
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
# 사용자의 계좌정보 저장 및 출력
def get_account_info(self):
account=self.get_login_info("ACCNO")
self.account_no=account.split(";")[0]
print("======== 계좌번호 : ",self.account_no,"========")
# 원하는 사용자 정보 반환
# param : tag - ACCNO - 보유계좌리스트
# ACCOUNT_CNT - 보유계좌 수
# USER_ID - 사용자 ID
# USER_NAME - 사용자 이름
# KEY_BSECGB - 키보드 보안 해제 여부 (0 : 정상, 1: 해지)
# FIREW_SECGB - 방화벽 설정여부 (0 : 미설정, 1: 설정, 2 : 해지)
# GetServerGubun - 접속서버 구분 (1 : 모의투자, 나머지 : 실서버)
# return : tag를 통해 요청한 정보(ret) 반환
def get_login_info(self,tag):
try:
ret=self.dynamicCall("GetLoginInfo(QString)",tag)
return ret
except Exception as e:
print(e)
sys.exit()
# 키움 api를 사용하기 위한 ocx controller 저장
def create_instance(self):
try:
self.setControl("KHOPENAPI.KHOpenAPICtrl.1")
except Exception as e:
print(e)
sys.exit()
# event처리를 위한 slot
def _signal_slots(self):
try:
self.OnEventConnect.connect(self._login_slot)
self.OnReceiveTrData.connect(self._receive_tr_data)
except Exception as e:
print(e)
sys.exit()
# 수동 로그인설정인 경우 로그인창을 출력해서 로그인을 시도
# 자동로그인 설정인 경우 로그인창 출력없이 로그인을 시도
def comm_connect(self):
try:
self.dynamicCall("CommConnect()")
self.login_event_loop.exec_()
except Exception as e:
print(e)
sys.exit()
# 로그인 이벤트 처리 slot
# param : code - 로그인 성공 시 0
# 실패 시 에러코드 출력
def _login_slot(self,code):
try:
result=errCode.errors(code)
if code==0:
print("Connected",result[1])
else:
print("Failed to connect",result[1])
self.login_event_loop.exit()
except Exception as e:
print(e)
sys.exit()
# 조회요청시 TR의 Input값을 지정하는 함수
# param : sId - TR에 명시된 Input이름
# svalue - Input이름으로 지정한 값
def _set_input_value(self,sId,sValue):
try:
self.dynamicCall("SetInputValue(QString, QString)", sId, sValue)
except Exception as e:
print(e)
sys.exit()
# 조회요청함수
# param : sRQName - 사용자 구분명
# sTrCode - 조회하려는 TR이름
# nPrevNext - 연속조회여부
# sScreenNo - 화면번호
def _comm_rq_data(self,sRQName,sTrData,nPrevNext,sScrNo):
self.dynamicCall("CommRqData(QString, QString, int, QString", sRQName, sTrData, nPrevNext, sScrNo)
self.tr_event_loop.exec_()
# OnReceiveTRData()이벤트가 호출될때 조회데이터를 얻어오는 함수
# param : sTrCode - TR 이름
# sRecordName - 레코드이름
# nIndex - TR반복부
# sItemName - TR에서 얻어오려는 출력항목이름
def _get_comm_data(self,sTrCode,sRecordName,nIndex,sItemName):
ret = self.dynamicCall("GetCommData(QString, QString, int, QString", sTrCode, sRecordName, nIndex, sItemName)
return ret.strip()
# 조회수신한 멀티데이터의 갯수(반복)을 얻는다
# param : sTrCode - tr이름
# sRecordName - 레코드 이름
def _get_repeat_cnt(self,sTrCode,sRecordName):
try:
ret=self.dynamicCall("GetRepeatCnt(QString, QString)",sTrCode,sRecordName)
return ret
except Exception as e:
print(e)
sys.exit()
if __name__ == "__main__":
app = QApplication(sys.argv)
OpenApi()
\ No newline at end of file