이하영

create database automatically

1 +import pymysql
2 +
3 +pymysql.install_as_MySQLdb()
4 +
5 +class Collector:
6 + def __init__(self):
...\ No newline at end of file ...\ No newline at end of file
1 +# Default ignored files
2 +/shelf/
3 +/workspace.xml
1 +<component name="InspectionProjectProfileManager">
2 + <settings>
3 + <option name="USE_PROJECT_PROFILE" value="false" />
4 + <version value="1.0" />
5 + </settings>
6 +</component>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<module type="PYTHON_MODULE" version="4">
3 + <component name="NewModuleRootManager">
4 + <content url="file://$MODULE_DIR$" />
5 + <orderEntry type="inheritedJdk" />
6 + <orderEntry type="sourceFolder" forTests="false" />
7 + </component>
8 + <component name="TestRunnerService">
9 + <option name="PROJECT_TEST_RUNNER" value="pytest" />
10 + </component>
11 +</module>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
4 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="ProjectModuleManager">
4 + <modules>
5 + <module fileurl="file://$PROJECT_DIR$/.idea/library.iml" filepath="$PROJECT_DIR$/.idea/library.iml" />
6 + </modules>
7 + </component>
8 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project version="4">
3 + <component name="VcsDirectoryMappings">
4 + <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
5 + </component>
6 +</project>
...\ No newline at end of file ...\ No newline at end of file
No preview for this file type
1 +from open_api import *
2 +
3 +class CollectorApi():
4 + def __init__(self):
5 + self.open_api=OpenApi()
6 + self.engine_bot=self.open_api.engine_bot
7 +
...@@ -2,6 +2,12 @@ ...@@ -2,6 +2,12 @@
2 db_id="user" 2 db_id="user"
3 db_pw="password" 3 db_pw="password"
4 db_port="3306" 4 db_port="3306"
5 +db_ip="localhost"
5 6
6 # 모의투자 계좌번호 7 # 모의투자 계좌번호
7 -account_no="8147766711"
...\ No newline at end of file ...\ No newline at end of file
8 +test_account_no="8147766711"
9 +
10 +# 시뮬레이션을 돌리기 시작할 날짜
11 +start_buying='20190101'
12 +simul_num1=1
13 +simul_name1="AutoBot"+str(simul_num1)+"_Test"
......
1 +def errors(err_code):
2 + err_dict={0:('OP_ERR_NONE','정상처리'),
3 + -10:('OP_ERR_FAIL','실패'),
4 + -100:('OP_ERR_LOGIN','사용자정보교환실패'),
5 + -101:('OP_ERR_CONNECT','서버접속실패'),
6 + -102:('OP_ERR_VERSION','버전처리실패'),
7 + -103:('OP_ERR_FAIRWALL','개인방화벽실패'),
8 + -104:('OP_ERR_MEMORY','메모리보호실패'),
9 + -105:('OP_ERR_INPUT','함수입력값오류'),
10 + -106:('OP_ERR_SOCKET_CLOSED','통신연결종료'),
11 + -200:('OP_ERR_SISE_OVERFLOW','시세조회과부화'),
12 + -201:('OP_ERR_RQ_STRUCT_FAIL','전문작성초기화실패'),
13 + -202:('OP_ERR_RQ_STRING_FAIL','전문작성입력값오류'),
14 + -203:('OP_ERR_NO_DATA','데이터없음'),
15 + -204:('OP_ERR_OVER_MAX_DATA','조회가능한종목수초과'),
16 + -205:('OP_ERR_DATA_RCV_FAIL','데이터수신실패'),
17 + -206:('OP_ERR_OVER_MAX_FID','조회가능한FID수초과'),
18 + -207:('OP_ERR_REAL_CANCEL','실시간해제오류'),
19 + -300:('OP_ERR_ORD_WRONG_INPUT','입력값오류'),
20 + -301:('OP_ERR_ORD_WRONG_ACCNO','계좌비밀번호없음'),
21 + -302:('OP_ERR_OTHER_ACC_USE','타인계좌사용오류'),
22 + -303:('OP_ERR_MIS_2BILL_EXC','주문가격이20억원을초과'),
23 + -304:('OP_ERR_MIS_5BILL_EXC','주문가격이50억원을초과'),
24 + -305:('OP_ERR_MIS_1PER_EXC','주문수량이총발행주수의1 % 초과오류'),
25 + -306:('OP_ERR_MIS_3PER_EXC','주문수량이총발행주수의3 % 초과오류'),
26 + -307:('OP_ERR_SEND_FAIL','주문전송실패'),
27 + -308:('OP_ERR_ORD_OVERFLOW','주문전송과부화'),
28 + -309:('OP_ERR_MIS_300CNT_EXC','주문수량300계약초과'),
29 + -310:('OP_ERR_MIS_500CNT_EXC','주문수량500계약초과'),
30 + -340:('OP_ERR_ORD_WRONG_ACCINFO','계좌정보없음'),
31 + -500:('OP_ERR_ORD_SYMCODE_EMPTY','종목코드없음')
32 + }
33 +
34 + result=err_dict[err_code]
35 + return result
...\ 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 *
4 +from PyQt5.QtTest import *
5 +from pandas import DataFrame
6 +import sys
7 +import pymysql
8 +from sqlalchemy import *
9 +
10 +import config
11 +import error_code
12 +
13 +TR_REQ_TIME_INTERVAL = 3600
14 +
15 +class OpenApi(QAxWidget):
16 + def __init__(self):
17 + super().__init__()
18 +
19 + # event_loop list
20 + self.tr_event_loop=QEventLoop()
21 + self.login_event_loop=QEventLoop()
22 +
23 + # variable list
24 + self.account_no=None # 계좌번호
25 + self.ohlcv = None # 거래정보(시가,종가,고가,저가,거래량)
26 + self.remained_data=None # 다음페이지 존재여부
27 +
28 + # screen number list
29 + self.screen_data_req="0101" # 거래 데이터
30 +
31 + self.create_instance()
32 + self._signal_slots()
33 + self.comm_connect() # 로그인
34 + self.get_account_info() # 계좌정보 가져오기
35 + self.variable_setting()
36 +
37 + def variable_setting(self):
38 + print("============variable setting function===============")
39 + # 모의투자
40 + if self.account_no==config.test_account_no:
41 + print("test investment!!!!!!")
42 + self.simul_num=config.simul_num1
43 + self.db_name_setting(config.simul_name1)
44 +
45 +
46 + # AutoBot Database 생성
47 + def create_database(self,cursor):
48 + print("create database")
49 + query="create database {}"
50 + cursor.execute(query.format(self.db_name))
51 +
52 + # AutoBot Database가 존재하는지 여부를 확인
53 + def is_BotTable_exist(self,cursor):
54 + query="select 1 from information_schema.schemata where schema_name='{}'"
55 + print(query.format(self.db_name))
56 + if (cursor.execute(query.format(self.db_name))):
57 + print("%s 데이터베이스가 존재합니다.",self.db_name)
58 + return True
59 + else:
60 + return False
61 +
62 + def db_name_setting(self,db_name):
63 + self.db_name=db_name
64 + print("db_name : %s"%self.db_name)
65 + conn = pymysql.connect(
66 + host=config.db_ip,
67 + port=int(config.db_port),
68 + user=config.db_id,
69 + password=config.db_pw,
70 + charset='utf8'
71 + )
72 + cursor=conn.cursor()
73 + if not self.is_BotTable_exist(cursor):
74 + self.create_database(cursor)
75 + self.engine_bot=create_engine(
76 + "mysql+pymysql://" + config.db_id + ":" + config.db_pw + "@" + config.db_ip + ":" + config.db_port + "/" +
77 + db_name, encoding='utf-8')
78 + self.db_setting(cursor)
79 +
80 + def db_setting(self,cursor):
81 + # 생성해야 할 데이터베이스 리스트
82 + to_create=['stock_info','daily_info','minute_info']
83 + query="select schema_name from information_schema.schemata"
84 + cursor.execute(query)
85 + result=cursor.fetchall()
86 + create_db="CREATE DATABASE {}"
87 + # 생성되어 있는 데이터베이스 리스트
88 + created=list()
89 + for item in result:
90 + created.append(item[0])
91 + # 생성하야 할 데이터베이스가 존재하지 않는 경우 새로 생성
92 + for db in to_create:
93 + if db not in created:
94 + print(db,"데이터베이스가 존재하지 않습니다. 데이터베이스를 새로 생성합니다.")
95 + create_query=create_db.format(db)
96 + cursor.execute(create_query)
97 + print(db,"데이터베이스 생성 완료!")
98 +
99 + # 주식일봉차트조회요청
100 + def _opt10081(self,sRQName,sTrCode):
101 + QTest.qWait(TR_REQ_TIME_INTERVAL)
102 +
103 + cnt=self._get_repeat_cnt(sTrCode,sRQName)
104 +
105 + for i in range(cnt):
106 + date=self._get_comm_data(sTrCode,sRQName,i,"일자")
107 + open=self._get_comm_data(sTrCode,sRQName,i,"시가")
108 + high=self._get_comm_data(sTrCode,sRQName,i,"고가")
109 + low=self._get_comm_data(sTrCode,sRQName,i,"저가")
110 + close=self._get_comm_data(sTrCode,sRQName,i,"현재가")
111 + volume=self._get_comm_data(sTrCode,sRQName,i,"거래량")
112 +
113 + self.ohlcv['date'].append(date)
114 + self.ohlcv['open'].append(int(open))
115 + self.ohlcv['high'].append(int(high))
116 + self.ohlcv['low'].append(int(low))
117 + self.ohlcv['close'].append(int(close))
118 + self.ohlcv['volumn'].append(int(volume))
119 +
120 + # TR 요청을 처리하는 slot
121 + # param sScrNo: 스크린번호
122 + # sRQName: 요청했을 때 지은 이름
123 + # sTrCode: 요청 id, tr코드
124 + # sRecordName: 레코드 이름
125 + # sPrevNext: 다음 페이지가 있는지 여부. "2" : 다음페이지 존재, "0" or "" : 다음페이지 없음
126 + def _receive_tr_data(self,sScrNo,sRQName,sTrCode,sRecordName,sPrevNext):
127 + if sPrevNext=='2':
128 + self.remained_data=True
129 + else:
130 + self.remained_data=False
131 +
132 + if sRQName=="opt10081":
133 + print("==============주식일봉차트조회요청================")
134 + self._opt10081(sRQName,sTrCode)
135 + elif sRQName=="opw0001_req":
136 + return
137 + elif sRQName=="opw00018_req":
138 + return
139 + elif sRQName=="opt10074_req":
140 + return
141 + elif sRQName=="opw00015_req":
142 + return
143 + elif sRQName=="opt10076_req":
144 + return
145 + elif sRQName=="opt10073_req":
146 + return
147 +
148 + try:
149 + self.tr_event_loop.exit()
150 + except AttributeError:
151 + pass
152 +
153 + # 특정 종목의 일자별 거래 데이터 조회 함수
154 + # param : code - 종목코드
155 + # start - 기준일자
156 + # return : df - 특정종목의 일자별 거래 데이터 목록
157 + def get_total_data(self,code,start):
158 + self.ohlcv = {'date': [], 'open': [], 'high': [], 'low': [], 'close': [], 'volume': []}
159 +
160 + self._set_input_value("종목코드",code)
161 + self._set_input_value("기준일자",start)
162 + self._set_input_value("수정주가구분",1)
163 + self._comm_rq_data("opt10081_req","opt10081",0,self.screen_data_req)
164 +
165 + while self.remained_data:
166 + self._set_input_value("종목코드",code)
167 + self._set_input_value("기준일자",start)
168 + self._set_input_value("수정주가구분",1)
169 + self._comm_rq_data("opt10081_req","opt10081",2,self.screen_data_req)
170 +
171 + # 데이터가 없거나, date=''일 경우 empty list를 반환
172 + if len(self.ohlcv)==0:
173 + return []
174 + if self.ohlcv['date']=='':
175 + return []
176 +
177 + # 데이터를 DataFrame형태로 저장 및 반환
178 + df=DataFrame(self.ohlcv,columns=['open','high','low','close','volume'],index=self.ohlcv['date'])
179 +
180 + return df
181 +
182 + # 특정 종목의 특정 날짜의 시가,종가,고가,저가,거래량 중 특정한 데이터를 반환하는 함수
183 + # param : code - 종목코드
184 + # : date - 조회날짜
185 + # : option - open(시가)/close(종가)/high(고가)/low(저가)/volume(거래량)
186 + # return : 조회한 데이터에 해당하는 값
187 + # 값이 없거나, option이 오류일 경우 return False
188 + def get_oneday_option_data(self,code,date,option):
189 + self.ohlcv = {'date': [], 'open': [], 'high': [], 'low': [], 'close': [], 'volume': []}
190 +
191 + self._set_input_value("종목코드",code)
192 + self._set_input_value("기준일자",date)
193 + self._set_input_value("수정주가구분",1)
194 + self._comm_rq_data("opt10081_req","opt10081",0,self.screen_data_req)
195 +
196 + if self.ohlcv['date']=="":
197 + return False
198 +
199 + df = DataFrame(self.ohlcv, columns=['open', 'high', 'low', 'close', 'volume'], index=self.ohlcv['date'])
200 + if option == 'open':
201 + return df.iloc[0, 0]
202 + elif option == 'high':
203 + return df.iloc[0, 1]
204 + elif option == 'low':
205 + return df.iloc[0, 2]
206 + elif option == 'close':
207 + return df.iloc[0, 3]
208 + elif option == 'volume':
209 + return df.iloc[0, 4]
210 + else:
211 + return False
212 +
213 + # 사용자의 계좌정보 저장 및 출력
214 + def get_account_info(self):
215 + account=self.get_login_info("ACCNO")
216 + self.account_no=account.split(";")[0]
217 + print("======== 계좌번호 : ",self.account_no,"========")
218 +
219 + # 원하는 사용자 정보 반환
220 + # param : tag - ACCNO - 보유계좌리스트
221 + # ACCOUNT_CNT - 보유계좌 수
222 + # USER_ID - 사용자 ID
223 + # USER_NAME - 사용자 이름
224 + # KEY_BSECGB - 키보드 보안 해제 여부 (0 : 정상, 1: 해지)
225 + # FIREW_SECGB - 방화벽 설정여부 (0 : 미설정, 1: 설정, 2 : 해지)
226 + # GetServerGubun - 접속서버 구분 (1 : 모의투자, 나머지 : 실서버)
227 + # return : tag를 통해 요청한 정보(ret) 반환
228 + def get_login_info(self,tag):
229 + try:
230 + ret=self.dynamicCall("GetLoginInfo(QString)",tag)
231 + return ret
232 + except Exception as e:
233 + print(e)
234 + sys.exit()
235 +
236 + # 키움 api를 사용하기 위한 ocx controller 저장
237 + def create_instance(self):
238 + try:
239 + self.setControl("KHOPENAPI.KHOpenAPICtrl.1")
240 + except Exception as e:
241 + print(e)
242 + sys.exit()
243 +
244 + # event처리를 위한 slot
245 + def _signal_slots(self):
246 + try:
247 + self.OnEventConnect.connect(self._login_slot)
248 + self.OnReceiveTrData.connect(self._receive_tr_data)
249 + except Exception as e:
250 + print(e)
251 + sys.exit()
252 +
253 + # 수동 로그인설정인 경우 로그인창을 출력해서 로그인을 시도
254 + # 자동로그인 설정인 경우 로그인창 출력없이 로그인을 시도
255 + def comm_connect(self):
256 + try:
257 + self.dynamicCall("CommConnect()")
258 + self.login_event_loop.exec_()
259 + except Exception as e:
260 + print(e)
261 + sys.exit()
262 +
263 + # 로그인 이벤트 처리 slot
264 + # param : code - 로그인 성공 시 0
265 + # 실패 시 에러코드 출력
266 + def _login_slot(self,code):
267 + try:
268 + result=error_code.errors(code)
269 + if code==0:
270 + print("Connected",result[1])
271 + else:
272 + print("Failed to connect",result[1])
273 + self.login_event_loop.exit()
274 + except Exception as e:
275 + print(e)
276 + sys.exit()
277 +
278 + # 조회요청시 TR의 Input값을 지정하는 함수
279 + # param : sId - TR에 명시된 Input이름
280 + # svalue - Input이름으로 지정한 값
281 + def _set_input_value(self,sId,sValue):
282 + try:
283 + self.dynamicCall("SetInputValue(QString, QString)", sId, sValue)
284 + except Exception as e:
285 + print(e)
286 + sys.exit()
287 +
288 + # 조회요청함수
289 + # param : sRQName - 사용자 구분명
290 + # sTrCode - 조회하려는 TR이름
291 + # nPrevNext - 연속조회여부
292 + # sScreenNo - 화면번호
293 + def _comm_rq_data(self,sRQName,sTrData,nPrevNext,sScrNo):
294 + self.dynamicCall("CommRqData(QString, QString, int, QString", sRQName, sTrData, nPrevNext, sScrNo)
295 + self.tr_event_loop.exec_()
296 +
297 + # OnReceiveTRData()이벤트가 호출될때 조회데이터를 얻어오는 함수
298 + # param : sTrCode - TR 이름
299 + # sRecordName - 레코드이름
300 + # nIndex - TR반복부
301 + # sItemName - TR에서 얻어오려는 출력항목이름
302 + def _get_comm_data(self,sTrCode,sRecordName,nIndex,sItemName):
303 + ret = self.dynamicCall("GetCommData(QString, QString, int, QString", sTrCode, sRecordName, nIndex, sItemName)
304 + return ret.strip()
305 +
306 + # 조회수신한 멀티데이터의 갯수(반복)을 얻는다
307 + # param : sTrCode - tr이름
308 + # sRecordName - 레코드 이름
309 + def _get_repeat_cnt(self,sTrCode,sRecordName):
310 + try:
311 + ret=self.dynamicCall("GetRepeatCnt(QString, QString)",sTrCode,sRecordName)
312 + return ret
313 + except Exception as e:
314 + print(e)
315 + sys.exit()
316 +
317 +if __name__ == "__main__":
318 + app = QApplication(sys.argv)
319 + api=OpenApi()
...\ No newline at end of file ...\ No newline at end of file