이하영

딥러닝 알고리즘

......@@ -15,6 +15,7 @@ from library.open_api import setup_sql_mod
listen(Pool,'connect',setup_sql_mod)
listen(Pool,'first_connect',setup_sql_mod)
def filter_by_ai(db_name,simul_num):
from library.simulator_api import simulator_api
sf=simulator_api(simul_num,'real',db_name)
......@@ -22,3 +23,119 @@ def filter_by_ai(db_name,simul_num):
ai_filter(sf.ai_num,sf.engine_simul)
except AttributeError:
sys.exit(1)
def lstm_algorithm(dataset,ai_setting):
shuffled_data=load_data(df=dataset.copy(),n_steps=ai_setting['n_steps'],test_size=ai_setting['test_size'])
model=create_model(n_steps=ai_setting['n_steps'],loss=ai_setting['loss'],units=ai_setting['units'],
n_layers=ai_setting['n_layers'],dropout=ai_setting['dropout'])
early_stopping=EarlyStopping(monitor='val_loss',patience=50)
model.fit(shuffled_data["X_train"],shuffled_data['y_train'],
batch_size=ai_setting['batch_size'],
epochs=ai_setting['epochs'],
validation_data=(shuffled_data['X_test'],shuffled_data['y_test']),
callbacks=[early_stopping],
verbose=1)
scaled_data=load_data(df=dataset.copy(),n_steps=ai_setting['n_steps'],test_size=ai_setting['test_size'],
shuffle=False)
mse=evaluate(scaled_data,model)
future_price=predict(scaled_data,model,n_steps=ai_setting['n_steps'])
predicted_y=model.predict(scaled_data['X_test'])
real_y=np.squeeze(scaled_data['column_scaler']['close'].inverse_transform(predicted_y))
if ai_setting['is_used_predicted_close']:
close=real_y[-1]
else:
close=dataset.iloc[-1]['close']
ratio=(future_price-close)/close*100
msg = f"After {ai_setting['lookup_step']}: {int(close)} -> {int(future_price)}"
if ratio > 0: # lookup_step(분, 일) 후 상승 예상일 경우 출력 메시지
msg += f' {ratio:.2f}% ⯅ '
elif ratio < 0: # lookup_step(분, 일) 후 하락 예상일 경우 출력 메시지
msg += f' {ratio:.2f}% ⯆ '
print(msg, end=' ')
return ai_setting['ratio_cut']
def create_training_engine(db_name):
return pymysql.connect(
host=cf.db_ip,
port=int(cf.db_port),
user=cf.db_id,
password=cf.db_pw,
db=db_name,
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
def ai_filter(ai_filter_num,engine,until=datetime.datetime.today()):
if ai_filter_num == 1:
ai_setting = {
"n_steps": 100, # 시퀀스 데이터를 몇개씩 담을지 설정
"lookup_step": 30, # 단위 : 몇 일(분) 뒤의 종가를 예측 할 것 인지
"test_size": 0.2, # train 범위
"n_layers": 4, # LSTM layer 개수
"units": 50, # LSTM neurons 개수
"dropout": 0.2, # overfitting 방지를 위한 dropout
"loss": "mse", # loss : 최적화 과정에서 최소화될 손실 함수
"optimizer": "adam", # optimizer : 최적화 알고리즘 선택
"batch_size": 64, # 각 학습 반복에 사용할 데이터 샘플 수
"epochs": 400, # 몇 번 테스트 할지
"ratio_cut": 3, # 단위:(%) lookup_step 기간 뒤 ratio_cut(%) 만큼 증가 할 것이 예측 된다면 매수
"table": "daily_craw", # 분석 시 daily_craw(일별데이터)를 이용 할지 min_craw(분별데이터)를 이용 할지
"is_used_predicted_close" : True # ratio(예상 상승률) 계산 시 예측 그래프의 close 값을 이용 할 경우 True,
# 실제 close 값을 이용할 시 False
}
tr_engine = create_training_engine(ai_setting['table'])
buy_list=None
try:
query="SELECT DISTINCT code_name FROM realtime_daily_buy_list"
buy_list=engine.execute(query).fetchall()
except (InternalError,ProgrammingError) as err:
if 'Table' in str(err):
print("realtime_daily_buy_list 테이블이 존재하지 않습니다.")
else:
print("autobot 데이터베이스가 존재하지 않습니다.")
exit(1)
feature_columns = ["close", "volume", "open", "high", "low"]
filtered_list = []
for code_name in buy_list:
sql = """
SELECT {} FROM `{}`
WHERE STR_TO_DATE(date, '%Y%m%d%H%i') <= '{}'
""".format(','.join(feature_columns), code_name, until)
df = pd.read_sql(sql, tr_engine)
# 데이터가 1000개(1000일 or 1000분)가 넘지 않으면 예측도가 떨어지기 때문에 필터링
if len(df) < 1000:
filtered_list.append(code_name)
print(f"테스트 데이터가 적어서 realtime_daily_buy_list 에서 제외")
continue
try:
filtered = lstm_algorithm(df, ai_setting)
except ValueError:
print(f"테스트 데이터가 적어서 realtime_daily_buy_list 에서 제외")
filtered_list.append(code_name)
continue
print(code_name)
# filtered가 True 이면 filtered_list(필터링 종목)에 해당 종목을 append
if filtered:
print(f"기준에 부합하지 않으므로 realtime_daily_buy_list 에서 제외")
filtered_list.append(code_name)
# filtered_list에 있는 종목들을 realtime_daily_buy_list(매수리스트)에서 제거
if len(filtered_list) > 0:
engine.execute(f"""
DELETE FROM realtime_daily_buy_list WHERE code_name in ({','.join(map('"{}"'.format, filtered_list))})
""")
\ No newline at end of file
......
This diff is collapsed. Click to expand it.
......@@ -326,7 +326,8 @@ class collector_api():
"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', 'vol80'
'vol5', 'vol10', 'vol20', 'vol60', 'vol120',
'd1_diff','dn_diff'
])
df_temp = df_temp.sort_values(by=['date'], ascending=True)
......@@ -365,6 +366,9 @@ class collector_api():
df_temp['vol60'] = df_temp['volume'].rolling(window=60).mean()
df_temp['vol120'] = df_temp['volume'].rolling(window=120).mean()
df_temp['d1_diff']=df_temp['close']-df_temp['close'].shift(1)
df_temp['dn_diff']=df_temp['close']-df_temp['close'].shift(14)
# daily_craw테이블이 존재할 경우, 저장되어있는 날짜 이후의 값을 저장
if self.engine_bot.dialect.has_table(self.open_api.engine_daily_craw, code_name):
df_temp = df_temp[df_temp.date > self.open_api.get_daily_craw_db_last_date(code_name)]
......@@ -587,3 +591,39 @@ class collector_api():
self.open_api.comm_rq_data("opt10074_req", "opt10074", 2, "0329")
self.db_to_jango()
def get_code_list(self):
self.dc.get_item_kospi()
self.stock_to_db(self.dc.code_df_kospi,"item_all")
def stock_to_db(self,origin_df,type):
checking_stocks=['kospi']
stock_df=DataFrame()
stock_df['code']=origin_df['code']
name_list=[]
for info in origin_df.itertuples():
kiwoom_name = self.open_api.dynamicCall("GetMasterCodeName(QString)", info.code).strip()
name_list.append(kiwoom_name)
if not kiwoom_name:
if type in checking_stocks:
logger.error(
f"종목명이 비어있습니다. - "
f"종목: {info.code_name}, "
f"코드: {info.code}"
)
stock_df['code_name']=name_list
stock_df['check_item']=0
if type in checking_stocks:
stock_df=stock_df[stock_df['code_name'].map(len)>0]
if type=="item_all":
stock_df['check_daily_crawler']='0'
stock_df['check_min_crawler']='0'
dtypes=dict(zip(list(stock_df.columns),[Text]*len(stock_df.columns)))
dtypes['check_item']=Integer
stock_df.to_sql(f'stock_{type}',self.open_api.engine_daily_buy_list,if_exists='replace',dtype=dtypes)
return stock_df
\ No newline at end of file
......
......@@ -64,7 +64,7 @@ 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
......@@ -72,13 +72,14 @@ class daily_buy_list():
if len(multi_list) != 0:
df_temp = DataFrame(multi_list,
columns=['index', 'date', 'check_item', 'code', 'code_name',
'd1_diff','d1_diff_rate',
'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'
'vol5', 'vol10', 'vol20', 'vol60', 'vol120',
'd1_diff','dn_diff'
])
df_temp.to_sql(name=self.date_rows[k][0], con=self.engine_daily_buy_list, if_exists='replace')
......
......@@ -47,3 +47,15 @@ class daily_crawler():
return True
else:
return False
def get_item_kospi(self):
self.code_df_kospi = pd.read_html('http://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13&marketType=stockMkt',header=0)[0] # 종목코드가 6자리이기 때문에 6자리를 맞춰주기 위해 설정해줌
# 6자리 만들고 앞에 0을 붙인다.
self.code_df_kospi.종목코드 = self.code_df_kospi.종목코드.map('{:06d}'.format)
# 회사명과 종목코드를 제외한 칼럼은 삭제
self.code_df_kospi = self.code_df_kospi[['회사명', '종목코드']]
# 한글로된 컬럼명을 영어로 변경
self.code_df_kospi = self.code_df_kospi.rename(columns={'회사명': 'code_name', '종목코드': 'code'})
......
......@@ -126,6 +126,7 @@ class open_api(QAxWidget):
self.login_event_loop.exit()
except Exception as e:
logger.critical(e)
sys.exit()
# 사용자의 계좌정보 저장 및 출력
def account_info(self):
......@@ -243,12 +244,12 @@ class open_api(QAxWidget):
# 해당 종목의 체결 실패 내역이 없다면
# all_stocks 테이블에 업데이트. 정상 체결 시 chegyul_check=0
if chegyul_fail_amount=="0":
logger.debug(code, "체결 완료")
logger.debug(code+ "체결 완료")
self.db_to_all_stocks(order_num,code,0,purchase_price,0)
# 체결 실패 내역이 존재한다면
# all_stocks 테이블에 업데이트. 미체결 시 chegyul_check=1
else:
logger.debug(code,"미체결")
logger.debug(code+"미체결")
self.db_to_all_stocks(order_num,code,1,purchase_price,0)
# 매수하는 경우
......@@ -281,7 +282,7 @@ class open_api(QAxWidget):
# 국내주식 잔고전달
elif sGubun=="1":
chegyul_fail_amount=self.get_chejan_data(902)
logger.debug("미체결 수량",chegyul_fail_amount)
logger.debug("미체결 수량 : "+chegyul_fail_amount)
else:
logger.debug("Invlid _receive_chejan_data")
......@@ -784,7 +785,7 @@ class open_api(QAxWidget):
self.set_input_value("계좌번호",self.account_no)
self.comm_rq_data("opt10076_req","opt10076",0,"0350")
query=f"update all_stocks set chegyul_check='0' where code='{r.code}' and sell_data='0' " \
query=f"update all_stocks set chegyul_check='0' where code='{r.code}' and sell_date='0' " \
f"order by buy_date desc limit 1"
# 과거에 거래한 내역이 존재하는 경우 opt10076 조회 시 주문번호 등의 데이터가 존재하지 않음
# 거래가 완료된 항목에 대해서 contract_check항목을 '0'으로 업데이트
......
......@@ -14,7 +14,7 @@ class Trader(QMainWindow):
self.market_start_time=QTime(9,0,0) # 장시작 시간
self.market_end_time=QTime(15,30,0) # 장마감 시간
self.buy_end_time=QTime(9,6,0) # 매수를 몇 시까지 할지
self.buy_end_time=QTime(9,30,0) # 매수를 몇 시까지 할지
# 매수 함수
def auto_trade_stock(self):
......@@ -42,6 +42,7 @@ class Trader(QMainWindow):
self.open_api.final_chegyul_check()
# 매도리스트 저장
self.get_sell_list_trade()
print(self.sell_list)
for i in range(len(self.sell_list)):
get_sell_code=self.sell_list[i][0] # 종목코드
......