Q-Bot 업데이트 231017
본문 바로가기
파이썬으로 만든 것들/퀀트투자 업그레이드

Q-Bot 업데이트 231017

by Squat Lee 2024. 3. 11.

백테스트를 실행한대로 주식종목을 골라주도록 기능을 추가했다.

 

다음에는 Factor를 Check Box로 바꿔서 공간효율성을 꾸며야겠다.

 

Q-Bot13.ui
0.03MB

 

전체코드는 아래와 같다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
import sqlite3
import pandas as pd
from pykrx import stock
import time
from datetime import datetime, timedelta
import random
 
ui = uic.loadUiType('Q-Bot13.ui')[0]
 
class Window(QMainWindow, ui):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.db_update()  # 시작하면 DB부터 업데이트
 
        # 시작년도 Combobox 만들기
        for sy in range(20032023):
            self.cb_start.addItem(str(sy))
 
        # 백테스트의 마지막년도 Combobox 만들기
        for ey in range(20042023):
            self.cb_end.addItem(str(ey))
 
        # 백테스트할 월을 Combobox로 만들기
        for m in range(113):
            self.cb_month.addItem(str(m))
 
        # 백테스트할 날짜를 Combobox로 만들기
        for ㅇ in range(132):
            self.cb_day.addItem(str(ㅇ))
 
        # 백테스트 투자종목 개수를 Combobox로 만들기
        for c in range(2031):
            self.cb_count.addItem(str(c))
 
        # 거래대금을 Combobox로 만들기
        for t in range(01000000000010000000):
            self.cb_transamount.addItem(f'{t:,}')
 
        # 거래대금 이상/이하를 Combobox로 만들기
        for tml in ['이상''이하']:
            self.cb_transmoreless.addItem(tml)
 
        # 시가총액을 Combobox로 만들기
        for mc in range(01000000000000010000000000):
            self.cb_cap.addItem(f'{mc:,}')
 
        # 시가총액 이상/이하를 Combobox로 만들기
        for cml in ['이상''이하']:
            self.cb_cap_moreless.addItem(cml)
 
        # 백테스트 버튼과 연결 시그널
        self.btn_test.clicked.connect(self.back_test)
 
        # 투자종목 개수를 Combobox로 만들기
        for fc in range(2031):
            self.cb_filter_count.addItem(str(fc))
 
        # 투자를 하기위해 기준일을 선택하는 콤보박스 만들기
        con = sqlite3.connect('krx_data_new.db')
 
        # DB에서 마지막 행 구하기
        db_last_df = pd.read_sql("SELECT 일자 FROM fund ORDER BY ROWID DESC LIMIT 1", con)
        db_last_date = db_last_df['일자'].iloc[0]  # 마지막 행에서 날짜 구하기
 
        # 마지막 날짜를 기준으로 콤보박스에 나올 날짜 List 만들기
        df_date_list = pd.read_sql("SELECT 일자 FROM fund WHERE 일자 LIKE '" + db_last_date[:4+ "%'", con)
 
        list_date = []
        for f_date in df_date_list['일자']:
            if f_date not in list_date:
                list_date.append(f_date)
        list_date = list_date[-20:] #최근 20일치만 보여주기
        list_date.reverse() #최근일부터 보여주기 위해 순서를 뒤집기
 
        for f in list_date:
            self.cb_filter_day.addItem(f)
 
        # 투자종목고르기 버튼과 연결 시그널
        self.btn_filter.clicked.connect(self.stock_filter)
 
    def back_test(self):
        try:
            con = sqlite3.connect('krx_data_new.db')
 
            # DB에 있는 날짜인지 확인하여 없으면 근처일로 변경
            def near_business_day(b_start, b_month, b_day):
                df_date = pd.read_sql("SELECT 일자 FROM fund WHERE 일자 LIKE " + "'" + b_start + "%'", con)
                df_date.drop_duplicates(inplace=True)
                li_df = df_date['일자'].tolist()
 
                date = b_start + b_month + b_day
                if date in li_df:
                    b_date = date
                else:
                    if int(b_day) < 15#날짜가 15미만이면 1씩 더해서 영업일 구하기
                        while 10#10번 정도 더하기 반복해서 DB에 있는 날짜 구하기
                            b_day = int(b_day) + 1
                            b_day = str(b_day).zfill(2)
                            b_date = date[:6+ b_day
                            if b_date in li_df:
                                break
                    else#날짜가 15이상이면 1씩 빼면서 영업일 구하기
                        while 10:
                            b_day = int(b_day) - 1
                            b_day = str(b_day).zfill(2)
                            b_date = date[:6+ b_day
                            if b_date in li_df:
                                break
                return b_date
 
            b_start = self.cb_start.currentText() #백테스트 시작년도
            b_end = self.cb_end.currentText() #백테스트 마지막 년도
            b_month = self.cb_month.currentText() #백테스트를 할 월
            b_month = b_month.zfill(2#월이 한자리 수일때 앞에 0을 채우기
            b_day = self.cb_day.currentText() #백테스트 할 날짜
            b_day = b_day.zfill(2#일이 한자리 수일때 앞에 0을 채우기
            count = int(self.cb_count.currentText()) #백테스트 투자종목 개수
 
            #Group Box의 Radio Button, 백테스트 할 요소 선택하기
            if self.rb_pbr.isChecked():
                col1 = 'PBR'
            elif self.rb_dps.isChecked():
                col1 = 'DPS'
            elif self.rb_per.isChecked():
                col1 = 'PER'
            elif self.rb_hcapital.isChecked():
                col1 = '시가총액'
            elif self.rb_lcapital.isChecked():
                col1 = '시가총액'
            elif self.rb_heps.isChecked():
                col1 = 'EPS'
            elif self.rb_leps.isChecked():
                col1 = 'EPS'
            elif self.rb_hdiv.isChecked():
                col1 = 'DIV'
            elif self.rb_ldiv.isChecked():
                col1 = 'DIV'
            print(col1)
 
            if self.rb_pbr_2.isChecked():
                col2 = 'PBR'
            elif self.rb_dps_2.isChecked():
                col2 = 'DPS'
            elif self.rb_per_2.isChecked():
                col2 = 'PER'
            elif self.rb_hcapital_2.isChecked():
                col2 = '시가총액'
            elif self.rb_lcapital_2.isChecked():
                col2 = '시가총액'
            elif self.rb_heps_2.isChecked():
                col2 = 'EPS'
            elif self.rb_leps_2.isChecked():
                col2 = 'EPS'
            elif self.rb_hdiv_2.isChecked():
                col2 = 'DIV'
            elif self.rb_ldiv_2.isChecked():
                col2 = 'DIV'
            print(col2)
 
            trans_amount = self.cb_transamount.currentText() #거래대금을 변수로 지정
            trans_amount = int(trans_amount.replace(',''')) #쉼표를 빼고 정수로 변경
            market_cap = self.cb_cap.currentText() #시가총액을 변수로 지정
            market_cap = int(market_cap.replace(',''')) #쉼표를 빼고 정수로 변경
 
            li_result = [] #년도와 수익률을 담을 리스트
            i = 0 #첫번째 년도를 확인하기 위해 만든 임의 변수
            self.tw_backdata.clear() #Back Data용 Text Edit 기존내용 지우기
            self.te_return.clear() #Result에 기존내용 지우기
            self.lbl_cagr.clear()
            self.lbl_mdd.clear()
            self.lbl_count_lost.clear()
            self.lbl_mean_lost.clear()
            self.lbl_acc_return.clear()
            for b_year in range(int(b_start), int(b_end)+1):
 
                b_date = near_business_day(str(b_year), b_month, b_day) #백테스트 기준일을 영업일로 변경
                print(b_date)
 
                if col1 == col2:
                    df = pd.read_sql("SELECT 일자, code, 종목명, 종가, 거래량, 거래대금, 상장주식수, " + col1 +
                                     " FROM Fund WHERE 일자= " + b_date, con)
                elif col1 == "시가총액" or col2 =="시가총액"#시가총액이 선택되었는지 확인
                    df = pd.read_sql("SELECT 일자, code, 종목명, 종가, 거래량, 거래대금, 상장주식수, " + col1 +
                                     ", " + col2 + " FROM Fund WHERE 일자= " + b_date, con)
                else:
                    df = pd.read_sql("SELECT 일자, code, 종목명, 종가, 거래량, 거래대금, 상장주식수, 시가총액, " + col1 +
                                     ", " + col2 + " FROM Fund WHERE 일자= " + b_date, con)
 
                df = df[(df['거래량'> 0& (df[col1] > 0& (df[col2] > 0)]  # 거래량, col1, col2가 0이상인 종목만 가져오기
 
                # 일 거래대금 조건 적용하기
                if self.cb_transmoreless.currentText() == "이상":
                    df = df[df['거래대금'>= trans_amount]
                else:
                    df = df[df['거래대금'< trans_amount]
 
                # 시가총액 조건 적용하기
                if self.cb_cap_moreless.currentText() == "이상":
                    df = df[df['시가총액'>= market_cap]
                else:
                    df = df[df['시가총액'< market_cap]
 
                if col1 == col2:
                    # col1 순위매기기
                    if self.rb_hcapital.isChecked() or self.rb_heps.isChecked() or self.rb_hdiv.isChecked():
                        df[col1 + '_rank'= df[col1].rank(ascending=False)  # 높은 순서대로 순위 매기기
                    else:
                        df[col1 + '_rank'= df[col1].rank()  # 낮은 순서대로 순위 매기기
 
                    df.sort_values(by=col1 + '_rank', inplace=True)  # 낮은 순서대로 정렬하기
 
                else:
                    # col1 순위매기기
                    if self.rb_hcapital.isChecked() or self.rb_heps.isChecked() or self.rb_hdiv.isChecked():
                        df[col1 + '_rank'= df[col1].rank(ascending=False)  # 높은 순서대로 순위 매기기
                    else:
                        df[col1 + '_rank'= df[col1].rank()  # 낮은 순서대로 순위 매기기
 
                    # col2 순위매기기
                    if self.rb_hcapital_2.isChecked() or self.rb_heps_2.isChecked() or self.rb_hdiv_2.isChecked():
                        df[col2 + '_rank'= df[col2].rank(ascending=False)  # 높은 순서대로 순위 매기기
                    else:
                        df[col2 + '_rank'= df[col2].rank()  # 낮은 순서대로 순위 매기기
 
                    df[col1 + '_' + col2] = df[col1 + '_rank'+ df[col2 + '_rank']  # 순위 매긴것을 더하기
                    df[col1 + '_' + col2 + '_' + 'rank'= df[col1 + '_' + col2].rank()  # 최종순위 구하기
                    df.sort_values(by=col1 + '_' + col2 + '_' + 'rank', inplace=True)  # 낮은 순서대로 정렬하기
                print(df)
                print(count)
                df = df.iloc[:count]  # 지정한 개수만 구하기
 
                # 1년후의 날짜 구하기
                date_later = near_business_day(str(b_year+1), b_month, b_day)
 
                # 1년후의 날짜로 데이터 가져오기
                df_later = pd.read_sql("SELECT 일자, code, 종가, 상장주식수 FROM fund WHERE 일자= " + date_later, con)
                df_later.columns = ['1년후의_일자''code''1년후_종가''1년후_상장주식수']
 
                df = pd.merge(df, df_later, on='code')
 
                df['수익률'= ((df['1년후_종가'- df['종가']) / df['종가'])
                profit = df['수익률'].sum()/count
                li_result.append([b_date, profit])
 
                if i == 0:  # 첫번째 날짜는 만들어진 dataframe이 df_t로 저장되고, 나머지는 계속 concat로 붙여넣기
                    df_t = df
                else:
                    df_t = pd.concat([df_t, df])
 
                prb = i / (int(b_end) - int(b_start)) * 100  # Progress Bar
                self.prb.setValue(prb)  # Progress Bar
 
                i += 1
 
            df_t['종가'= df_t['종가'].apply(lambda x: '{:,}'.format(x))
            df_t['거래량'= df_t['거래량'].apply(lambda x: '{:,}'.format(x))
            df_t['거래대금'= df_t['거래대금'].apply(lambda x: '{:,}'.format(x))
            df_t['상장주식수'= df_t['상장주식수'].apply(lambda x: '{:,}'.format(x))
            df_t['시가총액'= df_t['시가총액'].apply(lambda x: '{:,}'.format(x))
            # df_t['PBR'] = df_t['PBR'].apply(lambda x: round(x, 2))
            df_t['수익률'= df_t['수익률'].apply(lambda x: round(x * 1002))
            print(df_t)
 
            # 수익률의 Back Data를 Table Widget에 나타내기
            self.tw_backdata.setRowCount(len(df_t))
            self.tw_backdata.setColumnCount(len(df_t.columns))
            self.tw_backdata.setHorizontalHeaderLabels(df_t.columns.tolist())
            for b_row in range(len(df_t)):
                for b_col in range(len(df_t.columns)):
                    self.tw_backdata.setItem(b_row, b_col, QTableWidgetItem(str(df_t.iloc[b_row, b_col])))
 
            df_result = pd.DataFrame(data=li_result, columns=['투자년도''수익률'])  # 투자년도와 수익률로 데이터프레임 만들기
 
            li_acc = []
            for n, p in enumerate(df_result['수익률']):
                if n == 0:
                    li_acc.append(1 + p)
                else:
                    li_acc.append(li_acc[n - 1* (1 + p))
 
            df_result['누적수익률'= pd.DataFrame(data=li_acc, columns=['누적수익률'])
            cagr = (df_result['누적수익률'].iloc[-1]) ** (1 / len(df_result)) - 1
            cagr = str(round(cagr * 1002))
            self.lbl_cagr.setText(cagr + '%'#CAGR 레이블에 나타내기
 
            MDD = df_result['수익률'].min()
            self.lbl_mdd.setText(f'{MDD*100:.2f}%'#MDD를 Label에 표시
            f_acc_return = df_result['누적수익률'].iloc[-1]
            self.lbl_acc_return.setText(f'{f_acc_return*100:,.2f}%'#누적수익률을 Label에 표시
            df_lost = df_result[df_result['수익률']<0]
            count_lost = df_lost['수익률'].count()
            self.lbl_count_lost.setText(f'{count_lost}'#손실횟수
            mean_lost = df_lost['수익률'].mean()
            self.lbl_mean_lost.setText(f'{mean_lost*100:.2f}%'#손실평균
 
            #수익률을 TextEdit에 나타내기
            self.te_return.setText('투자시기     수익률     누적수익률')
            for row in range(len(df_result)):
                invest_y = str(df_result['투자년도'].iloc[row])
                return_rate = df_result['수익률'].iloc[row]
                acc_return = df_result['누적수익률'].iloc[row]
                self.te_return.append(f'{invest_y}      {return_rate:.2f}         {acc_return:.2f}')
 
            #Excel Export를 선택시 엑셀파일에 결과 저장
            if self.rb_excel.isChecked():
                trans_amount = self.cb_transamount.currentText()  # 거래대금을 변수로 지정
                market_cap = self.cb_cap.currentText()  # 시가총액을 변수로 지정
                transmoreless = self.cb_transmoreless.currentText()
                cap_moreless = self.cb_cap_moreless.currentText()
                cagr = cagr.split('.')
                print(cagr[0])
                MDD = str(MDD*100).split('.')
                print(MDD[0])
                # 하나의 엑셀파일에 2개의 시트를 저장하기 위해 ExcelWriter 함수를 사용
                writer = pd.ExcelWriter(col1+' '+col2+'백테스트결과 CAGR'+cagr[0]+' MDD'+MDD[0]+' 거래대금'+trans_amount
                                        +transmoreless+' 시가총액'+market_cap+cap_moreless+'.xlsx')
                df_result.to_excel(writer, sheet_name='년도별수익률')
                df_t.to_excel(writer, sheet_name='BackData')
                writer.save()
        except:
            pass
 
    def stock_filter(self):
        try:
 
            filter_day = self.cb_filter_day.currentText() #투자할 종목을 고를 기준일
            filter_count = int(self.cb_filter_count.currentText()) #투자종목 개수
 
            #Group Box의 Radio Button, 백테스트 할 요소 선택하기
            if self.rb_pbr.isChecked():
                col1 = 'PBR'
            elif self.rb_dps.isChecked():
                col1 = 'DPS'
            elif self.rb_per.isChecked():
                col1 = 'PER'
            elif self.rb_hcapital.isChecked():
                col1 = '시가총액'
            elif self.rb_lcapital.isChecked():
                col1 = '시가총액'
            elif self.rb_heps.isChecked():
                col1 = 'EPS'
            elif self.rb_leps.isChecked():
                col1 = 'EPS'
            elif self.rb_hdiv.isChecked():
                col1 = 'DIV'
            elif self.rb_ldiv.isChecked():
                col1 = 'DIV'
            print(col1)
 
            if self.rb_pbr_2.isChecked():
                col2 = 'PBR'
            elif self.rb_dps_2.isChecked():
                col2 = 'DPS'
            elif self.rb_per_2.isChecked():
                col2 = 'PER'
            elif self.rb_hcapital_2.isChecked():
                col2 = '시가총액'
            elif self.rb_lcapital_2.isChecked():
                col2 = '시가총액'
            elif self.rb_heps_2.isChecked():
                col2 = 'EPS'
            elif self.rb_leps_2.isChecked():
                col2 = 'EPS'
            elif self.rb_hdiv_2.isChecked():
                col2 = 'DIV'
            elif self.rb_ldiv_2.isChecked():
                col2 = 'DIV'
            print(col2)
 
            trans_amount = self.cb_transamount.currentText() #거래대금을 변수로 지정
            trans_amount = int(trans_amount.replace(',''')) #쉼표를 빼고 정수로 변경
            market_cap = self.cb_cap.currentText() #시가총액을 변수로 지정
            market_cap = int(market_cap.replace(',''')) #쉼표를 빼고 정수로 변경
 
            con = sqlite3.connect('krx_data_new.db')
 
            if col1 == "시가총액" or col2 == "시가총액":  # 시가총액이 선택되었는지 확인
                df_f = pd.read_sql("SELECT 일자, code, 종목명, 종가, 거래량, 거래대금, 상장주식수, " + col1 +
                                 ", " + col2 + " FROM Fund WHERE 일자= " + filter_day, con)
            else:
                df_f = pd.read_sql("SELECT 일자, code, 종목명, 종가, 거래량, 거래대금, 상장주식수, 시가총액, " + col1 +
                                 ", " + col2 + " FROM Fund WHERE 일자= " + filter_day, con)
 
            # 거래량, PBR, DPS가 모두 0 이상인 종목만 가져오기
            df_f = df_f[(df_f['거래량'> 0& (df_f['PBR'> 0& (df_f['DPS'> 0)]
            # 일 거래대금 조건 적용하기
            if self.cb_transmoreless.currentText() == "이상":
                df_f = df_f[df_f['거래대금'>= trans_amount]
            else:
                df_f = df_f[df_f['거래대금'< trans_amount]
 
            # 시가총액 조건 적용하기
            if self.cb_cap_moreless.currentText() == "이상":
                df_f = df_f[df_f['시가총액'>= market_cap]
            else:
                df_f = df_f[df_f['시가총액'< market_cap]
 
            # col1 순위매기기
            if self.rb_hcapital.isChecked() or self.rb_heps.isChecked() or self.rb_hdiv.isChecked():
                df_f[col1 + '_rank'= df_f[col1].rank(ascending=False)  # 높은 순서대로 순위 매기기
            else:
                df_f[col1 + '_rank'= df_f[col1].rank()  # 낮은 순서대로 순위 매기기
 
            # col2 순위매기기
            if self.rb_hcapital_2.isChecked() or self.rb_heps_2.isChecked() or self.rb_hdiv_2.isChecked():
                df_f[col2 + '_rank'= df_f[col2].rank(ascending=False)  # 높은 순서대로 순위 매기기
            else:
                df_f[col2 + '_rank'= df_f[col2].rank()  # 낮은 순서대로 순위 매기기
 
            df_f[col1 + '_' + col2] = df_f[col1 + '_rank'+ df_f[col2 + '_rank']  # 순위 매긴것을 더하기
            df_f[col1 + '_' + col2 + '_' + 'rank'= df_f[col1 + '_' + col2].rank()  # 최종순위 구하기
            df_f.sort_values(by=col1 + '_' + col2 + '_' + 'rank', inplace=True)  # 낮은 순서대로 정렬하기
 
            df_f = df_f.iloc[:filter_count]  # 지정한 개수만 구하기
 
            df_f['PBR_RANK'= df_f['PBR'].rank()  # 낮은 순서대로 순위매기기
            df_f['DPS_RANK'= df_f['DPS'].rank()  # 낮은 순서대로 순위매기기
            df_f['PBR_DPS'= df_f['PBR_RANK'+ df_f['DPS_RANK']  # 순위매긴걸 더하기
            df_f['PBR_DPS_RANK'= df_f['PBR_DPS'].rank()  # 최종순위 구하기
            df_f.sort_values(by='PBR_DPS_RANK', inplace=True)  # 낮은 순서대로 정렬하기
 
            # index를 1~20으로 reset 하기
            li_num = []
            for num in range(len(df_f)):
                li_num.append(num+1)
            df_f = df_f.set_index([li_num])
            print(df_f)
 
            # 수익률의 Back Data를 Table Widget에 나타내기
            self.tw_backdata.setRowCount(len(df_f))
            self.tw_backdata.setColumnCount(len(df_f.columns))
            self.tw_backdata.setHorizontalHeaderLabels(df_f.columns.tolist())
            for row in range(len(df_f)):
                for col in range(len(df_f.columns)):
                    print(str(df_f.iloc[row, col]))
                    self.tw_backdata.setItem(row, col, QTableWidgetItem(str(df_f.iloc[row, col])))
 
            #Excel Export를 선택시 엑셀파일에 결과 저장
            if self.rb_excel_invest.isChecked():
                trans_amount = self.cb_transamount.currentText()  # 거래대금을 변수로 지정
                market_cap = self.cb_cap.currentText()  # 시가총액을 변수로 지정
                transmoreless = self.cb_transmoreless.currentText()
                cap_moreless = self.cb_cap_moreless.currentText()
 
                # 엑셀파일에 투자할 항목 List 저장
                df_f.to_excel('투자할종목List('+ col1 + 'x' + col2 + '시가총액' + market_cap + transmoreless +
                                        '거래대금' + trans_amount + cap_moreless + ')' + filter_day + '.xlsx')
        except:
            pass
 
    # DB 업데이트
    def db_update(self):
        try:
            con = sqlite3.connect('krx_data_new.db')
 
            # 오늘날짜 기준으로 아직 받지않은 Data를 DB에 다운로드 받기
            # 영업일을 List로 가져오기
            def make_date_list(start, end):
                start = datetime.strptime(start, '%Y%m%d')
                end = datetime.strptime(end, '%Y%m%d')
                dates = [(start + timedelta(days=i)).strftime('%Y%m%d'for i in range((end - start).days + 1)]
                b_dates = []
                for d in dates:
                    b_day = stock.get_nearest_business_day_in_a_week(d)
                    if not b_day in b_dates:
                        b_dates.append(b_day)
                        s = random.randint(13)
                        time.sleep(s)
 
                return b_dates
 
            # Data를 다운로드 받기
            def data_download(date):
                codes = stock.get_market_ticker_list(date, market='ALL')  # code list 만들기
                corp = []  # Code와 Name을 저장할 List
                for code in codes:
                    name = stock.get_market_ticker_name(code)  # 종목 이름 가져오기
                    corp.append([code, name])  # Code와 이름으로 리스트를 만들기
                df1 = pd.DataFrame(data=corp, columns=['code''종목명'])  # code와 종목명을 데이터프레임으로 만들기
                df1.index = df1['code']  # index를 코드로 만들기
 
                df_f = stock.get_market_fundamental_by_ticker(date=date,
                                                              market='ALL')  # BPS, PER, PBR, EPS, DIV, DPS 가져와서 데이터 프레임 만들기
                df_c = stock.get_market_cap_by_ticker(date=date, market='ALL')  # 종가, 시가총액, 거래량, 거래대금, 상장주식수 가져오기
 
                time.sleep(1)
 
                df = pd.merge(df1, df_c, left_index=True, right_index=True)  # 종목명, 종가, 시가총액, 거래량, 거래대금, 상장주식수
                df = pd.merge(df, df_f, left_index=True, right_index=True)  # 위에 df + PER, PBR...
                # column은 '종목명', '종가', '시가총액', '거래량', '거래대금', '상장주식수', 'BPS', 'PER', 'PBR', 'EPS', 'DIV', 'DPS'
 
                df['일자'= date
                df = df.set_index('일자')
                df = df[['code''종목명''종가''시가총액''거래량''거래대금''상장주식수''BPS''PER''PBR',
                         'EPS''DIV''DPS']]
 
                return df
 
            # DB에서 마지막 행 구하기
            db_last_df = pd.read_sql("SELECT 일자, code, 종목명, DIV, DPS FROM fund ORDER BY ROWID DESC LIMIT 1",
                                     con)
            db_last_date = db_last_df['일자'].iloc[0]  # 마지막 행에서 날짜 구하기
            db_last_date = datetime.strptime(db_last_date, '%Y%m%d')
            start_date = (db_last_date + timedelta(days=1)).strftime('%Y%m%d')
 
            # 오늘날짜 구하기
            today = datetime.today().strftime('%Y%m%d')
            end_date = stock.get_nearest_business_day_in_a_week(today, prev=True)
            print(end_date)
 
            # 데이터 받아서 데이터프레임으로 합치고, DB에 저장
            if start_date <= end_date:
                try:
                    dates = make_date_list(start_date, end_date)
                    print(dates)
                    for n, date in enumerate(dates):
                        print(date)
                        if n == 0:
                            t_df = data_download(date)
                        else:
                            t_df = pd.concat([t_df, data_download(date)])
                        self.prb.setValue(int((n + 1/ len(dates) * 100))  # 진행 상태바 표시
                        time.sleep(0.1)  # 혹시나 차단될 수 있으니깐
                    t_df.to_sql('fund', con, if_exists='append')
                    print(t_df)
                except:
                    pass
            con.close()
 
        except:
            pass
 
if __name__=='__main__':
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    app.exec_()
 
 
cs

 

728x90
반응형

댓글