Showing
4 changed files
with
223 additions
and
14 deletions
This diff is collapsed. Click to expand it.
File moved
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__": | ... | ... |
-
Please register or login to post a comment