프로젝트 구조
코드 구현의 순서는 다음과 같습니다.
1. 요약 재무제표 크롤링
- FCFF 도출에 필요한 항목들만 추려내서 데이터 프레임으로 정리하기
- 각 항목들의 추정치 도출하기 (ex 매출액의 연평균성장률, 평균 매출원가율)
2. 정제된 재무제표를 바탕으로 미래 FCFF 추정하기
- 1번에서 구한 추정치를 바탕으로 FCFF추정하기
- 사용자의 시나리오에 따라 FCFF 추정하기
3. WACC 값 도출을 위한 크롤링
- Rf, Rm, B 등등 크롤링해오기
4. 주가가치 산출하기
- 앞선 과정으로 얻어진 값들로 회사가치, 주가가치 계산하기
- wacc, 영구성장률 변화에 따른 민감도 차이 보여주기
5. 시각화
- 민감도별 시각화하기
마지막 글입니다 5번 + 최종실행함수입니다.
사실 그냥 복붙이라 금방금방 써냈습니다ㅎ 아마 지금단계에서는 막히는 기업들도 많아서 부끄러운 수준이고 선택된 수치들도 조오금 그런 것들이 존재합니다. 만약 반응이 좋다면.. 꾸준히 수정해보겠습니다.(안좋아도 하긴할거임.. 늦을뿐)
class analysis:
def __init__(self, company, stockvalue, BS, FIS, stockvalue_t):
self._company = company
self._stockvalue = stockvalue
self._stock_value_t = stockvalue_t
self._stockprice = 0
self._concensus = ''
self._BS = BS
self._FIS = FIS
def today_stockprice(self):
ft = re.compile('\w+')
comp = ft.match(self._company).group()
url = 'https://comp.fnguide.com/SVO2/asp/SVD_Main.asp?pGB=1&gicode={}&cID=&MenuYn=Y&ReportGB=&NewMenuID=101&stkGb=701'.format(self._company)
response = requests.get(url)
if response.status_code == 200:
html = response.text
soup = BeautifulSoup(html, 'html.parser')
stockprice_r = soup.select_one('#svdMainChartTxt11')
else :
print(response.status_code)
ft = re.compile('\d+\,?\d+')
stock_t = stockprice_r.get_text()
stock = ft.match(stock_t)
stock = int(stock.group().replace(',',''))
self._stockprice = stock
print("__________________________________________________________________________________________")
print("전일 종가는 {}원 입니다.".format(self._stockprice))
return self._stockprice
def visualization(self):
wacc = self._stock_value_t.columns[2]
pg = self._stock_value_t.index[2]
x = np.arange(5)
pg_s = list(self._stock_value_t.index)
price1 = list(self._stock_value_t.iloc[:][wacc])
wacc_s = list(self._stock_value_t.columns)
price2 = list(self._stock_value_t.iloc[2][:])
f1 = plt.figure()
plt.title('Price trend by Pg')
plt.bar(x, price1)
plt.xticks(x, labels = pg_s)
plt.annotate("previous close", xy = (3,self._stockprice), xytext = (3.25,0.85*self._stockprice),
arrowprops=dict(arrowstyle="-", linewidth=1, color='r'))
plt.xlabel('Perpetual growth rate')
plt.ylabel('stock Price')
plt.axhline(self._stockprice,0, 1, color = 'r')
for i, v in enumerate(x):
plt.text(v, price1[i], price1[i], fontsize = 9,color='k',
horizontalalignment='center',verticalalignment='bottom')
f2 = plt.figure()
plt.title('Price trend by Wacc')
plt.bar(x, price2)
plt.xticks(x, labels = wacc_s)
plt.annotate("previous close", xy = (3,self._stockprice), xytext = (3.25,0.85*self._stockprice),
arrowprops=dict(arrowstyle="-", linewidth=1, color='r'))
plt.xlabel('WACC')
plt.ylabel('stock Price')
plt.axhline(self._stockprice,0, 1, color = 'r')
for i, v in enumerate(x):
plt.text(v, price2[i], price2[i], fontsize = 9,color='k',
horizontalalignment='center',verticalalignment='bottom')
f3 = plt.figure()
value = [self._stock_value_t.iloc[0][4],self._stock_value_t.iloc[1][3],
self._stockvalue,self._stockprice,self._stock_value_t.iloc[3][1],self._stock_value_t.iloc[4][0]]
x = [0,0.25,0.5,0.5,0.75,1]
plt.title('Target Zone')
plt.scatter(x,value)
plt.xlabel('Pg-WACC')
plt.ylabel('stock Price')
span_start = self._stockprice
span_end = 1.4*self._stockprice
plt.axhspan(span_start, span_end, facecolor='r', alpha = 0.3)
plt.annotate("Target Zone", xy = (0.5,self._stockprice), xytext = (0.6,0.85*self._stockprice),
arrowprops=dict(arrowstyle="-", linewidth=1, color='r'))
for i, v in enumerate(x):
plt.text(v, value[i], value[i], fontsize = 9,color='k',
horizontalalignment='center',verticalalignment='bottom')
plt.show()
print("#3번 그래프: x축 진행방향으로 갈수록 pg와 wacc 격차가 축소됨\n\n")
def concensus(self):
potential = round((self._stockvalue/self._stockprice - 1)*100,2)
if potential >= 40:
self._concensus = 'too high'
elif potential >= 10:
self._concensus = 'Buy'
elif 0 <= potential < 10:
self._concensus = 'Hold'
elif potential <= 0:
self._concensus = 'Sell'
print("산출된 주가 - 현재 주가 = {}".format(self._stockvalue-self._stockprice))
print("potentail = {}%".format(potential))
print("최종 의견: {}".format(self._concensus))
return self._concensus
def advise(self):
if self._concensus == 'Sell':
print("\n현재 가정하에 미래 현금흐름이 부족합니다.\n")
if (self._FIS.iloc[0][4]/self._FIS.iloc[0][0] - 1) > (self._FIS.iloc[8][4]/self._FIS.iloc[8][0] - 1):
print("수익성 개선이 필요합니다. 매출원가율, 판관비율을 줄일 필요가 있습니다.")
print("재고자산 회전율을 높이고 매출채권 비중을 낮춰야합니다. 또 미지급금을 줄여서 최종적으로 NWC를 낮춰야합니다.")
elif (self._FIS.iloc[0][4]/self._FIS.iloc[0][0] - 1) < (self._FIS.iloc[8][4]/self._FIS.iloc[8][0] - 1):
print("매출 성장률이 더 높아야 합니다.")
elif self._concensus == 'too high':
print("비현실적인 가정일 가능성이 높습니다. 수치 재조정이 권장됩니다.")
import datetime
import time
def checkTime(func):
def new_func(*args):
print("\n------------------------------------------------")
start = time.time();
func(*args)
print("\n실행시간:",time.time()-start)
print("------------------------------------------------\n")
return new_func
@checkTime
def do_valuation():
try:
IS, BS, CF, company = load_FS()
object1 = step1(company,IS, BS, CF)
tax = object1.Basic_IS()
object1.Basic_CF()
object1.Dnwc()
object1.FCFF()
fcff_table = object1.mktable()
object2 = step2(fcff_table,tax)
object2.ratios()
object2.Assume()
forecasts = object2.forecast()
forecasts
object3 = WACC(company, BS, tax)
object3.risk_free_rate()
object3.market_risk_premium()
object3.beta()
object3.cost_debt()
wacc = object3.wacc()
object4 = DCF(forecasts, wacc , company)
object4.pv_FCFF()
object4.TV()
object4.NOA_IBD()
stockvalue, table = object4.EV()
stockvalue
object5 = analysis(company, stockvalue, BS, forecasts, table)
object5.today_stockprice()
object5.visualization()
cons = object5.concensus()
cons
object5.advise()
except:
print("\n데이터를 불러오는데 문제가 있습니다. 보통 필요한 정보가 누락된 경우에 발생합니다. 혹은 종목 코드를 다시 입력해보십시오.")
ETF 입문1 (0) | 2021.08.11 |
---|---|
[아티클 리뷰] 국내 유니콘 기업의 큰손의 대부분 외국자본? (0) | 2021.07.26 |
파이썬으로 DCF 구현하기 3: 주가 산출 (0) | 2021.06.29 |
파이썬으로 DCF 구현하기 2: 추정 및 WACC값 구하기 (0) | 2021.06.29 |
파이썬으로 DCF 구현하기 1: 과거재무제표 크롤링, FCFF 도출 (1) | 2021.06.29 |