상세 컨텐츠

본문 제목

파이썬으로 DCF 구현하기 4: 시각화, 실행함수

투자

by 하드리아누스 2021. 6. 29. 11:41

본문

프로젝트 구조

코드 구현의 순서는 다음과 같습니다.

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데이터를 불러오는데 문제가 있습니다. 보통 필요한 정보가 누락된 경우에 발생합니다. 혹은 종목 코드를 다시 입력해보십시오.")

 

관련글 더보기