이하영

tr관련 함수 추가

1 +import logging.handlers
2 +import sys
3 +
4 +# formmater 생성
5 +formatter = logging.Formatter('[%(levelname)s|%(filename)s:%(lineno)s] %(asctime)s > %(message)s')
6 +
7 +# logger 인스턴스를 생성 및 로그 레벨 설정
8 +logger = logging.getLogger("crumbs")
9 +logger.setLevel(logging.DEBUG)
10 +streamHandler = logging.StreamHandler()
11 +streamHandler.setFormatter(formatter)
12 +logger.addHandler(streamHandler)
...\ No newline at end of file ...\ No newline at end of file
1 +import datetime
2 +from sqlalchemy import *
3 +import pymysql
4 +from pandas import DataFrame
5 +
6 +import config
7 +
8 +class Simulator_Api:
9 + def __init__(self,simul_num,op,db_name):
10 + self.simul_num=int(simul_num)
11 +
12 + if op=="real":
13 + self.op='real'
14 + self.simul_reset=False
15 + self.db_name=db_name
16 + self.set_variable()
17 +
18 + def set_date(self):
19 + self.today=datetime.datetime.today().strftime("%Y%m%d")
20 +
21 + def set_variable(self):
22 + self.set_date()
23 + self.set_database()
24 +
25 + # 매수/매도 알고리즘 선택 -> 차후 알고리즘 별로 구현 및 재설정
26 + self.buy_algorithm=1
27 + self.sell_algorithm=1
28 +
29 + # 특정 데이터베이스 내에 특정 테이블이 존재하는지 확인하는 함수
30 + def is_table_exist(self,db_name,table_name):
31 + query="select 1 from information_schema.tables where table_schema='%s' and table_name='%s'"
32 + result=self.engine_simul.execute(query%(db_name,table_name)).fetchall()
33 + if len(result)==1:
34 + return True
35 + else:
36 + return False
37 +
38 + # 데이터베이스 연결 설정
39 + def set_database(self):
40 + if self.op=="real":
41 + self.engine_simul=create_engine("mysql+pymysql://"+config.db_id+":"+config.db_pw+"@"+config.db_ip+
42 + ":"+config.db_port+"/"+str(self.db_name),encoding='utf-8')
43 + else:
44 + self.db_name='simulator'+str(self.simul_num)
45 + self.engine_simul=create_engine("mysql+pymysql://"+config.db_id+":"+config.db_pw+"@"+config.db_ip+
46 + ":"+config.db_port+"/"+str(self.db_name),encoding='utf-8')
47 +
48 + self.engine_daily = create_engine("mysql+pymysql://" + config.db_id + ":" + config.db_pw + "@" + config.db_ip +
49 + ":" + config.db_port + "/daily_info" , encoding='utf-8')
50 + self.engine_stock = create_engine("mysql+pymysql://" + config.db_id + ":" + config.db_pw + "@" + config.db_ip +
51 + ":" + config.db_port + "/stock_info", encoding='utf-8')
52 + self.engine_minute = create_engine("mysql+pymysql://" + config.db_id + ":" + config.db_pw + "@" + config.db_ip +
53 + ":" + config.db_port + "/minute_info", encoding='utf-8')
54 +
55 + self.conn=pymysql.connect(
56 + host=config.db_ip,
57 + port=int(config.db_port),
58 + user=config.db_id,
59 + password=config.db_pw,
60 + charset='utf8'
61 + )
62 +
63 + # 날짜별 주식 데이터를 저장해 놓은 데이터베이스에서 가장 최근 날짜를 가져오는 함수
64 + def get_latest_date(self):
65 + query="select table_name from information_schema.tables where table_schema='daily_info' and " \
66 + "table_name like '%s' order by table_name desc limit 1"
67 + result=self.engine_daily.execute(query%("20%%")).fetchall()
68 + if len(result)==0:
69 + return False
70 + else:
71 + return result[0][0]
72 +
73 + # transaction_history 테이블의 Dataframe 생성
74 + def df_transaction_history(self):
75 + df_temp={'id':[]}
76 + self.df_th=DataFrame(df_temp,
77 + columns=['id','order_num','code','code_name','rate','purchase_rate',
78 + 'purchase_price','present_price','valuation_price','valuation_profit',
79 + 'holding_amount','buy_date','total_purchase_price','contract_check','per_invest',
80 + 'sell_date','sell_price','sell_rate'
81 + ])
82 +
83 + # daily_info 데이터베이스에서 특정 날짜에서 특정 코드에 해당하는 정보만 가져오는 함수수
84 + def get_daily_info_by_code(self,code,date):
85 + query="select * from {} where code='{}' group by code"
86 + daily_info=self.engine_daily.execute(query.format(date,code)).fetchall()
87 + df_daily_info=DataFrame(daily_info,
88 + columns=['index','index2','date','check_item','code',
89 + 'code_name','dff_rate',
90 + 'close','open','high','low','volume',
91 + 'avg5','avg10','avg20','avg60','avg120',
92 + 'prev_avg5','prev_avg10','prev_avg20','prev_avg60','prev_avg120',
93 + 'avg5_diff_rate','avg10_diff_rate','avg20_diff_rate','avg60_diff_rate',
94 + 'avg120_diff_rate',
95 + 'vol5','vol10','vol20','vol60','vol120'])
96 + return df_daily_info
...\ No newline at end of file ...\ No newline at end of file
No preview for this file type
1 +from sqlalchemy import *
2 +
1 from open_api import * 3 from open_api import *
4 +from daily_info import *
5 +from stock_info import *
6 +import config
2 7
3 class CollectorApi(): 8 class CollectorApi():
4 def __init__(self): 9 def __init__(self):
5 self.open_api=OpenApi() 10 self.open_api=OpenApi()
6 self.engine_bot=self.open_api.engine_bot 11 self.engine_bot=self.open_api.engine_bot
7 12
13 + def set_variable(self):
14 + self.open_api.sort="collector"
15 + self.stock_info=StockInfo(config.real_bot,config.real_stockInfo,config.real_dailyInofo)
16 + self.daily_info=DailyInfo()
17 +
18 + def update_code(self):
19 + print("update code")
20 + query = "select code_update,jango_data_db_check, possessed_item, today_profit, final_chegyul_check, " \
21 + "db_to_buy_list,today_buy_list, daily_crawler , min_crawler, daily_buy_list " \
22 + "from setting_data limit 1"
23 + result=self.engine_bot.execute(query).fetchall()
24 +
25 + print(result)
26 +
27 + if result[0][0]!=self.open_api.today():
28 + self.open_api.check_balance()
29 + self.get_code_list()
30 +
31 +
32 + def set_db_minute_info(self):
33 + print("Make Minute Info Database")
34 + query="select code,code_name from stock_all"
35 + target=self.open_api.engine_dInfo.execute(query).fetchall()
36 + print(target)
37 +
38 +app = QApplication(sys.argv)
39 +c=CollectorApi()
40 +c.update_code()
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -9,5 +9,16 @@ test_account_no="8147766711" ...@@ -9,5 +9,16 @@ test_account_no="8147766711"
9 9
10 # 시뮬레이션을 돌리기 시작할 날짜 10 # 시뮬레이션을 돌리기 시작할 날짜
11 start_buying='20190101' 11 start_buying='20190101'
12 -simul_num1=1 12 +
13 -simul_name1="AutoBot"+str(simul_num1)+"_Test" 13 +test_num=1
14 +test_bot_name="AutoBot"+str(test_num)+"_Test"
15 +
16 +# 실전투자 정보
17 +real_account_no=""
18 +
19 +real_num=1
20 +
21 +# 데이터베이스 이름
22 +real_bot_name="AutoBot"+str(real_num)
23 +real_stockInfo_name="stock_info"
24 +real_dailyInfo_name="daily_info"
...\ No newline at end of file ...\ No newline at end of file
......
1 -from PyQt5.QtWidgets import *
2 -from PyQt5.QAxContainer import *
3 from PyQt5.QtCore import * 1 from PyQt5.QtCore import *
4 -from PyQt5.QtTest import * 2 +from PyQt5.QAxContainer import *
5 -from pandas import DataFrame 3 +from PyQt5.QtWidgets import *
6 -import sys
7 import pymysql 4 import pymysql
5 +import datetime
8 from sqlalchemy import * 6 from sqlalchemy import *
7 +from collections import defaultdict
8 +from pandas import DataFrame
9 9
10 +from Logger import *
10 import config 11 import config
11 -import error_code 12 +from Simulator_Api import *
12 13
13 -TR_REQ_TIME_INTERVAL = 3600 14 +pymysql.install_as_MySQLdb()
14 15
15 -class OpenApi(QAxWidget): 16 +class Open_Api(QAxWidget):
16 def __init__(self): 17 def __init__(self):
17 super().__init__() 18 super().__init__()
18 19
19 # event_loop list 20 # event_loop list
20 - self.tr_event_loop=QEventLoop()
21 self.login_event_loop=QEventLoop() 21 self.login_event_loop=QEventLoop()
22 + self.tr_event_loop=QEventLoop()
22 23
23 - # variable list 24 + # open_api 호출 횟수를 저장f
24 - self.account_no=None # 계좌번호 25 + self.rq_count=0
25 - self.ohlcv = None # 거래정보(시가,종가,고가,저가,거래량) 26 + self.set_date()
26 - self.remained_data=None # 다음페이지 존재여부 27 + self.tr_loop_count=0
27 - self.simul_num=None # 모의투자 번호 28 + self.call_time=datetime.datetime.now()
28 - self.db_name=None # 거래데이터를 담고 있는 AutoBot 데이터베이스
29 -
30 - # engine list
31 - self.engine_bot=None # AutoBot데이터베이스에 접속하는 engine
32 -
33 - # screen number list
34 - self.screen_data_req="0101" # 거래 데이터
35 -
36 - self.create_instance()
37 - self._signal_slots()
38 - self.comm_connect() # 로그인
39 - self.get_account_info() # 계좌정보 가져오기
40 - self.variable_setting() # 데이터베이스 설정
41 -
42 - # 데이터베이스 설정
43 - def variable_setting(self):
44 - print("============variable setting function===============")
45 - # 모의투자인 경우
46 - if self.account_no == config.test_account_no:
47 - self.simul_num = config.simul_num1
48 - self.db_name_setting(config.simul_name1)
49 -
50 - # AutoBot Database 생성
51 - def create_database(self,cursor):
52 - print("create database")
53 - query="create database {}"
54 - cursor.execute(query.format(self.db_name))
55 29
56 - # AutoBot Database가 존재하는지 여부를 확인 30 + # open_api 연동
57 - def is_BotTable_exist(self,cursor): 31 + self._create_instance()
58 - query="select 1 from information_schema.schemata where schema_name='{}'" 32 + self._set_signal_slots()
59 - print(query.format(self.db_name)) 33 + self.comm_connect()
60 - if (cursor.execute(query.format(self.db_name))): 34 +
61 - print("%s 데이터베이스가 존재합니다.",self.db_name) 35 + # 계좌정보 출력
62 - return True 36 + self.get_account_info()
37 +
38 + # 변수 설정
39 + self.set_variable()
40 +
41 + self.simul_api=Simulator_Api(self.simul_num,"real",self.db_name)
42 + logger.debug("알고리즘 번호 : %s",self.simul_api.simul_num)
43 + logger.debug("매수 알고리즘 번호 : %s",self.simul_api.buy_algorithm)
44 + logger.debug("매도 알고리즘 번호 : %s",self.simul_api.sell_algorithm)
45 +
46 + if not self.simul_api.is_table_exist(self.db_name,"setting_data"):
47 + self.create_setting_data()
48 +
49 + self.set_simul_variable()
50 + self.ohlcv=defaultdict(list)
51 +
52 + # 날짜 설정
53 + def set_date(self):
54 + self.today=datetime.datetime.today().strftime("%Y%m%d")
55 + self.today_time=datetime.datetime.today().strftime("%Y%m%d%H%M")
56 +
57 + # 키움 open_api 를 사용하기 위한 ocx controller 생성
58 + def _create_instance(self):
59 + try:
60 + self.setControl("KHOPENAPI.KHOpenAPICtrl.1")
61 + except Exception as e:
62 + logger.critical(e)
63 +
64 + # 이벤트 처리를 위한 slots
65 + def _set_signal_slots(self):
66 + try:
67 + # 로그인 처리 이벤트
68 + self.OnEventConnect.connect(self._login_slot)
69 + # 조회요청 처리 이벤트
70 + self.OnReceiveTrData.connect(self._receive_tr_data)
71 + # 서버 통신 후 수신메세지 처리 이벤트
72 + self.OnReceiveMsg.connect(self._receive_msg)
73 + # 주문요청 처리 이벤트
74 + self.OnReceiveChejanData.connect(self._receive_chejan_data)
75 + except Exception as e:
76 + logger.critical(e)
77 +
78 + # 로그인 이벤트 처리 slot
79 + # param : code - 로그인 성공 시 0
80 + # 실패 시 에러코드 출력
81 + def _login_slot(self,code):
82 + try:
83 + if code==0:
84 + logger.debug("connected")
63 else: 85 else:
64 - return False 86 + logger.debug("connection failed...")
87 + self.login_event_loop.exit()
88 + except Exception as e:
89 + logger.critical(e)
65 90
66 - # 데이터베이스 확인 및 생성 91 + # 수동 로그인설정인 경우 로그인창을 출력해서 로그인을 시도
67 - def db_name_setting(self,db_name): 92 + # 자동로그인 설정인 경우 로그인창 출력없이 로그인을 시도
68 - self.db_name=db_name 93 + def comm_connect(self):
69 - print("db_name : %s"%self.db_name) 94 + try:
70 - conn = pymysql.connect( 95 + self.dynamicCall("CommConnect()")
71 - host=config.db_ip, 96 + self.login_event_loop.exec_()
72 - port=int(config.db_port), 97 + except Exception as e:
73 - user=config.db_id, 98 + logger.critical(e)
74 - password=config.db_pw,
75 - charset='utf8'
76 - )
77 - cursor=conn.cursor()
78 - if not self.is_BotTable_exist(cursor):
79 - self.create_database(cursor)
80 - self.engine_bot=create_engine(
81 - "mysql+pymysql://" + config.db_id + ":" + config.db_pw + "@" + config.db_ip + ":" + config.db_port + "/" +
82 - db_name, encoding='utf-8')
83 - self.db_setting(cursor)
84 -
85 - # AutoBot 이외에 필요한 데이터베이스를 생성
86 - def db_setting(self,cursor):
87 - # 생성해야 할 데이터베이스 리스트
88 - to_create=['stock_info','daily_info','minute_info']
89 - query="select schema_name from information_schema.schemata"
90 - cursor.execute(query)
91 - result=cursor.fetchall()
92 - create_db="CREATE DATABASE {}"
93 - # 생성되어 있는 데이터베이스 리스트
94 - created=list()
95 - for item in result:
96 - created.append(item[0])
97 - # 생성하야 할 데이터베이스가 존재하지 않는 경우 새로 생성
98 - for db in to_create:
99 - if db not in created:
100 - print(db,"데이터베이스가 존재하지 않습니다. 데이터베이스를 새로 생성합니다.")
101 - create_query=create_db.format(db)
102 - cursor.execute(create_query)
103 - print(db,"데이터베이스 생성 완료!")
104 -
105 - # 주식일봉차트조회요청
106 - def _opt10081(self,sRQName,sTrCode):
107 - QTest.qWait(TR_REQ_TIME_INTERVAL)
108 -
109 - cnt=self._get_repeat_cnt(sTrCode,sRQName)
110 -
111 - for i in range(cnt):
112 - date=self._get_comm_data(sTrCode,sRQName,i,"일자")
113 - open=self._get_comm_data(sTrCode,sRQName,i,"시가")
114 - high=self._get_comm_data(sTrCode,sRQName,i,"고가")
115 - low=self._get_comm_data(sTrCode,sRQName,i,"저가")
116 - close=self._get_comm_data(sTrCode,sRQName,i,"현재가")
117 - volume=self._get_comm_data(sTrCode,sRQName,i,"거래량")
118 -
119 - self.ohlcv['date'].append(date)
120 - self.ohlcv['open'].append(int(open))
121 - self.ohlcv['high'].append(int(high))
122 - self.ohlcv['low'].append(int(low))
123 - self.ohlcv['close'].append(int(close))
124 - self.ohlcv['volumn'].append(int(volume))
125 99
126 # TR 요청을 처리하는 slot 100 # TR 요청을 처리하는 slot
127 - # param sScrNo: 스크린번호 101 + # param sScrNo : 스크린번호
128 - # sRQName: 요청했을 때 지은 이름 102 + # sRQName : 요청했을 때 지은 이름
129 - # sTrCode: 요청 id, tr코드 103 + # sTrCode : 요청 id, tr코드
130 - # sRecordName: 레코드 이름 104 + # sRecordName : 레코드 이름
131 - # sPrevNext: 다음 페이지가 있는지 여부. "2" : 다음페이지 존재, "0" or "" : 다음페이지 없음 105 + # sPrevNext : 다음 페이지가 있는지 여부. "2" : 다음페이지 존재, "0" or "" : 다음페이지 없음
132 def _receive_tr_data(self,sScrNo,sRQName,sTrCode,sRecordName,sPrevNext): 106 def _receive_tr_data(self,sScrNo,sRQName,sTrCode,sRecordName,sPrevNext):
133 if sPrevNext=='2': 107 if sPrevNext=='2':
134 self.remained_data=True 108 self.remained_data=True
135 else: 109 else:
136 self.remained_data=False 110 self.remained_data=False
137 111
138 - if sRQName=="opt10081": 112 + # Request 요청에 따른 함수 처리
139 - print("==============주식일봉차트조회요청================") 113 + if sRQName == "opt10081_req" and self.purpose == "trader":
114 + logger.debug("주식일봉차트조회요청")
140 self._opt10081(sRQName,sTrCode) 115 self._opt10081(sRQName,sTrCode)
141 - elif sRQName=="opw0001_req": 116 + elif sRQName == "opt10081_req" and self.purpose == "collector":
142 - return 117 + logger.debug("주식일봉차트조회요청")
143 - elif sRQName=="opw00018_req": 118 + self.collector_opt10081(sRQName,sTrCode)
144 - return 119 + elif sRQName == "opw00001_req":
145 - elif sRQName=="opt10074_req": 120 + logger.debug("예수금상세현황요청")
146 - return 121 + self._opw00001(sRQName,sTrCode)
147 - elif sRQName=="opw00015_req": 122 + elif sRQName == "opw00018_req":
148 - return 123 + logger.debug("계좌평가잔고내역요청")
149 - elif sRQName=="opt10076_req": 124 + self._opw00018(sRQName,sTrCode)
150 - return 125 + elif sRQName == "opt10074_req":
151 - elif sRQName=="opt10073_req": 126 + logger.debug("일자별실현손익요청")
152 - return 127 + self._opt10084(sRQName,sTrCode)
128 + elif sRQName == "opw00015_req":
129 + logger.debug("위탁종합거래내역요청")
130 + self._opw00015(sRQName,sTrCode)
131 + elif sRQName == "opt10076_req":
132 + logger.debug("실시간체결요청")
133 + self._opt10076(sRQName,sTrCode)
134 + elif sRQName == "opt10073_req":
135 + logger.debug("일자별종목별실현손익요청")
136 + self._opt10073(sRQName,sTrCode)
137 + elif sRQName == "opt10080_req":
138 + logger.debug("주식분봉차트조회요청")
139 + self._opt10080(sRQName,sTrCode)
140 + elif sRQName == "send_order_req":
141 + pass
142 + else:
143 + logger.debug("Invalid Request Code...")
153 144
145 + # 다음 페이지가 존재할 경우 처리
146 + # 다음 페이지가 존재하지 않을 경우 event loop를 종료
147 + if sRQName!="send_order_req":
148 + self.tr_loop_count-=1
154 try: 149 try:
150 + if self.tr_loop_count<=0:
155 self.tr_event_loop.exit() 151 self.tr_event_loop.exit()
152 + self.tr_loop_count=0
156 except AttributeError: 153 except AttributeError:
157 pass 154 pass
158 155
159 - # 특정 종목의 일자별 거래 데이터 조회 함수 156 + # 서버통신 후 수신한 메시지를 알려주는 slot
160 - # param : code - 종목코드 157 + def _receive_msg(self,sScrNo,sRQName,sTrCode,sMsg):
161 - # start - 기준일자 158 + logger.debug(sMsg)
162 - # return : df - 특정종목의 일자별 거래 데이터 목록 159 +
163 - def get_total_data(self,code,start): 160 + # 주문요청후 주문접수, 체결통보, 잔고통보를 수신할 때 마다 호출
164 - self.ohlcv = {'date': [], 'open': [], 'high': [], 'low': [], 'close': [], 'volume': []} 161 + # GetChejanData()함수를 이용해서 상세한 정보를 얻을 수 있다
165 - 162 + # param : sGubun - 체결구분. 접수와 체결시 '0'값, 국내주식 잔고전달은 '1'값, 파생잔고 전달은 '4'
166 - self._set_input_value("종목코드",code) 163 + def _receive_chejan_data(self,sGubun,nItemCnt,sFIdList):
167 - self._set_input_value("기준일자",start) 164 + # 현재 체결 진행 중인 코드
168 - self._set_input_value("수정주가구분",1) 165 + print("주분번호 : ",self.get_chejan_data(9023))
169 - self._comm_rq_data("opt10081_req","opt10081",0,self.screen_data_req) 166 + print("종목명 : ",self.get_chejan_data(302))
170 - 167 + print("주문수량 : ",self.get_chejan_data(900))
171 - while self.remained_data: 168 + print("주문가격 : ",self.get_chejan_data(901))
172 - self._set_input_value("종목코드",code) 169 +
173 - self._set_input_value("기준일자",start) 170 + # OnReceiveChejan()이벤트가 호출될때 체결정보나 잔고정보를 얻어오는 함수
174 - self._set_input_value("수정주가구분",1) 171 + # param : nFid - 실시간 타입에 포함된 FID
175 - self._comm_rq_data("opt10081_req","opt10081",2,self.screen_data_req) 172 + def get_chejan_data(self,nFid):
176 - 173 + try:
177 - # 데이터가 없거나, date=''일 경우 empty list를 반환 174 + ret=self.dynamicCall("GetChejanData(int)",nFid)
178 - if len(self.ohlcv)==0: 175 + return ret
179 - return [] 176 + except Exception as e:
180 - if self.ohlcv['date']=='': 177 + logger.critical(e)
181 - return []
182 -
183 - # 데이터를 DataFrame형태로 저장 및 반환
184 - df=DataFrame(self.ohlcv,columns=['open','high','low','close','volume'],index=self.ohlcv['date'])
185 -
186 - return df
187 -
188 - # 특정 종목의 특정 날짜의 시가,종가,고가,저가,거래량 중 특정한 데이터를 반환하는 함수
189 - # param : code - 종목코드
190 - # : date - 조회날짜
191 - # : option - open(시가)/close(종가)/high(고가)/low(저가)/volume(거래량)
192 - # return : 조회한 데이터에 해당하는 값
193 - # 값이 없거나, option이 오류일 경우 return False
194 - def get_oneday_option_data(self,code,date,option):
195 - self.ohlcv = {'date': [], 'open': [], 'high': [], 'low': [], 'close': [], 'volume': []}
196 -
197 - self._set_input_value("종목코드",code)
198 - self._set_input_value("기준일자",date)
199 - self._set_input_value("수정주가구분",1)
200 - self._comm_rq_data("opt10081_req","opt10081",0,self.screen_data_req)
201 -
202 - if self.ohlcv['date']=="":
203 - return False
204 -
205 - df = DataFrame(self.ohlcv, columns=['open', 'high', 'low', 'close', 'volume'], index=self.ohlcv['date'])
206 - if option == 'open':
207 - return df.iloc[0, 0]
208 - elif option == 'high':
209 - return df.iloc[0, 1]
210 - elif option == 'low':
211 - return df.iloc[0, 2]
212 - elif option == 'close':
213 - return df.iloc[0, 3]
214 - elif option == 'volume':
215 - return df.iloc[0, 4]
216 - else:
217 - return False
218 178
219 # 사용자의 계좌정보 저장 및 출력 179 # 사용자의 계좌정보 저장 및 출력
220 def get_account_info(self): 180 def get_account_info(self):
221 - account=self.get_login_info("ACCNO") 181 + account_no=self.get_login_info("ACCNO")
222 - self.account_no=account.split(";")[0] 182 + self.account_no=account_no.split(";")[0]
223 - print("======== 계좌번호 : ",self.account_no,"========") 183 + logger.debug(self.account_no)
224 184
225 # 원하는 사용자 정보 반환 185 # 원하는 사용자 정보 반환
226 # param : tag - ACCNO - 보유계좌리스트 186 # param : tag - ACCNO - 보유계좌리스트
...@@ -236,50 +196,7 @@ class OpenApi(QAxWidget): ...@@ -236,50 +196,7 @@ class OpenApi(QAxWidget):
236 ret=self.dynamicCall("GetLoginInfo(QString)",tag) 196 ret=self.dynamicCall("GetLoginInfo(QString)",tag)
237 return ret 197 return ret
238 except Exception as e: 198 except Exception as e:
239 - print(e) 199 + logger.critical(e)
240 - sys.exit()
241 -
242 - # 키움 api를 사용하기 위한 ocx controller 저장
243 - def create_instance(self):
244 - try:
245 - self.setControl("KHOPENAPI.KHOpenAPICtrl.1")
246 - except Exception as e:
247 - print(e)
248 - sys.exit()
249 -
250 - # event처리를 위한 slot
251 - def _signal_slots(self):
252 - try:
253 - self.OnEventConnect.connect(self._login_slot)
254 - self.OnReceiveTrData.connect(self._receive_tr_data)
255 - except Exception as e:
256 - print(e)
257 - sys.exit()
258 -
259 - # 수동 로그인설정인 경우 로그인창을 출력해서 로그인을 시도
260 - # 자동로그인 설정인 경우 로그인창 출력없이 로그인을 시도
261 - def comm_connect(self):
262 - try:
263 - self.dynamicCall("CommConnect()")
264 - self.login_event_loop.exec_()
265 - except Exception as e:
266 - print(e)
267 - sys.exit()
268 -
269 - # 로그인 이벤트 처리 slot
270 - # param : code - 로그인 성공 시 0
271 - # 실패 시 에러코드 출력
272 - def _login_slot(self,code):
273 - try:
274 - result=error_code.errors(code)
275 - if code==0:
276 - print("Connected",result[1])
277 - else:
278 - print("Failed to connect",result[1])
279 - self.login_event_loop.exit()
280 - except Exception as e:
281 - print(e)
282 - sys.exit()
283 200
284 # 조회요청시 TR의 Input값을 지정하는 함수 201 # 조회요청시 TR의 Input값을 지정하는 함수
285 # param : sId - TR에 명시된 Input이름 202 # param : sId - TR에 명시된 Input이름
...@@ -320,6 +237,190 @@ class OpenApi(QAxWidget): ...@@ -320,6 +237,190 @@ class OpenApi(QAxWidget):
320 print(e) 237 print(e)
321 sys.exit() 238 sys.exit()
322 239
323 -if __name__ == "__main__":
324 - app = QApplication(sys.argv)
325 - api=OpenApi()
...\ No newline at end of file ...\ No newline at end of file
240 + # 변수 설정
241 + # 실전투자인지 모의투자인지 여부를 확인하고 그에 해당하는 데이터베이스를 생성하는 함수
242 + def set_variable(self):
243 + self.config=config
244 + if self.account_no==self.config.real_account_no:
245 + logger.debug("실전투자")
246 + self.simul_num=self.config.real_num
247 + self.set_database(self.config.real_bot_name)
248 + elif self.account_no==self.config.test_account_no:
249 + logger.debug("모의투자")
250 + self.simul_num=self.config.test_num
251 + self.set_database(self.config.test_bot_name)
252 + else:
253 + logger.debug("Invalid Account Number. Check the Config.py")
254 + exit(1)
255 +
256 + # 데이터베이스 생성 및 엔진 설정
257 + def set_database(self,db_name):
258 + self.db_name=db_name
259 + conn=pymysql.connect(
260 + host=config.db_ip,
261 + port=int(config.db_port),
262 + user=config.db_id,
263 + password=config.db_pw,
264 + charset='utf8'
265 + )
266 + cursor=conn.cursor()
267 + if not self.is_database_exist(cursor):
268 + self.create_database(cursor)
269 + self.engine_bot=create_engine("mysql+pymysql://"+self.config.db_id+":"+self.config.db_pw+"@"+
270 + self.config.db_ip + ":" + self.config.db_port+"/"+db_name,encoding='utf-8')
271 + self.create_info_database(cursor)
272 +
273 + conn.commit()
274 + cursor.close()
275 + conn.close()
276 +
277 + self.engine_daily=create_engine("mysql+pymysql://"+self.config.db_id+":"+self.config.db_pw+"@"+
278 + self.config.db_ip + ":" + self.config.db_port+"/daily_info",encoding='utf-8')
279 + self.engine_stock=create_engine("mysql+pymysql://"+self.config.db_id+":"+self.config.db_pw+"@"+
280 + self.config.db_ip + ":" + self.config.db_port+"/stock_info",encoding='utf-8')
281 + self.engine_minute=create_engine("mysql+pymysql://"+self.config.db_id+":"+self.config.db_pw+"@"+
282 + self.config.db_ip + ":" + self.config.db_port+"/minute_info",encoding='utf-8')
283 +
284 + # Bot Database가 존재하는지 확인하는 함수
285 + def is_database_exist(self,cursor):
286 + query="select 1 from information_schema.schemata where schema_name='{}'"
287 + result=cursor.execute(query.format(self.db_name))
288 + if result:
289 + return True
290 + else:
291 + return False
292 +
293 + # Bot Database를 생성하는 함수
294 + def create_database(self,cursor):
295 + query="create database {}"
296 + cursor.execute(query.format(self.db_name))
297 +
298 + # information 데이터베이스가 존재하는지 확인
299 + # 존재하지 않는다면 새로 생성
300 + def create_info_database(self,cursor):
301 + info_list=['daily_info','stock_info','minute_info']
302 + query="select schema_name from information_schema.schemata"
303 + cursor.execute(query)
304 + result=cursor.fetchall()
305 + print(result)
306 + exist_list=[item[0].lower() for item in result]
307 + create_query="create database {}"
308 + has_created=False
309 + for db in info_list:
310 + if db not in exist_list:
311 + has_created=True
312 + logger.debug(db,"Database not exist. Create the Database.")
313 + cursor.execute(create_query.format(db))
314 + logger.debug(db,"Creation Completed!")
315 +
316 + if has_created and self.engine_bot.has_table('setting_data'):
317 + print("exist")
318 + self.engine_bot.execute("update setting_data set code_update='0")
319 +
320 + def create_setting_data(self):
321 + df_data={"limit_money":[],"per_invest":[],"max_per_invest":[],"min_per_invest":[],"set_per_invest":[],
322 + "code_update":[],"today_finish":[],"balance_to_db":[],"posses_stocks":[],"today_profit":[],
323 + "contract_check":[],"db_to_daily_info":[],"today_buy_list":[],"stock_info":[],"daily_info":[]}
324 + df_setting_data=DataFrame(df_data,
325 + columns=['limit_money','per_invest','max_per_invest','min_per_invest','set_per_invest',
326 + 'code_update','today_finish','balance_to_db','posses_stocks','today_profit',
327 + 'contract_check','db_to_daily_info','today_buy_list','stock_info','daily_info'])
328 +
329 + df_setting_data.loc[0,'limit_money']=int(0)
330 + df_setting_data.loc[0,'per_invest']=int(0)
331 + df_setting_data.loc[0,'max_per_invest']=int(0)
332 + df_setting_data.loc[0,'min_per_invest']=int(0)
333 + df_setting_data.loc[0,'set_per_invest']=str(0)
334 +
335 + df_setting_data.loc[0,'code_update']=str(0)
336 + df_setting_data.loc[0,'today_finish']=str(0)
337 + df_setting_data.loc[0,'balance_to_db']=str(0)
338 + df_setting_data.loc[0,'posses_stocks']=str(0)
339 + df_setting_data.loc[0,'today_profit']=float(0)
340 +
341 + df_setting_data.loc[0,'contract_check']=str(0)
342 + df_setting_data.loc[0,'db_to_daily_info']=str(0)
343 + df_setting_data.loc[0,'today_buy_list']=str(0)
344 + df_setting_data.loc[0,'stock_info']=str(0)
345 + df_setting_data.loc[0,'daily_info']=str(0)
346 +
347 + df_setting_data.to_sql("setting_data",self.engine_bot,if_exists="replace")
348 +
349 + def set_simul_variable(self):
350 + self.latest_date=self.simul_api.get_latest_date()
351 + if not self.simul_api.is_table_exist(self.db_name,"transaction_history"):
352 + logger.debug("create transaction_history table")
353 + self.per_invest=0
354 + self.create_transaction_history(0,0,0,0,0)
355 + self.delete_item_by_code(0)
356 +
357 + # transaction_history 테이블 생성 및 column 설정
358 + def create_transaction_history(self,order_num,code,contract_check,purchase_price,rate):
359 + logger.debug("creating transaction_history table")
360 + self.set_date()
361 + self.simul_api.df_transaction_history()
362 + self.simul_api.df_th.loc[0,'order_num']=order_num
363 + self.simul_api.df_th.loc[0,'code']=str(code)
364 + self.simul_api.df_th.loc[0,'reate']=float(rate)
365 + self.simul_api.df_th.loc[0,'buy_date']=self.today_time
366 + self.simul_api.df_th.loc[0,'contract_check']=contract_check
367 + self.simul_api.df_th.loc[0,'per_invest']=self.per_invest
368 + self.simul_api.df_th.loc[0,'purchase_price']=purchase_price
369 +
370 + self.simul_api.df_th=self.simul_api.df_th.fillna(0)
371 + self.simul_api.df_th.to_sql('transaction_history',self.engine_bot,if_exists='append')
372 +
373 + def delete_item_by_code(self,code):
374 + query="delete from transaction_history where code='%s'"
375 + self.engine_bot.execute(query%code)
376 +
377 + # setting_data에 per_invest항목이 설정되어 있는지 확인하는 함수
378 + def check_per_invest(self):
379 + query="select per_invest, set_per_invest from setting_data"
380 + result=self.engine_bot.execute(query).fetchall()
381 + if result[0][1]==self.today:
382 + self.per_invest=result[0][0]
383 + return True
384 + else:
385 + return False
386 +
387 + def set_per_invest(self):
388 + self.get_deposit()
389 +
390 + # 예수금 조회 및 저장
391 + def get_deposit(self):
392 + self._set_input_value("계좌번호",self.account_no)
393 + self._set_input_value("비밀번호입력매체구분",00)
394 + self._set_input_value("조회구분",1)
395 + self._comm_rq_data("opw00001_req","opw00001",0,"2000")
396 +
397 + # 예수금 상세현황요청 함수
398 + def _opw00001(self,sRQName,sTrCode):
399 + self.deposit=self._get_comm_data(sTrCode,sRQName,0,"d+2출금가능금액")
400 + self.deposit=int(self.deposit)
401 +
402 + def get_balance(self):
403 + self._set_input_value("계좌번호",self.account_no)
404 + self._comm_rq_data("opw00018_req","opw00018",0,"2000")
405 + # 다음페이지가 존재할 경우 계속해서 조회
406 + while self.remained_data:
407 + self._set_input_value("계좌번호",self.account_no)
408 + self._comm_rq_data("opw00018_req","opw00018",2,"2000")
409 +
410 + def _opw00018(self,sRQName,sTrCode):
411 + self.total_purchase=self._get_comm_data(sTrCode,sRQName,0,"총매입금액")
412 + self.total_evaluated_price=self._get_comm_data(sTrCode,sRQName,0,"총평가금액")
413 + self.total_valuation=self._get_comm_data(sTrCode,sRQName,0,"총평가손익금액")
414 + self.earning_rate=self._get_comm_data(sTrCode,sRQName,0,"총수익률(%)")
415 + self.estimated_deposit=self._get_comm_data(sTrCode,sRQName,0,"추정예탁자산")
416 +
417 + self.total_purchase=int(self.total_purchase)
418 + self.total_evaluated_price=int(self.total_evaluated_price)
419 + self.total_valuation=int(self.total_valuation)
420 + self.earning_rate=float(self.earning_rate)
421 + self.estimated_deposit=int(self.estimated_deposit)
422 +
423 +if __name__=="__main__":
424 + app=QApplication(sys.argv)
425 + a=Open_Api()
426 + a.get_balance()
...\ No newline at end of file ...\ No newline at end of file
......
1 +from sqlalchemy import *
2 +from PyQt5.QtCore import *
3 +import datetime
4 +
5 +import config
6 +
1 class StockInfo(): 7 class StockInfo():
2 - def __init__(self): 8 + def __init__(self,db_name,stock_info_name,daily_info_name):
9 + if db_name!=0:
10 + self.db_name=db_name
11 + self.stockInfo_name=stock_info_name
12 + self.dailyInfo_name=daily_info_name
13 +
14 + self.engine=create_engine(
15 + "mysql+pymysql://" + config.db_id + ":" + config.db_pw + "@" + config.db_ip + ":" + config.db_port +
16 + "/stock_info", encoding='utf-8')
17 + self.conn=self.engine.connect()
18 +
19 + self.set_variable()
20 +
21 + # 변수 설정
22 + def set_variable(self):
23 + self.mkt_start_time=QTime(9,0,0)
24 + self.mkt_end_time=QTime(15,31,0)
25 +
26 + self.today=datetime.datetime.today().strftime("%Y%m%d")
27 +
28 + # 현재 시간이 주식장이 열린 시간인지 확인하는 함수
29 + def time_check(self):
30 + self.current_time=QTime.currentTime()
31 + if (self.current_time>self.mkt_start_time and self.current_time<self.mkt_end_time):
32 + return True
33 + else:
34 + return False
...\ No newline at end of file ...\ No newline at end of file
......