이하영

simulator기능 구현

This diff is collapsed. Click to expand it.
1 from Open_Api import * 1 from Open_Api import *
2 from collections import OrderedDict 2 from collections import OrderedDict
3 from pandas import DataFrame 3 from pandas import DataFrame
4 +import time
4 5
5 from Daily_Info import * 6 from Daily_Info import *
6 from Stock_Info import * 7 from Stock_Info import *
...@@ -23,27 +24,40 @@ class Collector_Api(): ...@@ -23,27 +24,40 @@ class Collector_Api():
23 "today_buy_list,stock_info,min_info,daily_info from setting_data" 24 "today_buy_list,stock_info,min_info,daily_info from setting_data"
24 result=self.engine_bot.execute(query).fetchall() 25 result=self.engine_bot.execute(query).fetchall()
25 26
27 + today=self.open_api.today
28 +
26 # 오늘 날짜에 종목리스트가 업데이트 되지 않았다면 업데이트를 실행 29 # 오늘 날짜에 종목리스트가 업데이트 되지 않았다면 업데이트를 실행
27 - if result[0][0]!=self.open_api.today: 30 + if result[0][0]!=today:
28 self.open_api.get_balance() 31 self.open_api.get_balance()
29 self.get_code_list() 32 self.get_code_list()
30 33
31 # 계좌정보 업데이트 34 # 계좌정보 업데이트
32 - if result[0][1]!=self.open_api.today or result[0][2]!=self.open_api.today: 35 + if result[0][1]!=today or result[0][2]!=today:
33 self.check_balance() 36 self.check_balance()
34 self.open_api.set_per_invest() 37 self.open_api.set_per_invest()
35 38
36 # 현재 보유종목 테이블 업데이트 39 # 현재 보유종목 테이블 업데이트
37 - if result[0][2]!=self.open_api.today: 40 + if result[0][2]!=today:
38 self.open_api.get_posses_item() 41 self.open_api.get_posses_item()
39 self.open_api.setting_data_posses_stock() 42 self.open_api.setting_data_posses_stock()
40 43
41 - if result[0][3]!=self.open_api.today: 44 + # 수익률 테이블 업데이트
45 + if result[0][3]!=today:
42 self.update_today_profit_list() 46 self.update_today_profit_list()
43 47
44 - if result[0][7]!=self.open_api.today: 48 + # stock_info 테이블 업데이트
49 + if result[0][7]!=today:
50 + self.check_stock_info()
51 +
52 + if result[0][9]!=today:
45 self.check_daily_info() 53 self.check_daily_info()
46 54
55 + if result[0][4]!=today:
56 + self.open_api.check_contract()
57 + self.open_api.final_check_contract()
58 +
59 + if result[0][6]!=today:
60 + self.realtime_daily_info_check()
47 61
48 62
49 # 코스피, 코스닥 리스트 확인 및 데이터베이스 업데이트 63 # 코스피, 코스닥 리스트 확인 및 데이터베이스 업데이트
...@@ -256,7 +270,7 @@ class Collector_Api(): ...@@ -256,7 +270,7 @@ class Collector_Api():
256 query = "UPDATE setting_data SET today_profit='%s' limit 1" 270 query = "UPDATE setting_data SET today_profit='%s' limit 1"
257 self.engine_bot.execute(query % (self.open_api.today)) 271 self.engine_bot.execute(query % (self.open_api.today))
258 272
259 - def check_daily_info(self): 273 + def check_stock_info(self):
260 self.update_daily_info() 274 self.update_daily_info()
261 query="update setting_data set daily_info='%s'" 275 query="update setting_data set daily_info='%s'"
262 self.engine_bot.execute(query%(self.open_api.today)) 276 self.engine_bot.execute(query%(self.open_api.today))
...@@ -273,12 +287,102 @@ class Collector_Api(): ...@@ -273,12 +287,102 @@ class Collector_Api():
273 code=code_list[i][0] 287 code=code_list[i][0]
274 code_name=code_list[i][1] 288 code_name=code_list[i][1]
275 289
276 - check_item_sort=self.set_minute_info_table(code,code_name) 290 + check_item_sort=self.set_stock_info_table(code,code_name)
277 291
278 self.open_api.engine_daily.execute(query%(check_item_sort,code)) 292 self.open_api.engine_daily.execute(query%(check_item_sort,code))
279 293
280 - def set_minute_info_table(self,code,code_name): 294 + # stock_info 데이터베이스에 테이블 생성 및 추가
281 - df=self.open_api. 295 + def set_stock_info_table(self,code,code_name):
296 + df=self.open_api.get_date_data(code,code_name,self.open_api.today)
297 +
298 + df=DataFrame(df,
299 + columns=['date', 'check_item', 'code', 'code_name', 'd1_diff_rate',
300 + 'close', 'open', 'high','low','volume',
301 + 'clo5', 'clo10', 'clo20', 'clo60','clo120',
302 + 'pre_clo5', 'pre_clo10', 'pre_clo20', 'pre_clo60','pre_clo120',
303 + 'vol5', 'vol10', 'vol20', 'vol60','vol120'])
304 +
305 + df=df.sort_values(by=['date'],ascending=True)
306 +
307 + df['code']=code
308 + df['code_name']=code_name
309 + df['d1_diff_rate']=float((df['close']-df['close'].shift(1))/df['close'].shift(1)*100)
310 +
311 + df['clo5']=df['close'].rolling(window=5).mean()
312 + df['clo10']=df['close'].rolling(window=10).mean()
313 + df['clo20']=df['close'].rolling(window=20).mean()
314 + df['clo60']=df['close'].rolling(window=60).mean()
315 + df['clo120']=df['close'].rolling(window=120).mean()
316 +
317 + df['pre_col5']=df['clo5'].shift(1)
318 + df['pre_col10']=df['clo10'].shift(1)
319 + df['pre_col20']=df['clo20'].shift(1)
320 + df['pre_col60']=df['clo60'].shift(1)
321 + df['pre_col120']=df['clo120'].shift(1)
322 +
323 + df['vlo5']=df['volume'].rolling(window=5).mean()
324 + df['vlo10']=df['volume'].rolling(window=10).mean()
325 + df['vlo20']=df['volume'].rolling(window=20).mean()
326 + df['vlo60']=df['volume'].rolling(window=60).mean()
327 + df['vlo120']=df['volume'].rolling(window=120).mean()
328 +
329 + # 이미 테이블이 존재한다면 저장된 가장 최신의 날짜 이후의 데이터만 저장
330 + if self.engine_bot.dialect.has_table(self.open_api.engine_stock,code_name):
331 + df=df[df.date>self.open_api.get_latest_date_from_stock_info(code_name)]
332 +
333 + df[['date', 'check_item', 'code', 'code_name', 'd1_diff_rate',
334 + 'close', 'open', 'high','low','volume',
335 + 'clo5', 'clo10', 'clo20', 'clo60','clo120',
336 + 'pre_clo5', 'pre_clo10', 'pre_clo20', 'pre_clo60','yes_clo120',
337 + 'vol5', 'vol10', 'vol20', 'vol60','vol120']]=\
338 + df[['date', 'check_item', 'code', 'code_name', 'd1_diff_rate',
339 + 'close', 'open', 'high','low','volume',
340 + 'clo5', 'clo10', 'clo20', 'clo60','clo120',
341 + 'pre_clo5', 'pre_clo10', 'pre_clo20', 'pre_clo60','yes_clo120',
342 + 'vol5', 'vol10', 'vol20', 'vol60','vol120']].fillna(0).astype(int)
343 +
344 + df.to_sql(name=code_name,con=self.open_api.engine_stock,if_exists='append')
345 +
346 + check_item_sort = 1
347 + return check_item_sort
348 +
349 + def check_daily_info(self):
350 + self.daily_info.create_daily_table()
351 + query="update setting_data set daily_info='%s'"
352 + self.engine_bot.execute(query%(self.open_api.today))
353 +
354 + def realtime_daily_info_check(self):
355 + if self.open_api.simul_api.is_date_exist(self.open_api.today):
356 + self.open_api.simul_api.get_date_for_simul()
357 + self.open_api.simul_api.choose_to_buy_list(self.open_api.today,self.open_api.today,len(self.open_api.simul_api.date_rows))
358 +
359 +
360 +
361 +
362 +
363 + if self.open_api.sf.is_date_exist(self.open_api.today):
364 + logger.debug("daily_buy_list DB에 {} 테이블이 있습니다. jackbot DB에 realtime_daily_buy_list 테이블을 생성합니다".format(self.open_api.today))
365 +
366 + self.open_api.sf.get_date_for_simul()
367 + # 첫 번째 파라미터는 여기서는 의미가 없다.
368 + # 두 번째 파라미터에 오늘 일자를 넣는 이유는 매수를 하는 시점인 내일 기준으로 date_rows_yesterday가 오늘 이기 때문
369 + self.open_api.sf.db_to_realtime_daily_buy_list(self.open_api.today, self.open_api.today, len(self.open_api.sf.date_rows))
370 +
371 +
372 + # all_item_db에서 open, clo5~120, volume 등을 오늘 일자 데이터로 업데이트 한다.
373 + self.open_api.sf.update_all_db_by_date(self.open_api.today)
374 + self.open_api.rate_check()
375 + # realtime_daily_buy_list(매수 리스트) 테이블 세팅을 완료 했으면 아래 쿼리를 통해 setting_data의 today_buy_list에 오늘 날짜를 찍는다.
376 + sql = "UPDATE setting_data SET today_buy_list='%s' limit 1"
377 + self.engine_JB.execute(sql % (self.open_api.today))
378 + else:
379 + logger.debug(
380 + """daily_buy_list DB에 {} 테이블이 없습니다. jackbot DB에 realtime_daily_buy_list 테이블을 생성 할 수 없습니다.
381 + realtime_daily_buy_list는 daily_buy_list DB 안에 오늘 날짜 테이블이 만들어져야 생성이 됩니다.
382 + realtime_daily_buy_list 테이블을 생성할 수 없는 이유는 아래와 같습니다.
383 + 1. 장이 열리지 않은 날 혹은 15시 30분 ~ 23시 59분 사이에 콜렉터를 돌리지 않은 경우
384 + 2. 콜렉터를 오늘 날짜 까지 돌리지 않아 daily_buy_list의 오늘 날짜 테이블이 없는 경우
385 + """.format(self.open_api.today))
282 386
283 387
284 app=QApplication(sys.argv) 388 app=QApplication(sys.argv)
......
...@@ -329,13 +329,13 @@ class Open_Api(QAxWidget): ...@@ -329,13 +329,13 @@ class Open_Api(QAxWidget):
329 def create_setting_data(self): 329 def create_setting_data(self):
330 df_data={"limit_money":[],"per_invest":[],"max_per_invest":[],"min_per_invest":[],"set_per_invest":[], 330 df_data={"limit_money":[],"per_invest":[],"max_per_invest":[],"min_per_invest":[],"set_per_invest":[],
331 "code_update":[],"today_finish":[],"balance_to_db":[],"posses_stocks":[],"today_profit":[], 331 "code_update":[],"today_finish":[],"balance_to_db":[],"posses_stocks":[],"today_profit":[],
332 - "contract_check":[],"db_to_daily_info":[],"today_buy_list":[],"stock_info":[],"min_info":[], 332 + "contract_check":[],"final_contract_check":[],"db_to_daily_info":[],"today_buy_list":[],
333 - "daily_info":[]} 333 + "stock_info":[],"min_info":[],"daily_info":[]}
334 df_setting_data=DataFrame(df_data, 334 df_setting_data=DataFrame(df_data,
335 columns=['limit_money','per_invest','max_per_invest','min_per_invest','set_per_invest', 335 columns=['limit_money','per_invest','max_per_invest','min_per_invest','set_per_invest',
336 'code_update','today_finish','balance_to_db','posses_stocks','today_profit', 336 'code_update','today_finish','balance_to_db','posses_stocks','today_profit',
337 - 'contract_check','db_to_daily_info','today_buy_list','stock_info','min_info', 337 + 'contract_check','final_contract_check','db_to_daily_info','today_buy_list',
338 - 'daily_info']) 338 + 'stock_info','min_info','daily_info'])
339 339
340 df_setting_data.loc[0,'limit_money']=int(0) 340 df_setting_data.loc[0,'limit_money']=int(0)
341 df_setting_data.loc[0,'per_invest']=int(0) 341 df_setting_data.loc[0,'per_invest']=int(0)
...@@ -350,11 +350,12 @@ class Open_Api(QAxWidget): ...@@ -350,11 +350,12 @@ class Open_Api(QAxWidget):
350 df_setting_data.loc[0,'today_profit']=float(0) 350 df_setting_data.loc[0,'today_profit']=float(0)
351 351
352 df_setting_data.loc[0,'contract_check']=str(0) 352 df_setting_data.loc[0,'contract_check']=str(0)
353 + df_setting_data.loc[0,'final_contract_check']=str(0)
353 df_setting_data.loc[0,'db_to_daily_info']=str(0) 354 df_setting_data.loc[0,'db_to_daily_info']=str(0)
354 df_setting_data.loc[0,'today_buy_list']=str(0) 355 df_setting_data.loc[0,'today_buy_list']=str(0)
355 df_setting_data.loc[0,'stock_info']=str(0) 356 df_setting_data.loc[0,'stock_info']=str(0)
356 - df_setting_data.loc[0,'min_info']=str(0)
357 357
358 + df_setting_data.loc[0,'min_info']=str(0)
358 df_setting_data.loc[0,'daily_info']=str(0) 359 df_setting_data.loc[0,'daily_info']=str(0)
359 360
360 df_setting_data.to_sql("setting_data",self.engine_bot,if_exists="replace") 361 df_setting_data.to_sql("setting_data",self.engine_bot,if_exists="replace")
...@@ -588,9 +589,113 @@ class Open_Api(QAxWidget): ...@@ -588,9 +589,113 @@ class Open_Api(QAxWidget):
588 589
589 self.opt10073_output['multi'].append([date,code,code_name,amount,today_profit,earning_rate]) 590 self.opt10073_output['multi'].append([date,code,code_name,amount,today_profit,earning_rate])
590 591
592 + # 특정 종목의 일자별 거래 데이터 조회 함수
593 + def get_date_data(self,code,code_name,date):
594 + self.ohlcv=defaultdict(list)
595 + self.set_input_value("종목코드",code)
596 + self.set_input_value("기준일자",date)
597 + self.set_input_value("수정주가구분",1)
598 +
599 + # 한번에 600일치의 데이터를 가져온다
600 + self.comm_rq_data("opt10081_req","opt10081",0,"0101")
601 +
602 + # stock_info 테이블이 존재하지 않는다면 600일치 이상의 전체 데이터를 가져와야 하므로 다음 페이지가 존재하지 않을 때까지 조회
603 + if not self.is_stock_table_exist(code_name):
604 + while self.remained_data==True:
605 + self.set_input_value("종목코드",code)
606 + self.set_input_value("기준일자",date)
607 + self.set_input_value("수정주가구분",1)
608 + self.comm_rq_data("opt10081_req","opt10081",2,"0101")
609 +
610 + if len(self.ohlcv)==0:
611 + return []
612 + if self.ohlcv['date']=='':
613 + return []
614 +
615 + df=DataFrame(self.ohlcv,columns=['date','open','high','low','close','volume'])
616 +
617 + return df
618 +
619 + # stock_info 데이터베이스가 존재하는지 확인하는 함수
620 + def is_stock_table_exist(self,code_name):
621 + query = "select 1 from information_schema.tables where table_schema ='stock_info' and table_name = '{}'"
622 + result=self.engine_stock.execute(query.format(code_name)).fetchall()
623 + if result:
624 + return True
625 + else:
626 + return False
627 +
628 + # 주식 일봉차트 조회 요청
629 + # 주식의 날짜별 데이터를 저장하는 함수
630 + def collector_opt10081(self,sRQName,sTrCode):
631 + ohlcv_cnt=self._get_repeat_cnt(sTrCode,sRQName)
591 632
633 + for i in range(ohlcv_cnt):
634 + date=self._get_comm_data(sTrCode,sRQName,i,"일자")
635 + open=self._get_comm_data(sTrCode,sRQName,i,"시가")
636 + high=self._get_comm_data(sTrCode,sRQName,i,"고가")
637 + low=self._get_comm_data(sTrCode,sRQName,i,"저가")
638 + close=self._get_comm_data(sTrCode,sRQName,i,"현재가")
639 + volume=self._get_comm_data(sTrCode,sRQName,i,"거래량")
640 +
641 + self.ohlcv['date'].append(date)
642 + self.ohlcv['open'].append(int(open))
643 + self.ohlcv['high'].append(int(high))
644 + self.ohlcv['low'].append(int(low))
645 + self.ohlcv['close'].append(int(close))
646 + self.ohlcv['volume'].append(int(volume))
647 +
648 + # stock_info의 특정 종목 테이블에서 마지막으로 저장된 날짜를 가져오는 함수
649 + # 저장된 데이터가 없다면 '0'문자를 반환
650 + def get_latest_date_from_stock_info(self,code_name):
651 + query="select date from {} order by date desc limit 1"
652 + result=self.engine_stock.execute(query.format(code_name)).fetchall()
653 + if len(result):
654 + return result[0][0]
655 + else:
656 + return str(0)
657 +
658 + def check_contract(self):
659 + query="select code from transaction_history where contract_check='1' and (sell date='0' or sell_date='')"
660 + rows=self.engine_bot.execute(query).fetchall()
592 661
662 + for r in rows:
663 + self.set_input_value("종목코드",r.code)
664 + self.set_input_value("조회구분",1)
665 + self.set_input_value("계좌번호",self.account_no)
666 + self.comm_rq_data("opt10076_req","opt10076",0,"0350")
593 667
668 + query="update transaction_history set contract_check='0' where code='{}' and sell_date='0'"
669 + # 거래가 완료된 항목은 주문번호가 존재하지 않음
670 + # 거래가 완료된 항목에 대해서 contract_check항목을 '0'으로 업데이트
671 + if not self.not_contract['주문번호']:
672 + self.engine_bot.execute(query.format(r.code))
673 + # 미체결 수량이 없을 경우 contract_check항목을 '0'으로 업데이트
674 + elif self.not_contract['미체결수량']==0:
675 + logger.debug("미체결 항목이 없습니다")
676 + self.engine_bot.execute(query.format(r.code))
677 + else:
678 + logger.debug("미체결 종목이 존재합니다")
679 +
680 + # posses_item테이블에는 존재하지만 transaction_history테이블에 존재하지 않는 항목에 대해 업데이트
681 + def final_check_contract(self):
682 + query="select code from transaction_history" \
683 + "where" \
684 + "sell_date='%s' or sell_date='%s' and code not in (select code from posses_item) and contract_check!='%s'"
685 + result=self.engine_bot.execute(query%(0,"",1)).fetchall()
686 + num=len(result)
687 + for i in range(num):
688 + self.sell_check(result[i][0])
689 + query="update setting_data set final_contract_check='%s'"
690 + self.engine_bot.execute(query%(self.today))
691 +
692 + # 가지고 있던 종목을 판매하여 posses_item테이블에 내역이 존재하지 않지만 transaction_history에 매도처리가 되지 않은 항목 업데이트
693 + def sell_check(self,code):
694 + query="update transaction_history" \
695 + "set" \
696 + "contract_check='%s', sell_date='%s'" \
697 + "where code='%s' and sell_date='%s'"
698 + self.engine_bot.execute(query%(0,self.today_time,code,0))
594 699
595 700
596 if __name__=="__main__": 701 if __name__=="__main__":
......