이번 포스트는 지난번에 만든 PER, ROA를 가져오는 함수를 이용해서 전 종목의 PER과 ROA의 순위를 매긴다음 조엘그린블란트의 마법의 공식과 비슷하게 20개 종목을 고르는 코드를 작성해 보겠습니다.
지난 포스트는 아래 링크를 참고하세요.
2022.07.25 - [집구석 강의/파이썬으로 마법의 공식 구현하기] - 파이썬 마법의 공식 - 6. ROA 가져오기
def make_magic_df(year, date):
# #KRX 데이터 "종목코드", "종목명", "PER" 가져오기
codes = per(date)
codes['종목코드'] = codes.index
|
이번에는 바로 함수를 만들어서 함수 안에서 작성해 보도록 하겠습니다.
지난번에 만든 PER 함수를 이용해서 전 종목의 Code를 가져와서 'codes'라는 데이터프레임 형태의 변수에 넣겠습니다.
그리고 인덱스를 '종목코드'라는 컬럼으로 따로 만들도록 하겠습니다.
# ROA를 가져와서 데이트프레임 만들기
for num, code in enumerate(codes['종목코드']):
try:
if num == 0:
roa_df = get_roa(code, year)
else:
roa_df = pd.concat([roa_df, get_roa(code, year)])
time.sleep(0.01)
except:
pass
print(len(codes['종목코드']) - num, codes['종목명'][num])
|
지난번에 만든 ROA를 가져오는 함수는 코드를 인자로 일일이 넣어줘야 합니다.
2000개가 넘는 종목코드를 일일이 넣어 줄 수는 없기에 codes['종목코드'] 에서 code를 하나씩 빼서 "get_roa" 함수에 넣어줍니다.
이때 for 문에서 숫자가 순차적으로 표시되는 enumerate 함수를 사용합니다. 왜냐하면, 첫번째 가져오는 Dataframe은 "roa_df"라는 데이터프레임에 바로 넣어주고, 두번째 부터는 기존에 만든 Dataframe과 새로가져온 Dataframe을 "concat"로 합쳐줘야 하기 때문입니다.
예를 들어서 첫번째 삼성전자 ROA를 가져왔다면, 두번째 현대자동차 ROA를 가져와서 이 두 Data를 Dataframe 형태로 합쳐줍니다.
(※ Dataframe은 테이블 형식으로 가져오는 데이터를 말합니다. 좀 더 자세히 알고 싶으시면 "10 min for pandas"를 공부해 보시기 바랍니다.)
크롤링을 하는 것이기에 try 함수를 사용하고, 에러가 발생하면 과감하게 pass 하도록 하겠습니다.
그리고 실제로 실행되는지 실행창에서 확인해보기 위해 전체종목 숫자(len(codes['종목코드'])-num)를 하나씩 줄여가며, 해당 종목을 프린트 해 봅니다.
# 종목코드 칼럼을 index로 바꾸기
codes = codes.set_index('종목코드')
|
이제 칼럼으로 뺀 '종목코드'를 다시 index로 바꿉니다.
# ROA, ROA 문자형 데이터를 숫자로 변경
roa_df['ROA'] = pd.to_numeric(roa_df['ROA'], errors='coerce') #문자는 에러를 발생하므로 N/A로 변경
roa_df = roa_df['ROA'].dropna()
|
ROA는 문자형태로 가져옵니다. 순위를 구하기 위해서는 숫자형태로 변경할 필요가 있습니다.
"to_numeric" 함수의 옵션을 사용해서 "errors='coerce'" 로 공백이나, 숫자로 변경이 안되는 항목은 N/A로 변경합니다.
N/A 항목은 행으로 모두 삭제해 줍니다.
# 전체 마법의 공식 데이터 만들기
total_df = pd.merge(codes, roa_df, left_index=True, right_index=True)
# 값이 0인 행 제거
total_df = total_df[total_df['PER'] != 0]
|
get_roa 함수로 가져온 ROA 데이터와 get_per 함수로 가져온 '종목코드', '종목명', 'PER'을 합쳐줍니다.
PER 값이 0인 항목은 제거합니다.
# PER 순위매기기
total_df['per_rank'] = total_df['PER'].rank()
total_df['roa_rank'] = total_df['ROA'].rank(ascending=False)
total_df['total'] = total_df['per_rank'] + total_df['roa_rank']
total_df['total_rank'] = total_df['total'].rank()
total_df = total_df.sort_values(by=['total_rank'])
|
PER은 낮은 순서로 순위를 매기고, ROA는 높은 순서로 순위를 매깁니다. rank 함수를 사용하는데, 옵션에서 asccending=False 값으로 설정하면 높은 숫자부터 순위를 매깁니다.
PER 순위와 ROA 순위를 더한 다음 최종 순위를 매겨서 total_df['total_rank'] 컬럼에 표시합니다. 그리고 순위가 낮은 순서로 정렬을 합니다.
today = datetime.today().strftime('%y-%m-%d')
total_df.to_excel('Magic(' + today + ').xlsx')
return total_df
|
파일 이름에 작성한 날짜를 넣기 위해 'today'라는 변수를 만들어주고, 다 만든 Dataframe(total_df)은 엑셀로 변환해 줍니다.
전체 코드는 아래와 같으니 참고하시기 바랍니다.
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
|
from pykrx import stock
import pandas as pd
import requests
import time
from datetime import datetime
def per(date):
codes = stock.get_market_ticker_list(date, market='ALL')
corp = []
for code in codes:
name = stock.get_market_ticker_name(code)
corp.append([code, name])
df = pd.DataFrame(data=corp, columns=['종목코드', '종목명'])
df = df.set_index('종목코드')
df_f = stock.get_market_fundamental_by_ticker(date, market='ALL')
df = pd.merge(df, df_f, left_index=True, right_index=True)
return df
def get_roa(code, year):
url = 'https://comp.fnguide.com/SVO2/ASP/SVD_FinanceRatio.asp?pGB=1&gicode=A'+ code \
+'&cID=&MenuYn=Y&ReportGB=&NewMenuID=104&stkGb=701'
fr_page = requests.get(url)
fr_tables = pd.read_html(fr_page.text)
temp_df = fr_tables[0]
temp_df = temp_df.set_index(temp_df.columns[0]) #가져온 칼럼의 첫번째 열을 인덱스로 지정하기
temp_df = temp_df.loc[['ROA계산에 참여한 계정 펼치기']] #'ROA계산에 참여한 계정 펼치기' 행만 가져오기
temp_df.index = ['ROA'] #인덱스 이름을 'ROA'로 수정하기
temp_df = pd.DataFrame({code:temp_df[year]}) #가져올 시점에 따라 데이터프레임 만들기
temp_df = temp_df.transpose() #행과 열의 위치를 바꾸기
return temp_df
def make_magic_df(year, date):
# #KRX 데이터 "종목코드", "종목명", "PER" 가져오기
codes = per(date)
codes['종목코드'] = codes.index
# ROA를 가져와서 데이트프레임 만들기
for num, code in enumerate(codes['종목코드']):
try:
if num == 0:
roa_df = get_roa(code, year)
else:
roa_df = pd.concat([roa_df, get_roa(code, year)])
time.sleep(0.01)
except:
pass
print(len(codes['종목코드']) - num, codes['종목명'][num])
# 종목코드 칼럼을 index로 바꾸기
codes = codes.set_index('종목코드')
# ROA, ROA 문자형 데이터를 숫자로 변경
roa_df['ROA'] = pd.to_numeric(roa_df['ROA'], errors='coerce') #문자는 에러를 발생하므로 N/A로 변경
roa_df = roa_df['ROA'].dropna()
# 전체 마법의 공식 데이터 만들기
total_df = pd.merge(codes, roa_df, left_index=True, right_index=True)
# 값이 0인 행 제거
total_df = total_df[total_df['PER'] != 0]
# PER 순위매기기
total_df['per_rank'] = total_df['PER'].rank()
total_df['roa_rank'] = total_df['ROA'].rank(ascending=False)
total_df['total'] = total_df['per_rank'] + total_df['roa_rank']
total_df['total_rank'] = total_df['total'].rank()
total_df = total_df.sort_values(by=['total_rank'])
today = datetime.today().strftime('%y-%m-%d')
total_df.to_excel('Magic(' + today + ').xlsx')
return total_df
year = '2022/06'
date = '20220812'
print(make_magic_df(year, date))
|
cs |
제가 마법의 공식을 흉내내서 코드를 작성하다 보니깐 한 가지 문제점이 있더라구요.
fnguide에서 데이터를 가져오다 보니깐, 해당 페이지가 업데이트 되면(새로운 회계 데이터가 업데이트 되면) 에러가 발생하는 경우가 있습니다.
최근에 업데이트 된 시점(year 이라는 변수입니다.)으로 검색하셔만 해당 데이터가 잘 나옵니다. 이 점 참고하시기 바랍니다.
'파이썬(Python) > 마법의 공식' 카테고리의 다른 글
파이썬 마법의 공식 - 6. ROA 가져오기 (0) | 2022.07.25 |
---|---|
파이썬 마법의 공식 - 5. PER 가져오기 (2) | 2022.07.13 |
파이썬 마법의 공식 - 4. 모든 종목번호, 종목명 가져오기 (5) | 2022.06.28 |
파이썬 마법의 공식 - 3. 모듈(라이브러리) 설치하기 (0) | 2022.06.23 |
파이썬 마법의 공식 - 2. 파이썬 설치하기 (1) | 2022.06.20 |
댓글