이하영

딥러닝 알고리즘

...@@ -15,6 +15,7 @@ from library.open_api import setup_sql_mod ...@@ -15,6 +15,7 @@ from library.open_api import setup_sql_mod
15 listen(Pool,'connect',setup_sql_mod) 15 listen(Pool,'connect',setup_sql_mod)
16 listen(Pool,'first_connect',setup_sql_mod) 16 listen(Pool,'first_connect',setup_sql_mod)
17 17
18 +
18 def filter_by_ai(db_name,simul_num): 19 def filter_by_ai(db_name,simul_num):
19 from library.simulator_api import simulator_api 20 from library.simulator_api import simulator_api
20 sf=simulator_api(simul_num,'real',db_name) 21 sf=simulator_api(simul_num,'real',db_name)
...@@ -22,3 +23,119 @@ def filter_by_ai(db_name,simul_num): ...@@ -22,3 +23,119 @@ def filter_by_ai(db_name,simul_num):
22 ai_filter(sf.ai_num,sf.engine_simul) 23 ai_filter(sf.ai_num,sf.engine_simul)
23 except AttributeError: 24 except AttributeError:
24 sys.exit(1) 25 sys.exit(1)
26 +
27 +
28 +def lstm_algorithm(dataset,ai_setting):
29 + shuffled_data=load_data(df=dataset.copy(),n_steps=ai_setting['n_steps'],test_size=ai_setting['test_size'])
30 + model=create_model(n_steps=ai_setting['n_steps'],loss=ai_setting['loss'],units=ai_setting['units'],
31 + n_layers=ai_setting['n_layers'],dropout=ai_setting['dropout'])
32 + early_stopping=EarlyStopping(monitor='val_loss',patience=50)
33 + model.fit(shuffled_data["X_train"],shuffled_data['y_train'],
34 + batch_size=ai_setting['batch_size'],
35 + epochs=ai_setting['epochs'],
36 + validation_data=(shuffled_data['X_test'],shuffled_data['y_test']),
37 + callbacks=[early_stopping],
38 + verbose=1)
39 + scaled_data=load_data(df=dataset.copy(),n_steps=ai_setting['n_steps'],test_size=ai_setting['test_size'],
40 + shuffle=False)
41 + mse=evaluate(scaled_data,model)
42 +
43 + future_price=predict(scaled_data,model,n_steps=ai_setting['n_steps'])
44 + predicted_y=model.predict(scaled_data['X_test'])
45 + real_y=np.squeeze(scaled_data['column_scaler']['close'].inverse_transform(predicted_y))
46 +
47 + if ai_setting['is_used_predicted_close']:
48 + close=real_y[-1]
49 + else:
50 + close=dataset.iloc[-1]['close']
51 +
52 + ratio=(future_price-close)/close*100
53 +
54 + msg = f"After {ai_setting['lookup_step']}: {int(close)} -> {int(future_price)}"
55 +
56 + if ratio > 0: # lookup_step(분, 일) 후 상승 예상일 경우 출력 메시지
57 + msg += f' {ratio:.2f}% ⯅ '
58 + elif ratio < 0: # lookup_step(분, 일) 후 하락 예상일 경우 출력 메시지
59 + msg += f' {ratio:.2f}% ⯆ '
60 + print(msg, end=' ')
61 +
62 + return ai_setting['ratio_cut']
63 +
64 +
65 +def create_training_engine(db_name):
66 + return pymysql.connect(
67 + host=cf.db_ip,
68 + port=int(cf.db_port),
69 + user=cf.db_id,
70 + password=cf.db_pw,
71 + db=db_name,
72 + charset='utf8mb4',
73 + cursorclass=pymysql.cursors.DictCursor
74 + )
75 +
76 +
77 +def ai_filter(ai_filter_num,engine,until=datetime.datetime.today()):
78 + if ai_filter_num == 1:
79 + ai_setting = {
80 + "n_steps": 100, # 시퀀스 데이터를 몇개씩 담을지 설정
81 + "lookup_step": 30, # 단위 : 몇 일(분) 뒤의 종가를 예측 할 것 인지
82 + "test_size": 0.2, # train 범위
83 + "n_layers": 4, # LSTM layer 개수
84 + "units": 50, # LSTM neurons 개수
85 + "dropout": 0.2, # overfitting 방지를 위한 dropout
86 + "loss": "mse", # loss : 최적화 과정에서 최소화될 손실 함수
87 + "optimizer": "adam", # optimizer : 최적화 알고리즘 선택
88 + "batch_size": 64, # 각 학습 반복에 사용할 데이터 샘플 수
89 + "epochs": 400, # 몇 번 테스트 할지
90 + "ratio_cut": 3, # 단위:(%) lookup_step 기간 뒤 ratio_cut(%) 만큼 증가 할 것이 예측 된다면 매수
91 + "table": "daily_craw", # 분석 시 daily_craw(일별데이터)를 이용 할지 min_craw(분별데이터)를 이용 할지
92 + "is_used_predicted_close" : True # ratio(예상 상승률) 계산 시 예측 그래프의 close 값을 이용 할 경우 True,
93 + # 실제 close 값을 이용할 시 False
94 + }
95 + tr_engine = create_training_engine(ai_setting['table'])
96 +
97 + buy_list=None
98 +
99 + try:
100 + query="SELECT DISTINCT code_name FROM realtime_daily_buy_list"
101 + buy_list=engine.execute(query).fetchall()
102 + except (InternalError,ProgrammingError) as err:
103 + if 'Table' in str(err):
104 + print("realtime_daily_buy_list 테이블이 존재하지 않습니다.")
105 + else:
106 + print("autobot 데이터베이스가 존재하지 않습니다.")
107 + exit(1)
108 +
109 + feature_columns = ["close", "volume", "open", "high", "low"]
110 + filtered_list = []
111 + for code_name in buy_list:
112 + sql = """
113 + SELECT {} FROM `{}`
114 + WHERE STR_TO_DATE(date, '%Y%m%d%H%i') <= '{}'
115 + """.format(','.join(feature_columns), code_name, until)
116 + df = pd.read_sql(sql, tr_engine)
117 +
118 + # 데이터가 1000개(1000일 or 1000분)가 넘지 않으면 예측도가 떨어지기 때문에 필터링
119 + if len(df) < 1000:
120 + filtered_list.append(code_name)
121 + print(f"테스트 데이터가 적어서 realtime_daily_buy_list 에서 제외")
122 + continue
123 + try:
124 + filtered = lstm_algorithm(df, ai_setting)
125 + except ValueError:
126 + print(f"테스트 데이터가 적어서 realtime_daily_buy_list 에서 제외")
127 + filtered_list.append(code_name)
128 + continue
129 +
130 + print(code_name)
131 +
132 + # filtered가 True 이면 filtered_list(필터링 종목)에 해당 종목을 append
133 + if filtered:
134 + print(f"기준에 부합하지 않으므로 realtime_daily_buy_list 에서 제외")
135 + filtered_list.append(code_name)
136 +
137 + # filtered_list에 있는 종목들을 realtime_daily_buy_list(매수리스트)에서 제거
138 + if len(filtered_list) > 0:
139 + engine.execute(f"""
140 + DELETE FROM realtime_daily_buy_list WHERE code_name in ({','.join(map('"{}"'.format, filtered_list))})
141 + """)
...\ No newline at end of file ...\ No newline at end of file
......
This diff is collapsed. Click to expand it.
...@@ -326,7 +326,8 @@ class collector_api(): ...@@ -326,7 +326,8 @@ class collector_api():
326 "clo5_diff_rate", "clo10_diff_rate","clo20_diff_rate", "clo60_diff_rate", 326 "clo5_diff_rate", "clo10_diff_rate","clo20_diff_rate", "clo60_diff_rate",
327 "clo120_diff_rate", 327 "clo120_diff_rate",
328 'yes_clo5', 'yes_clo10', 'yes_clo20', 'yes_clo60', 'yes_clo120', 328 'yes_clo5', 'yes_clo10', 'yes_clo20', 'yes_clo60', 'yes_clo120',
329 - 'vol5', 'vol10', 'vol20', 'vol60', 'vol120', 'vol80' 329 + 'vol5', 'vol10', 'vol20', 'vol60', 'vol120',
330 + 'd1_diff','dn_diff'
330 ]) 331 ])
331 332
332 df_temp = df_temp.sort_values(by=['date'], ascending=True) 333 df_temp = df_temp.sort_values(by=['date'], ascending=True)
...@@ -365,6 +366,9 @@ class collector_api(): ...@@ -365,6 +366,9 @@ class collector_api():
365 df_temp['vol60'] = df_temp['volume'].rolling(window=60).mean() 366 df_temp['vol60'] = df_temp['volume'].rolling(window=60).mean()
366 df_temp['vol120'] = df_temp['volume'].rolling(window=120).mean() 367 df_temp['vol120'] = df_temp['volume'].rolling(window=120).mean()
367 368
369 + df_temp['d1_diff']=df_temp['close']-df_temp['close'].shift(1)
370 + df_temp['dn_diff']=df_temp['close']-df_temp['close'].shift(14)
371 +
368 # daily_craw테이블이 존재할 경우, 저장되어있는 날짜 이후의 값을 저장 372 # daily_craw테이블이 존재할 경우, 저장되어있는 날짜 이후의 값을 저장
369 if self.engine_bot.dialect.has_table(self.open_api.engine_daily_craw, code_name): 373 if self.engine_bot.dialect.has_table(self.open_api.engine_daily_craw, code_name):
370 df_temp = df_temp[df_temp.date > self.open_api.get_daily_craw_db_last_date(code_name)] 374 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(): ...@@ -587,3 +591,39 @@ class collector_api():
587 self.open_api.comm_rq_data("opt10074_req", "opt10074", 2, "0329") 591 self.open_api.comm_rq_data("opt10074_req", "opt10074", 2, "0329")
588 592
589 self.db_to_jango() 593 self.db_to_jango()
594 +
595 + def get_code_list(self):
596 + self.dc.get_item_kospi()
597 + self.stock_to_db(self.dc.code_df_kospi,"item_all")
598 +
599 + def stock_to_db(self,origin_df,type):
600 + checking_stocks=['kospi']
601 + stock_df=DataFrame()
602 + stock_df['code']=origin_df['code']
603 + name_list=[]
604 + for info in origin_df.itertuples():
605 + kiwoom_name = self.open_api.dynamicCall("GetMasterCodeName(QString)", info.code).strip()
606 + name_list.append(kiwoom_name)
607 + if not kiwoom_name:
608 + if type in checking_stocks:
609 + logger.error(
610 + f"종목명이 비어있습니다. - "
611 + f"종목: {info.code_name}, "
612 + f"코드: {info.code}"
613 + )
614 +
615 + stock_df['code_name']=name_list
616 + stock_df['check_item']=0
617 +
618 + if type in checking_stocks:
619 + stock_df=stock_df[stock_df['code_name'].map(len)>0]
620 +
621 + if type=="item_all":
622 + stock_df['check_daily_crawler']='0'
623 + stock_df['check_min_crawler']='0'
624 +
625 + dtypes=dict(zip(list(stock_df.columns),[Text]*len(stock_df.columns)))
626 + dtypes['check_item']=Integer
627 +
628 + stock_df.to_sql(f'stock_{type}',self.open_api.engine_daily_buy_list,if_exists='replace',dtype=dtypes)
629 + return stock_df
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -64,7 +64,7 @@ class daily_buy_list(): ...@@ -64,7 +64,7 @@ class daily_buy_list():
64 if not self.is_table_exist_daily_craw(code, code_name): 64 if not self.is_table_exist_daily_craw(code, code_name):
65 continue 65 continue
66 66
67 - query = f"select * from {self.stock_item_all[i][0]} where date = '{self.date_rows[k][0]}' " \ 67 + query = f"select * from `{self.stock_item_all[i][0]}` where date = '{self.date_rows[k][0]}' " \
68 f"group by date" 68 f"group by date"
69 rows = self.engine_daily_craw.execute(query).fetchall() 69 rows = self.engine_daily_craw.execute(query).fetchall()
70 multi_list += rows 70 multi_list += rows
...@@ -72,13 +72,14 @@ class daily_buy_list(): ...@@ -72,13 +72,14 @@ class daily_buy_list():
72 if len(multi_list) != 0: 72 if len(multi_list) != 0:
73 df_temp = DataFrame(multi_list, 73 df_temp = DataFrame(multi_list,
74 columns=['index', 'date', 'check_item', 'code', 'code_name', 74 columns=['index', 'date', 'check_item', 'code', 'code_name',
75 - 'd1_diff','d1_diff_rate', 75 + 'd1_diff_rate',
76 'close', 'open', 'high', 'low','volume', 76 'close', 'open', 'high', 'low','volume',
77 'clo5', 'clo10', 'clo20', 'clo60', 'clo120', 77 'clo5', 'clo10', 'clo20', 'clo60', 'clo120',
78 "clo5_diff_rate", "clo10_diff_rate","clo20_diff_rate", 78 "clo5_diff_rate", "clo10_diff_rate","clo20_diff_rate",
79 "clo60_diff_rate", "clo120_diff_rate", 79 "clo60_diff_rate", "clo120_diff_rate",
80 'yes_clo5', 'yes_clo10', 'yes_clo20', 'yes_clo60', 'yes_clo120', 80 'yes_clo5', 'yes_clo10', 'yes_clo20', 'yes_clo60', 'yes_clo120',
81 - 'vol5', 'vol10', 'vol20', 'vol60', 'vol120' 81 + 'vol5', 'vol10', 'vol20', 'vol60', 'vol120',
82 + 'd1_diff','dn_diff'
82 ]) 83 ])
83 84
84 df_temp.to_sql(name=self.date_rows[k][0], con=self.engine_daily_buy_list, if_exists='replace') 85 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(): ...@@ -47,3 +47,15 @@ class daily_crawler():
47 return True 47 return True
48 else: 48 else:
49 return False 49 return False
50 +
51 + def get_item_kospi(self):
52 + 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자리를 맞춰주기 위해 설정해줌
53 +
54 + # 6자리 만들고 앞에 0을 붙인다.
55 + self.code_df_kospi.종목코드 = self.code_df_kospi.종목코드.map('{:06d}'.format)
56 +
57 + # 회사명과 종목코드를 제외한 칼럼은 삭제
58 + self.code_df_kospi = self.code_df_kospi[['회사명', '종목코드']]
59 +
60 + # 한글로된 컬럼명을 영어로 변경
61 + self.code_df_kospi = self.code_df_kospi.rename(columns={'회사명': 'code_name', '종목코드': 'code'})
......
...@@ -126,6 +126,7 @@ class open_api(QAxWidget): ...@@ -126,6 +126,7 @@ class open_api(QAxWidget):
126 self.login_event_loop.exit() 126 self.login_event_loop.exit()
127 except Exception as e: 127 except Exception as e:
128 logger.critical(e) 128 logger.critical(e)
129 + sys.exit()
129 130
130 # 사용자의 계좌정보 저장 및 출력 131 # 사용자의 계좌정보 저장 및 출력
131 def account_info(self): 132 def account_info(self):
...@@ -243,12 +244,12 @@ class open_api(QAxWidget): ...@@ -243,12 +244,12 @@ class open_api(QAxWidget):
243 # 해당 종목의 체결 실패 내역이 없다면 244 # 해당 종목의 체결 실패 내역이 없다면
244 # all_stocks 테이블에 업데이트. 정상 체결 시 chegyul_check=0 245 # all_stocks 테이블에 업데이트. 정상 체결 시 chegyul_check=0
245 if chegyul_fail_amount=="0": 246 if chegyul_fail_amount=="0":
246 - logger.debug(code, "체결 완료") 247 + logger.debug(code+ "체결 완료")
247 self.db_to_all_stocks(order_num,code,0,purchase_price,0) 248 self.db_to_all_stocks(order_num,code,0,purchase_price,0)
248 # 체결 실패 내역이 존재한다면 249 # 체결 실패 내역이 존재한다면
249 # all_stocks 테이블에 업데이트. 미체결 시 chegyul_check=1 250 # all_stocks 테이블에 업데이트. 미체결 시 chegyul_check=1
250 else: 251 else:
251 - logger.debug(code,"미체결") 252 + logger.debug(code+"미체결")
252 self.db_to_all_stocks(order_num,code,1,purchase_price,0) 253 self.db_to_all_stocks(order_num,code,1,purchase_price,0)
253 254
254 # 매수하는 경우 255 # 매수하는 경우
...@@ -281,7 +282,7 @@ class open_api(QAxWidget): ...@@ -281,7 +282,7 @@ class open_api(QAxWidget):
281 # 국내주식 잔고전달 282 # 국내주식 잔고전달
282 elif sGubun=="1": 283 elif sGubun=="1":
283 chegyul_fail_amount=self.get_chejan_data(902) 284 chegyul_fail_amount=self.get_chejan_data(902)
284 - logger.debug("미체결 수량",chegyul_fail_amount) 285 + logger.debug("미체결 수량 : "+chegyul_fail_amount)
285 286
286 else: 287 else:
287 logger.debug("Invlid _receive_chejan_data") 288 logger.debug("Invlid _receive_chejan_data")
...@@ -784,7 +785,7 @@ class open_api(QAxWidget): ...@@ -784,7 +785,7 @@ class open_api(QAxWidget):
784 self.set_input_value("계좌번호",self.account_no) 785 self.set_input_value("계좌번호",self.account_no)
785 self.comm_rq_data("opt10076_req","opt10076",0,"0350") 786 self.comm_rq_data("opt10076_req","opt10076",0,"0350")
786 787
787 - query=f"update all_stocks set chegyul_check='0' where code='{r.code}' and sell_data='0' " \ 788 + query=f"update all_stocks set chegyul_check='0' where code='{r.code}' and sell_date='0' " \
788 f"order by buy_date desc limit 1" 789 f"order by buy_date desc limit 1"
789 # 과거에 거래한 내역이 존재하는 경우 opt10076 조회 시 주문번호 등의 데이터가 존재하지 않음 790 # 과거에 거래한 내역이 존재하는 경우 opt10076 조회 시 주문번호 등의 데이터가 존재하지 않음
790 # 거래가 완료된 항목에 대해서 contract_check항목을 '0'으로 업데이트 791 # 거래가 완료된 항목에 대해서 contract_check항목을 '0'으로 업데이트
......
...@@ -14,7 +14,7 @@ class Trader(QMainWindow): ...@@ -14,7 +14,7 @@ class Trader(QMainWindow):
14 14
15 self.market_start_time=QTime(9,0,0) # 장시작 시간 15 self.market_start_time=QTime(9,0,0) # 장시작 시간
16 self.market_end_time=QTime(15,30,0) # 장마감 시간 16 self.market_end_time=QTime(15,30,0) # 장마감 시간
17 - self.buy_end_time=QTime(9,6,0) # 매수를 몇 시까지 할지 17 + self.buy_end_time=QTime(9,30,0) # 매수를 몇 시까지 할지
18 18
19 # 매수 함수 19 # 매수 함수
20 def auto_trade_stock(self): 20 def auto_trade_stock(self):
...@@ -42,6 +42,7 @@ class Trader(QMainWindow): ...@@ -42,6 +42,7 @@ class Trader(QMainWindow):
42 self.open_api.final_chegyul_check() 42 self.open_api.final_chegyul_check()
43 # 매도리스트 저장 43 # 매도리스트 저장
44 self.get_sell_list_trade() 44 self.get_sell_list_trade()
45 + print(self.sell_list)
45 46
46 for i in range(len(self.sell_list)): 47 for i in range(len(self.sell_list)):
47 get_sell_code=self.sell_list[i][0] # 종목코드 48 get_sell_code=self.sell_list[i][0] # 종목코드
......