常用估值方法的编程实现(1):自由现金流折现

  本文主要介绍自由现金流折现的意义、计算方法,以及基于python与Tushare数据接口的编程实现。参考资料主要为CFA二级Equity Evaluation的Free Cash Flow Evaluation部分。

自由现金流模型介绍

简介及计算

  自由现金流(Free Cash Flow,FCF)衡量公司/股东在不影响公司持续发展的前提下可供分配的最大金额,话句话说,其衡量的是一种提供股息的能力。FCF分两种,即FCFF和FCFE,F和E分别代表firm和equity。二者的计算公式分别为:
在这里插入图片描述
公式中,各符号代表如下:
NI:net income,当期净利润;
Int:interest,当期利息;
t:tax rate,税率;
NCC:non cash charge,非货币支出,一般有depreciation折旧、amortization摊销等等;
WC Inv:working capital investment,对于营运资本的投资,working capital=流动资产-流动负债。但对于流动资产不考虑账上的现金,而对于流动负债不考虑应付票据和长期票据的短期部分;
FC Inv:fixed capital investment,固定资产支出;
NB:net borrowing,净借贷。

估值

  利用自由现金流进行估值的大体思路实际就是对未来每一期预测的自由现金流进行折现,这样假定每年都有一个固定的永续增长率g的话,就可以用戈登增长模型(实际上就是从等比数列求和推出来的)进行计算,公式如下:
在这里插入图片描述

在这里插入图片描述需要说明的是,由于变量设置的原因,可能导致利用FCFF和FCFE进行的估值并不一致。

其他数据计算方法

折现率

  对于股票估值,折现率R有两种取法:1.取要求回报率、2.利用CAPM(资本资产定价模型)进行计算。对于前者直接赋值即可,对于后者计算方法如下。
CAPM模型:
在这里插入图片描述
此处Rf为无风险回报率,可取Shibor(上海银行间同业拆借利率)的值;
Rm为市场平均回报率,可以取指数在一定期间内的平均回报,注意由于复利的原因,这里的平均应该取几何平均而非算术平均;
Beta值的定义式如下:
在这里插入图片描述
可见,只要找到市场(还是用指数替代)和个股之间的关系,即可求得相应的Beta系数。

编程实现

编程求取折现率

  具体计算公式见Section 2.1。

无风险收益率计算:

ShiBOR = pro.shibor(start_date= TODAY, end_date= TODAY)
Rf = ShiBOR["1y"].values[0]
Rf = Rf / 100
print("-- Rf : ", Rf)

市场平均收益率计算:

year = int(TODAY[0 : 4]) - TERM
startDate = str(year) + TODAY[4 : ]
StockIndex =  pro.index_daily(ts_code= stockIndex, start_date= startDate, end_date= TODAY)
startPrice = StockIndex.loc[StockIndex.shape[0] -1, "close"]
endPrice = StockIndex.loc[0, "close"]
Rm = (endPrice / startPrice) ** (1 / TERM) - 1
print("-- Rm :", Rm)

beta计算:

indexTrend = StockIndex.loc[:, ["trade_date", "close"]]
indexTrend.columns = ["date", "index"]
stockDF = pro.daily(ts_code= stockCode, start_date= startDate, end_date= TODAY)
# stockDF = pro.index_daily(ts_code='399300.SZ', start_date= startDate, end_date= TODAY)
stockTrend = stockDF.loc[:, ["trade_date", "close"]]
stockTrend.columns = ["date", "stock"]
mergedDF = pd.merge(indexTrend, stockTrend, how= "inner", on= ["date"])     # Only keep those days both are traded
x = np.array(mergedDF.loc[:, "index"].values)
y = np.array(mergedDF.loc[:, "stock"].values)
Var = np.var(x)
Cov = np.cov(x, y)[0,1]
beta = Cov / Var
print("-- beta : ", beta)

折现率计算:

Ri = Rf + beta * (Rm - Rf)
print("-- Ri : ", Ri)

NI、NCC、WC_Inv、FC_Inv以及NB的编程计算

  具体计算公式见Section 1.1。另外有几点需要注意:
  1、NCC的计算利用了EBITDA与EBIT的差值,前者为earning before interest, tax, depreciation and amortization,后者为earning before interest and tax,差值正好是NCC;
  2、这里用到了tushare的财务数据接口,资产负债表pro.balancesheet和损益表pro.income,可能会涉及到一些积分不够无法调取的问题。

def GetFinancialData(pro, eachStockCode, STOCK_LIST, TODAY):

    line = STOCK_LIST.loc[STOCK_LIST["ts_code"] == eachStockCode].values[0]
    IPO_date = line[-1]
    IPO_year = int(IPO_date[0 : 4])
    if int(TODAY[4 : 6]) < 4 :
        Last_year = int(TODAY[0: 4]) - 2
    else:
        Last_year = int(TODAY[0 : 4]) - 1

    if Last_year - IPO_year <= 2 :
        return "new", "new", "new", "new", "new"

    total_cur_assets = []
    money_cap = []
    total_cur_liab = []
    notes_payable = []
    non_cur_liab_due_1y = []
    lt_borr = []
    st_borr = []
    n_income = []
    ebitda = []
    ebit = []
    fix_assets = []
    for i in range(Last_year - IPO_year):
        thisYear = IPO_year + i
        thisDate = str(thisYear) + "1231"

        BalanceSheet = pro.balancesheet(ts_code= eachStockCode, period= thisDate)
        BalanceSheet = BalanceSheet.fillna(0)
        total_cur_assets.append(BalanceSheet["total_cur_assets"].values[0])
        money_cap.append(BalanceSheet["money_cap"].values[0])
        total_cur_liab.append(BalanceSheet["total_cur_liab"].values[0])
        notes_payable.append(BalanceSheet["notes_payable"].values[0])
        non_cur_liab_due_1y.append(BalanceSheet["non_cur_liab_due_1y"].values[0])
        lt_borr.append(BalanceSheet["lt_borr"].values[0])
        st_borr.append(BalanceSheet["st_borr"].values[0])
        fix_assets.append(BalanceSheet["fix_assets"].values[0])

        IncomeSheet = pro.income(ts_code= eachStockCode, period= thisDate)
        IncomeSheet = IncomeSheet.fillna(0)
        n_income.append(IncomeSheet["n_income"].values[0])
        ebitda.append(IncomeSheet["ebitda"].values[0])
        ebit.append(IncomeSheet["ebit"].values[0])

    WC_Inv = []
    FC_Inv = []
    NB = []
    NCC = []
    NI = n_income[1 : len(n_income)]
    for eachYear in range(1, len(total_cur_assets)):
        CA = total_cur_assets[eachYear] - money_cap[eachYear]
        CA_0 = total_cur_assets[eachYear - 1] - money_cap[eachYear - 1]
        CL = total_cur_liab[eachYear] - notes_payable[eachYear] - non_cur_liab_due_1y[eachYear]
        CL_0 = total_cur_liab[eachYear - 1] - notes_payable[eachYear - 1] - non_cur_liab_due_1y[eachYear - 1]
        WC = CA - CL
        WC_0 = CA_0 - CL_0
        WC_Inv.append(WC - WC_0)

        borrowing = lt_borr[eachYear] + st_borr[eachYear] + notes_payable[eachYear]
        borrowing_0 = lt_borr[eachYear - 1] + st_borr[eachYear - 1] + notes_payable[eachYear - 1]
        NB.append(borrowing - borrowing_0)

        NCC.append(ebitda[eachYear] - ebit[eachYear])

        FC = fix_assets[eachYear]
        FC_0 = fix_assets[eachYear - 1]
        FC_Inv.append(FC - FC_0)

    return NI, NCC, WC_Inv, FC_Inv, NB

FCFE的编程计算

  具体计算公式见Section 1.1。

def CalculateFCFE(NI, NCC, WC_Inv, FC_Inv, NB, term):
    FCFE = []
    for i in range(len(NI)):
        fcfe = NI[i] + NCC[i] - WC_Inv[i] - FC_Inv[i] + NB[i]
        if fcfe < 0 :
            fcfe = 0
        FCFE.append(fcfe)

    start = FCFE[-term]
    last = FCFE[-1]
    g = (last / start) ** (1 / term) - 1

    return FCFE, g

主函数(估值)

  具体计算公式见Section 2.1。

TODAY = "20200213"
STOCK_CODE = "002410.SZ"
STOCK_INDEX = "000001.SH"
TERM = 7
alphaReturn = 5

pro = ts.pro_api("############################")
STOCK_LIST = pro.stock_basic(exchange='', list_status='L', fields='ts_code,symbol,name,area,industry,list_date')

NI, NCC, WC_Inv, FC_Inv, NB = GetFinancialData(pro, STOCK_CODE, STOCK_LIST, TODAY)
FCFE, g = CalculateFCFE(NI, NCC, WC_Inv, FC_Inv, NB, TERM)

r = CalculateDiscountRate(pro, STOCK_CODE, STOCK_INDEX, TODAY, TERM)
r = r / 100
ShiBOR = pro.shibor(start_date=TODAY, end_date=TODAY)
Rf = ShiBOR["1y"].values[0]
if (Rf + alphaReturn) / 100 > r :
    r = (Rf + alphaReturn) / 100

V_0 = FCFE[-1] * (1 + g) / (r - g)
daily = pro.daily_basic(ts_code= STOCK_CODE, trade_date= TODAY)
shares = daily["total_share"].values[0] * 10000
price = pro.daily(ts_code= STOCK_CODE, start_date= TODAY, end_date= TODAY)["close"].values[0]
value = V_0 / shares

print("NI : ", NI[-1])
print("NCC : ", NCC[-1])
print("WC_Inv : ", WC_Inv[-1])
print("FC_Inv : ", FC_Inv[-1])
print("NB : ", NB[-1])
print("FCFE : ", FCFE[-1])
print("g : ", g)
print("r : ", r)
print("V_0 : ", V_0 )
print("price : ", price)
print("value : ", value)

总结

  自由现金流折现是一种常用的估值方法,是我在学习CFA二级的时候学到的,之后就想着能否把整套估值方法代码话,进行自动化分析估值。CFA这个东西说实话学起来很杂,我希望可以尽量把我的学习成果总结后呈现给大家,以求达到知识共享的目的。
  对于代码、公式推导甚至经济金融原理,有没写清楚或者没有理解透的地方都可以与我交流(VX:Erich-Duan)。之后这个系列还会继续更新残余收益模型等等的基于python与tushare的实现。
  人生路漫漫,与诸君共勉。

  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值