Calculating Weighted Average Cost of Capital (WACC) with Python

In this post we are going to learn how to build a model to calculate a firm weighted average cost of capital (WACC) with Python. We will learn what is WACC and how to calculate it step by step. Then, in my next post already published, we will apply WACC to estimate the value of a company using the discounted cash flow method.

Calculating Weighted Average Cost of Capital with Python
Photo by Karolina Grabowska from Pexels

What is the Weighted Average Cost of Capital (WACC)?

The WACC is a firm cost of capital. Is the capital rate that a firm is expected to pay on average to all its security holders. As we will see in the formula of next section, the WACC uses cost of debt, cost of equity, capital structure of a firm and tax rate.

A company capital structure is important to compute WACC since it uses the blended cost of capital across all sources of capital (i.e. cost of debt and cost of equity).

The tax rate is used in WACC due to the tax effects of interest payments. Interest payments can be deducted from the taxable income. For every USD in interest payments, a company can save its firm tax rate in tax payments.

Why do we need WACC in Finance?

WACC is commonly used as a discount rate to calculate the net present value of a company. For example, when valuing a company using the Discounted Cash Flow model, we should use WACC to discount future free cash flows. We will see in my next post how to value a company using the Discounted Cash Flow model.

How to calculate WACC?

We can calculate a firm’s weighted average cost of capital by applying below formula:

WACC = Kd * (1 -Tc) * (D /D+E) + Ke * (E /D+E)

Where:

  • WACC = Weighted Average Cost of Capital
  • Kd = Cost of debt
  • Tc = Firm tax rate
  • Ke = Cost of equity
  • D / D + E = Proportion of debt in firm capital structure

Let’s see how can we get each of this elements:

Companies Cost of Debt

To estimate a firm cost of debt, we could follow one of below two approaches:

a. Calculate the bond yields to maturity of a company existing tradable bonds. Yield to maturity is a good proxy for cost of debt. The problem is that this approach would require to look into each company and look what is the most representative bond to use as a proxy for cost of debt. Some companies may have more than 10 bonds available. Therefore, it is difficult to automate this approach with Python and may be time consuming to do it manually.

b. Therefore, we are going to use a different approach. We will use the credit rating of companies to calculate the credit spread. Then, we will apply below formula to get our cost of debt (Kd).

Kd = Rf + Credit Spread

Not all companies may have a credit rating available. Even if they have a publish credit rating, we would need to do some manual work to find online the rating for a particular company. As a workaround, we are going to calculate a synthetic credit rating for companies based on their interest coverage ratio.

Then, based on Damodaran site rating system, we can calculate the credit spread based on below table.

Calculate Cost of Debt with Pyhton
Calculate Cost of Debt with Pyhton

For the Risk free rate we will use the interest rate offered by a 1 year US T-bill which currently is around 0.15%.

Companies Cost of Equity

To estimate a company cost of equity we can use two different approaches; the Capital Asset Pricing Model (CAPM) or the dividend discount model. I have already covered how to use these two models to estimate the cost of equity in two of my previous posts. Refer to below links if you want to learn more on how to calculate cost of equity with Python:

Companies Capital Structure and Tax Rate

The firm capital structure and tax rate can be extracted from looking into company financial reports. In the next section, we will learn how to extract this information with Python in a programmatically way.

Calculating WACC with Python

Time to move to the coding part of the post. We are going to build different functions in Python in order to get the needed elements to compute a company WACC. In this example, we will calculate the WACC of Microsoft.

First, we will estimate the cost of debt, then we will calculate the cost of equity using the CAPM method. Finally, we will retrieve the company tax rate and capital structure to compute the company WACC.

Note that we are going to retrieve all financials required for our computation from financialmodelingprep API. It is a great financial API which offer up to 250 free requests per month. Alternatively, if 250 requests are not enough, you can get a yearly subscription for a bit more of $100. Financialmodelingprep offers a 25% discount to all readers of this blog by using this link.

The way the code is going to work is very simple. We will have three functions. One to estimate the cost of debt, another one to estimate the cost of equity and a third one to get the company tax rate, capital structure and calculate WACC.

Lets start by creating the function to calculate the cost of debt.

Estimating Cost of Debt with Python

First of all we will import all packages required to calculate WACC with Python. Then, we need to create a function to calculate the interest coverage ratio and risk free rate. Remember that we will use the interest coverage to create a synthetic credit rating and therefore estimate the cost of debt with it.

For the code to work, please ensure that you have created an account in financialmodelingprep. Then, replace your api key within the demo variable. Use the following link to benefit from a 25% discount on the yearly subscription.

The risk free rate can be retrieved by using pandas_datareader and extracting the 1- year treasury bills. Then, we take the most recent data point. That will be our risk free rate required to estimate the cost of debt.

import pandas_datareader.data as web
import datetime
import requests

company = 'MSFT'
demo = 'your api key'

def interest_coveraga_and_RF(company):
  IS= requests.get(f'https://financialmodelingprep.com/api/v3/income-statement/{company}?apikey={demo}').json()
  EBIT= IS[0]['ebitda'] - IS[0]['depreciationAndAmortization'] 
  interest_expense = IS[0]['interestExpense']
  interest_coverage_ratio = EBIT / interest_expense

    #RF
  start = datetime.datetime(2019, 7, 10)
        
  end= datetime.datetime.today().strftime('%Y-%m-%d')
  #end = datetime.datetime(2020, 7, 10)

  Treasury = web.DataReader(['TB1YR'], 'fred', start, end)
  RF = float(Treasury.iloc[-1])
  RF = RF/100
  print(RF, interest_coverage_ratio)
  return [RF,interest_coverage_ratio]

interest_coverage_and_RF(company)

#outcome
RF is 0.0018 
Interest Coverage Ratio is 15.99367088607595

Having calculated the interest coverage ratio and risk free rate, we can move to estimate the cost of debt. We will have a cost of debt function that will take as arguments the name of the company, the risk free rate (RF) and the interest coverage ratio.

Note that what we are doing is replicate the credit rating system proposed on the Damodaran site with Python. Based on the interest coverage ratio calculated before, we will estimate the credit spread to calculate the cost of debt.

def cost_of_debt(company, RF,interest_coverage_ratio):
  if interest_coverage_ratio > 8.5:
    #Rating is AAA
    credit_spread = 0.0063
  if (interest_coverage_ratio > 6.5) & (interest_coverage_ratio <= 8.5):
    #Rating is AA
    credit_spread = 0.0078
  if (interest_coverage_ratio > 5.5) & (interest_coverage_ratio <=  6.5):
    #Rating is A+
    credit_spread = 0.0098
  if (interest_coverage_ratio > 4.25) & (interest_coverage_ratio <=  5.49):
    #Rating is A
    credit_spread = 0.0108
  if (interest_coverage_ratio > 3) & (interest_coverage_ratio <=  4.25):
    #Rating is A-
    credit_spread = 0.0122
  if (interest_coverage_ratio > 2.5) & (interest_coverage_ratio <=  3):
    #Rating is BBB
    credit_spread = 0.0156
  if (interest_coverage_ratio > 2.25) & (interest_coverage_ratio <=  2.5):
    #Rating is BB+
    credit_spread = 0.02
  if (interest_coverage_ratio > 2) & (interest_coverage_ratio <=  2.25):
    #Rating is BB
    credit_spread = 0.0240
  if (interest_coverage_ratio > 1.75) & (interest_coverage_ratio <=  2):
    #Rating is B+
    credit_spread = 0.0351
  if (interest_coverage_ratio > 1.5) & (interest_coverage_ratio <=  1.75):
    #Rating is B
    credit_spread = 0.0421
  if (interest_coverage_ratio > 1.25) & (interest_coverage_ratio <=  1.5):
    #Rating is B-
    credit_spread = 0.0515
  if (interest_coverage_ratio > 0.8) & (interest_coverage_ratio <=  1.25):
    #Rating is CCC
    credit_spread = 0.0820
  if (interest_coverage_ratio > 0.65) & (interest_coverage_ratio <=  0.8):
    #Rating is CC
    credit_spread = 0.0864
  if (interest_coverage_ratio > 0.2) & (interest_coverage_ratio <=  0.65):
    #Rating is C
    credit_spread = 0.1134
  if interest_coverage_ratio <=  0.2:
    #Rating is D
    credit_spread = 0.1512
  
  cost_of_debt = RF + credit_spread
  print(cost_of_debt)
  return cost_of_debt
kd = cost_of_debt(company,RF,interest_coverage_ratio)
#outcome
0.0081 # 0.8% is the estimated cost of debt for Microsoft

Great, we see that the estimated cost of debt for Microsoft is 0.8%. Lets now move to calculate the cost of equity.

Estimating Cost of Equity with Python

Since I have already covered this topic in one of my previous posts on how to calculate ROE with Python. I will simply provide the code in this post.

Note that we use the yearly SP500 return as a proxy for market return.

The only element that we do not calculate and we take directly from the API is the company beta. I will create a separate post in the future showing how to estimate the beta of a company using Python. For now, let’s rely on the beta estimation provided by financialmodelingprep:

def costofequity(company):
  #RF
  start = datetime.datetime(2019, 7, 10)
  end= datetime.datetime.today().strftime('%Y-%m-%d')
  #end = datetime.datetime(2020, 7, 10)
  Treasury = web.DataReader(['TB1YR'], 'fred', start, end)
  RF = float(Treasury.iloc[-1])
  RF = RF/100

#Beta
  beta = requests.get(f'https://financialmodelingprep.com/api/v3/company/profile/{company}?apikey={demo}')
  beta = beta.json()
  beta = float(beta['profile']['beta'])

  #Market Return
  start = datetime.datetime(2019, 7, 10)
  end= datetime.datetime.today().strftime('%Y-%m-%d')

  SP500 = web.DataReader(['sp500'], 'fred', start, end)
      #Drop all Not a number values using drop method.
  SP500.dropna(inplace = True)

  SP500yearlyreturn = (SP500['sp500'].iloc[-1]/ SP500['sp500'].iloc[-252])-1
    
  cost_of_equity = RF+(beta*(SP500yearlyreturn - RF))
  print(cost_of_equity)
  return cost_of_equity

costofequity(company)
#outcome
0.0695424296147323

We get that the cost of equity for Microsoft is 6.9%. We are getting there, let’s now get the effective tax rate and capital structure of Microsoft to finally compute Microsoft WACC.

Weighted Average Cost of Capital (WACC) with Python

Finally, we can now retrieve from the API the effective tax rate, total debt and total equity. Then, we will have all required elements to compute the WACC for Microsoft (or any other company).

#effective tax rate and capital structure
def wacc(company):
#effective tax rate
  FR = requests.get(f'https://financialmodelingprep.com/api/v3/ratios/{company}?apikey={demo}').json()
  ETR = FR[0]['effectiveTaxRate']

#capital structure 
  BS = requests.get(f'https://financialmodelingprep.com/api/v3/balance-sheet-statement/{company}?period=quarter&apikey={demo}').json()
  Debt_to = BS[0]['totalDebt'] / (BS[0]['totalDebt'] + BS[0]['totalStockholdersEquity'])
  equity_to = BS[0]['totalStockholdersEquity'] / (BS[0]['totalDebt'] + BS[0]['totalStockholdersEquity'])

#wacc
  WACC = (kd*(1-ETR)*Debt_to) + (ke*equity_to)
  print(WACC,equity_to,Debt_to)
  return WACC
wacc_company = wacc(company)
print('wacc of ' + company + ' is ' + str((wacc_company*100))+'%')

#outcome
wacc of MSFT is 4.0239263558674985%

We can see that our WACC estimation for Microsoft is 4.02%.

Wrapping Up

Nice! We have built a model to estimate the Weighted Average Cost of Capital (WACC) with Python for any company. Simply, pass the ticker of the company that you would like to calculate WACC for in the variable company. Please note that when executing the code, if a company ticker is not available in the financialmodelingprep API, you may get an error.

Now that we know how to compute WACC with Python, we are ready to apply it to different valuation methods in order to discount future values. In my next post, we are going to use WACC in order to value a company using the Discounted Cash Flow method.

Thanks a lot for reading. If you have liked the article, feel free to share it in social media.

Also, see below video for all of you who prefer to have a look at the video tutorial:

WACC with Python

Below you can see the whole code used in this post for your reference:

#cost of equity
import pandas_datareader.data as web
import datetime
import requests


company = 'MSFT'
demo = 'your api key'
#Interest coverage ratio = EBIT / interest expenses

def interest_coveraga_and_RF(company):
  IS= requests.get(f'https://financialmodelingprep.com/api/v3/income-statement/{company}?apikey={demo}').json()
  EBIT= IS[0]['ebitda'] - IS[0]['depreciationAndAmortization'] 
  interest_expense = IS[0]['interestExpense']
  interest_coverage_ratio = EBIT / interest_expense

    #RF
  start = datetime.datetime(2019, 7, 10)
        
  end= datetime.datetime.today().strftime('%Y-%m-%d')
  #end = datetime.datetime(2020, 7, 10)

  Treasury = web.DataReader(['TB1YR'], 'fred', start, end)
  RF = float(Treasury.iloc[-1])
  RF = RF/100
  print(RF,interest_coverage_ratio)
  return [RF,interest_coverage_ratio]
  

#Cost of debt
def cost_of_debt(company, RF,interest_coverage_ratio):
  if interest_coverage_ratio > 8.5:
    #Rating is AAA
    credit_spread = 0.0063
  if (interest_coverage_ratio > 6.5) & (interest_coverage_ratio <= 8.5):
    #Rating is AA
    credit_spread = 0.0078
  if (interest_coverage_ratio > 5.5) & (interest_coverage_ratio <=  6.5):
    #Rating is A+
    credit_spread = 0.0098
  if (interest_coverage_ratio > 4.25) & (interest_coverage_ratio <=  5.49):
    #Rating is A
    credit_spread = 0.0108
  if (interest_coverage_ratio > 3) & (interest_coverage_ratio <=  4.25):
    #Rating is A-
    credit_spread = 0.0122
  if (interest_coverage_ratio > 2.5) & (interest_coverage_ratio <=  3):
    #Rating is BBB
    credit_spread = 0.0156
  if (interest_coverage_ratio > 2.25) & (interest_coverage_ratio <=  2.5):
    #Rating is BB+
    credit_spread = 0.02
  if (interest_coverage_ratio > 2) & (interest_coverage_ratio <=  2.25):
    #Rating is BB
    credit_spread = 0.0240
  if (interest_coverage_ratio > 1.75) & (interest_coverage_ratio <=  2):
    #Rating is B+
    credit_spread = 0.0351
  if (interest_coverage_ratio > 1.5) & (interest_coverage_ratio <=  1.75):
    #Rating is B
    credit_spread = 0.0421
  if (interest_coverage_ratio > 1.25) & (interest_coverage_ratio <=  1.5):
    #Rating is B-
    credit_spread = 0.0515
  if (interest_coverage_ratio > 0.8) & (interest_coverage_ratio <=  1.25):
    #Rating is CCC
    credit_spread = 0.0820
  if (interest_coverage_ratio > 0.65) & (interest_coverage_ratio <=  0.8):
    #Rating is CC
    credit_spread = 0.0864
  if (interest_coverage_ratio > 0.2) & (interest_coverage_ratio <=  0.65):
    #Rating is C
    credit_spread = 0.1134
  if interest_coverage_ratio <=  0.2:
    #Rating is D
    credit_spread = 0.1512
  
  cost_of_debt = RF + credit_spread
  print(cost_of_debt)
  return cost_of_debt


def costofequity(company):


  #RF
  start = datetime.datetime(2019, 7, 10)
  end= datetime.datetime.today().strftime('%Y-%m-%d')
  #end = datetime.datetime(2020, 7, 10)

  Treasury = web.DataReader(['TB1YR'], 'fred', start, end)
  RF = float(Treasury.iloc[-1])
  RF = RF/100

#Beta

  beta = requests.get(f'https://financialmodelingprep.com/api/v3/company/profile/{company}?apikey={demo}')
  beta = beta.json()
  beta = float(beta['profile']['beta'])


  #Market Return
  start = datetime.datetime(2019, 7, 10)
  end= datetime.datetime.today().strftime('%Y-%m-%d')

  SP500 = web.DataReader(['sp500'], 'fred', start, end)
      #Drop all Not a number values using drop method.
  SP500.dropna(inplace = True)

  SP500yearlyreturn = (SP500['sp500'].iloc[-1]/ SP500['sp500'].iloc[-252])-1
    
  cost_of_equity = RF+(beta*(SP500yearlyreturn - RF))
  print(cost_of_equity)
  return cost_of_equity

#effective tax rate and capital structure
def wacc(company):
  FR = requests.get(f'https://financialmodelingprep.com/api/v3/ratios/{company}?apikey={demo}').json()

  ETR = FR[0]['effectiveTaxRate']

# 
  BS = requests.get(f'https://financialmodelingprep.com/api/v3/balance-sheet-statement/{company}?period=quarter&apikey={demo}').json()



  Debt_to = BS[0]['totalDebt'] / (BS[0]['totalDebt'] + BS[0]['totalStockholdersEquity'])
  equity_to = BS[0]['totalStockholdersEquity'] / (BS[0]['totalDebt'] + BS[0]['totalStockholdersEquity'])

  WACC = (kd*(1-ETR)*Debt_to) + (ke*equity_to)
  print(WACC,equity_to,Debt_to)
  return WACC

company = 'MSFT'
demo = 'your api key'

RF_and_IntCov = interest_coveraga_and_RF(company)
RF = RF_and_IntCov[0]
interest_coverage_ratio = RF_and_IntCov[1]
ke = costofequity(company)
kd = cost_of_debt(company,RF,interest_coverage_ratio)
wacc_company = wacc(company)
print('wacc of ' + company + ' is ' + str((wacc_company*100))+'%')

3 thoughts on “Calculating Weighted Average Cost of Capital (WACC) with Python

  1. Hi,

    Having some trouble understanding what’s going on when I run the first bit of code to calculate the interest coverage.

    —————————————————————————
    NameError Traceback (most recent call last)
    in
    20 return [RF,interest_coverage_ratio]
    21
    —> 22 interest_coverage_and_RF(company)

    NameError: name ‘interest_coverage_and_RF’ is not defined

    1. Hi,

      To me it seems that you did not create the function below in your code

      def interest_coveraga_and_RF(company):

      Be sure that the function is above the line where you call it.

      Hope that solves it

  2. yes, when i calculate the WACC i get a (TypeError: can’t multiply sequence by non-int of type ‘float’.)

Comments are closed.