In partnership with

Wake up to better business news

Some business news reads like a lullaby.

Morning Brew is the opposite.

A free daily newsletter that breaks down what’s happening in business and culture — clearly, quickly, and with enough personality to keep things interesting.

Each morning brings a sharp, easy-to-read rundown of what matters, why it matters, and what it means to you. Plus, there’s daily brain games everyone’s playing.

Business news, minus the snooze. Read by over 4 million people every morning.

Elite Quant Plan – 7-Day Free Trial (This Week Only)

No card needed. Cancel anytime. Zero risk.

You get immediate access to:

  • Full code from every article (including today’s HMM notebook)

  • Private GitHub repos & templates

  • All premium deep dives (3–5 per month)

  • 2 × 1-on-1 calls with me

  • One custom bot built/fixed for you

Try the entire Elite experience for 14 days — completely free.

→ Start your free trial now 👇

(Doors close in 7 days or when the post goes out of the spotlight — whichever comes first.)

See you on the inside.

👉 Upgrade Now

🔔 Limited-Time Holiday Deal: 20% Off Our Complete 2026 Playbook! 🔔

Level up before the year ends!

AlgoEdge Insights: 30+ Python-Powered Trading Strategies – The Complete 2026 Playbook

30+ battle-tested algorithmic trading strategies from the AlgoEdge Insights newsletter – fully coded in Python, backtested, and ready to deploy. Your full arsenal for dominating 2026 markets.

Special Promo: Use code WINTER2026 for 20% off

Valid only until February 10, 2026 — act fast!

👇 Buy Now & Save 👇

Instant access to every strategy we've shared, plus exclusive extras.

— AlgoEdge Insights Team

Premium Members – Your Full Notebook Is Ready

The complete Google Colab notebook from today’s article (with live data, full Hidden Markov Model, interactive charts, statistics, and one-click CSV export) is waiting for you.

Preview of what you’ll get:

Inside:

  • Key Steps in DCF Model

  • Retrieving Fundamental Data via FMP

  • Future Growth Estimates from Analysts’ Projections

  • Calculate Cost of Equity and Debt

  • Effective Tax Rate and WACC

  • Discounting Cash Flows and Terminal Value

  • Intrinsic Value Per Share & Margin of Safety

  • Sensitivity Analysis — WACC, Growth Rates and Fair Values

  • Unlevered Discounted Cash Flow

  • Beautiful interactive Plotly charts

  • Regime duration & performance tables

  • Ready-to-use CSV export

  • Bonus: works on Bitcoin, SPX, or any ticker with one line change

Free readers – you already got the full breakdown and visuals in the article. Paid members – you get the actual tool.

Not upgraded yet? Fix that in 10 seconds here👇

Google Collab Notebook With Full Code Is Available In the End Of The Article Behind The Paywall 👇 (For Paid Subs Only)

Serious investors should have the ability to estimate the fair value of assets they invest in.

Bill Ackman, for instance, emphasizes the importance of factors like discount rates and growth projections when assessing the company value.

A model that relies on these factors is the Discounted Cash Flow’ model, which estimates a company’s intrinsic value by projecting and discounting future cash flows.

However, as you’ll see next, it’s not an exact science and depends heavily on the analyst’s assumptions and knowledge.

In this guide, we will break down the DCF model into clear steps using fundamental data obtained via the Financial Modeling Prep (FMP) API.

We will show you how to project future cash flows, discount them to their present value, and calculate the terminal value.

To help you apply these steps, we’ve prepared an end-to-end Google Colab notebook. This will allow you to implement the model yourself and adjust the key assumptions as needed.

Someone just spent $236,000,000 on a painting. Here’s why it matters for your wallet.

The WSJ just reported the highest price ever paid for modern art at auction.

While equities, gold, bitcoin hover near highs, the art market is showing signs of early recovery after one of the longest downturns since the 1990s.

Here’s where it gets interesting→

Each investing environment is unique, but after the dot com crash, contemporary and post-war art grew ~24% a year for a decade, and after 2008, it grew ~11% annually for 12 years.*

Overall, the segment has outpaced the S&P by 15 percent with near-zero correlation from 1995 to 2025.

Now, Masterworks lets you invest in shares of artworks featuring legends like Banksy, Basquiat, and Picasso. Since 2019, investors have deployed $1.25 billion across 500+ artworks.

Masterworks has sold 25 works with net annualized returns like 14.6%, 17.6%, and 17.8%.

Shares can sell quickly, but my subscribers skip the waitlist:

*Per Masterworks data. Investing involves risk. Past performance not indicative of future returns. Important Reg A disclosures: masterworks.com/cd

This article is structured as follows:

  • Key Steps in DCF Model

  • Retrieving Fundamental Data via FMP

  • Future Growth Estimates from Analysts’ Projections

  • Calculate Cost of Equity and Debt

  • Effective Tax Rate and WACC

  • Discounting Cash Flows and Terminal Value

  • Intrinsic Value Per Share & Margin of Safety

  • Sensitivity Analysis — WACC, Growth Rates and Fair Values

  • Unlevered Discounted Cash Flow

1. The Discounted Cash Flow model (‘DCF’)

DCF model estimates the present value of a company by projecting future free cash flows and discounting them back to the present using a discount rate:

Here are FCFt are the future projected cash flows, r is the discount rate, TV is the terminal value. We’ll discuss each in detail.

Step 1. Project Future Free Cash Flows:

The first step in the DCF model is to project the company’s future free cash flows.

These cash flows represent the amount of cash a company generates after accounting for capital expenditures:

To project FCF, start with the most recent FCF and apply a growth rate, g:

This growth rate is based on the company’s earnings projections, industry averages, or analyst estimates.

Cash flows are forecasted until a stable growth period is expected, often 5 to 10 years into the future.

Step 2. Discount Cash Flows:

The next step is to discount the future FCFs to their present value using a discount rate, usually derived from the Weighted Average Cost of Capital’.

WACC reflects the company’s cost of equity and debt, adjusted for tax effects:

By discounting future cash flows, you determine what those future dollars are worth today.

Please note that calculting the cost of equity and the cost of debt involves its own process which we will discuss in the implementation below.

Step 3. Calculate Terminal Value:

Next, estimate the terminal value, which accounts for all future cash flows beyond the forecast period. The terminal value represents the company’s value at the end of the projection period.

This can be calculated using the Gordon Growth Model. In this model, you need to assume a constant ‘perpetual’ growth rate that reflects long-term expectations.

One can set the perpetual growth rate, g, at 2% or 3% to align with long-term economic growth or inflation expectations.

The Headlines Traders Need Before the Bell

Tired of missing the trades that actually move?

In under five minutes, Elite Trade Club delivers the top stories, market-moving headlines, and stocks to watch — before the open.

Join 200K+ traders who start with a plan, not a scroll.

Step 4. Calculate Enterprise Value

With the discounted FCFs and terminal value in hand, you can calculate the enterprise value of the company.

This is done by summing the present value of the projected FCFs and the discounted terminal value.

The enterprise value represents the total value of the company’s operations in today’s terms.

Step 5. Calculate Net Debt:

To move from enterprise value to equity value, subtract net debt. This adjustment accounts for the company’s financial obligations. The remaining value reflects what is available to equity investors.

Net debt is simply the company’s total debt minus its cash and cash equivalents.:

Next step is to isolate the value that belongs to shareholders:

Step 6. Calculate Intrinsic Value per Share

Finally, divide the equity value by the number of shares outstanding to calculate the intrinsic value per share.

This value represents what each share of the company is worth based on the DCF model.

Comparing this intrinsic value to the current market price will help you determine whether the stock is undervalued or overvalued.

2. Programatic Implementation with FMP API

Let’s now set up the code for pulling in the financial data, and calculating everything needed for the DCF model.

We’ll build the DCF model programmatically to make the process more efficient and flexible when tweaking assumptions for different scenarios.

2.1 Libraries and Ticker

First, ensure these libraries are installed:

  • yfinance: For retrieving stock price data from Yahoo Finance.

  • numpy and pandas: For data manipulation and numerical operations.

  • requests: For making requests to the Financial Modeling Prep API.

  • and BeautifulSoup: For scraping additional financial data from web sources (e.g. analyst’ growth rates estimates).

import yfinance as yf
import numpy as np
import pandas as pd
import requests
from bs4 import BeautifulSoup
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings("ignore")

Then, we need to set up the variables required to pull data for the stock we are analyzing.

We’ll use NVIDIA (ticker: NVDA) as an example, but you can replace it with any other stock ticker.

FMP_API_KEY = ""  # Replace with your actual API key
FMP_BASE_URL = "https://financialmodelingprep.com/api/v3/"
HEADERS = {'User-Agent': 'Mozilla/5.0'}
ticker = "NVDA"  # Example Company ticker
  • FMP_API_KEY: Your API key for accessing the Financial Modeling Prep API.

  • FMP_BASE_URL: The base URL for API endpoints.

  • HEADERS: These headers are necessary for making the API requests.

The Financial Modeling Prep API give you access to a wide range of financial data, including but not limited to:

  • Real-time stock, crypto, forex market data

  • Historical financial statement data spanning over 30 years

  • Analyst ratings and forecasts

  • Earnings announcements

  • Automatic real-time valuation metrics

Sign up to FMP with 15% Discount. Free version of the API also available.

2.2 Cash Flow

Next, we retrieve the company’s cash flow statement. Free Cash Flows are typically stated directly. If not, you can deduce them by deducing capital expenses from operating cash flows.

We’ll use the FMP API to pull in the cash flow data for the last four quarter. After pulling the data, we sum up the last four quarters to get the Trailing Twelve Months cash flow. This gives the latest full year’s worth of cash flow data:


cash_flow_url = f"{FMP_BASE_URL}cash-flow-statement/{ticker}?period=quarter&limit=4&apikey={FMP_API_KEY}"
cash_flow_response = requests.get(cash_flow_url)
cash_flow_data = cash_flow_response.json()
cash_flow_df = pd.DataFrame(cash_flow_data)

# Sum the last 4 quarters to simulate TTM (Trailing Twelve Months)
cash_flow_ttm = cash_flow_df.iloc[:4].sum(numeric_only=True)

# Add a "Trailing Twelve Month" column header
cash_flow_ttm = pd.DataFrame(cash_flow_ttm, columns=["Trailing Twelve Months"])

print("TTM Cash Flow Data (Summed Last 4 Quarters):")
cash_flow_ttm

Figure. 1: Trailing Twelve Months Cash Flow Statement Data for NVDA.

2.3 Income Statement

Now, let’s grab the income statement data. This is where we get a clear picture of the company’s profitability —Interest Expense, Pretax Income, and Tax Provision.

We’ll focus these key figures for calculating Cost of Debt and the True Value of the Firm.

Similarly to Cash Flows, we sum up the last four quarters to get the TTM totals.

income_statement_url = f"{FMP_BASE_URL}income-statement/{ticker}?period=quarter&limit=4&apikey={FMP_API_KEY}"
income_statement_response = requests.get(income_statement_url)
income_statement_data = income_statement_response.json()
income_statement_df = pd.DataFrame(income_statement_data)

# Sum the last 4 quarters to simulate TTM (Trailing Twelve Months)
income_statement_ttm = income_statement_df.iloc[:4].sum(numeric_only=True)

# Add a "Trailing Twelve Months" column header
income_statement_ttm = pd.DataFrame(income_statement_ttm, columns=["Trailing Twelve Months"])

print("TTM Income Statement Data (Summed Last 4 Quarters):")
income_statement_ttm

Figure. 2: Trailing Twelve Months Income Statement Data for NVDA.

2.4 Balance Sheet

The balance sheet provides a snapshot of the company’s financial position — Assets, liabilities, and equity at a specific point in time.

For our purposes, we’re particularly interested in the company’s total debt, which we’ll use to calculate the cost of debt.

balance_sheet_url = f"{FMP_BASE_URL}balance-sheet-statement/{ticker}?period=quarter&limit=1&apikey={FMP_API_KEY}"
balance_sheet_response = requests.get(balance_sheet_url)
balance_sheet_data = balance_sheet_response.json()
balance_sheet_df = pd.DataFrame(balance_sheet_data)
print("Balance Sheet Data:")
pd.DataFrame(balance_sheet_df).T

Figure. 3: Latest Balance Sheet Quarter Data for NVDA.

2.5 Calculating Cost of Debt

2.5.1 Effective Tax Rate

To calculate the cost of debt, we first need to determine the effective tax rate. The effective tax rate helps adjust the cost of debt in the WACC calculation.

This adjustment accounts for the fact that interest expenses are tax-deductible, which reduces the actual cost a company incurs on its debt.

To calculate the effective tax rate, we follow these steps:

1. Calculate the Total Income Tax Expense: Sum up the income tax expenses from the last four quarters.

2. Calculate the Total Income Before Tax: Sum up the income before tax figures from the last four quarters.

3. Determine the Effective Tax Rate: Divide the total income tax expense by the total income before tax.

total_tax_expense = income_statement_df['incomeTaxExpense'].sum()
total_pre_tax_income = income_statement_df['incomeBeforeTax'].sum()
effective_tax_rate = total_tax_expense / total_pre_tax_income
print(f"Effective Tax Rate: {effective_tax_rate*100:.2f}%")
Effective Tax Rate: 13.27%

2.5.2 Cost of Debt

The Cost of Debt is calculated by dividing the total interest expense by the total debt.

First, sum up the interest expenses from the last four quarters. This gives us the total interest the company has paid over the past year.

Next, we sum up the company’s total debt from the last four quarters to get an accurate view of its borrowings over the past year.

The pre-tax cost of debt is calculated by dividing the total interest expense by the total debt.

Finally, adjust the pre-tax cost of debt by the effective tax rate to get the after-tax cost of debt.

This adjustment reflects the tax benefits the company receives on its interest payments.

total_debt = balance_sheet_df.loc[0, 'totalDebt']
total_interest_expense = income_statement_df['interestExpense'].sum()
pre_tax_cost_of_debt = total_interest_expense / total_debt
after_tax_cost_of_debt = pre_tax_cost_of_debt * (1 - effective_tax_rate)
print(f"Cost of Debt (After-Tax): {after_tax_cost_of_debt*100:.2f}%")
Cost of Debt (After-Tax): 2.17%

Note: If the Interest Expense is not directly stated in the financial statements, you can estimate it using other methods, such as reviewing company filings (10-Ks), using historical data, using market data (e.g., Moody’s, S&P, or Fitch and comparable bond yields) or referencing industry averages.

2.6 Calculating Cost of Equity

We calculate the cost of equity using the Capital Asset Pricing Model:

There are a number of parameters which need to be calculated. We do that below.

2.6.1 Beta, Risk Free, Market Risk Premium

To calculate the Cost of Equity using CAPM, we need to determine three key components: Beta, the Risk-Free Rate, and the Market Risk Premium. These factors represent the expected return that equity investors require.

Beta

Beta measures the stock’s volatility relative to the market and captures one type of risk — market risk. We calculate Beta by analyzing historical price data for both the stock and a market index, such as the S&P 500.

# Define the start and end dates for the data. 
# Use a sufficiently long time frame to minimize the impact of random fluctuations and seasonality.
start_date = "2019-01-01"
end_date = pd.Timestamp.today().strftime('%Y-%m-%d')

# Download historical data for the S&P 500 index ('Market Index')
market_data = yf.download("^GSPC", start=start_date, end=end_date)['Adj Close']

# Download historical stock price data for the selected ticker
stock_data = yf.download(ticker , start=start_date, end=end_date)['Adj Close']

# Calculate daily returns for the market and the stock
market_returns = market_data.pct_change().dropna()
stock_returns = stock_data.pct_change().dropna()

# Calculate Beta (β) by comparing stock returns with market returns
covariance = np.cov(stock_returns, market_returns)[0, 1]
market_variance = np.var(market_returns)
beta = covariance / market_variance
print(f"Beta (β): {beta:.4f}")
Beta (β): 1.7847

Risk-Free Rate

The risk-free rate represents the return on an investment with zero risk. The risk-free rate is often derived from government bond yields, typically using the 10-year or 30-year Treasury yields.

The 10-year yield balances short- and long-term risks, while the 30-year yield offers a longer-term outlook for extended investments. We’ll use the 10-year treasury yield in this example and retrieve it from Yahoo Finance.

# Download historical data for the 10-Year Treasury Yield
treasury_yield = yf.download("^TNX", start=start_date, end=end_date)['Close']

# Calculate the risk-free rate from the latest 10-Year Treasury Yield
risk_free_rate = treasury_yield.iloc[-1] / 100  # Convert from percentage to decimal
print(f"Risk-Free Rate: {risk_free_rate:.4f}")
Risk-Free Rate: 0.0391

Market Risk Premium

The Market Risk Premium is the difference between the expected return of the market (E(Rm)) and the risk-free rate. This premium compensates investors for taking on the higher risk of investing in the stock:

Where E(Rm) is the expected market return, calculated as:

# Calculate the expected market return as the average of historical market returns
expected_market_return = market_returns.mean() * 252  # Annualized return
print(f"Expected Market Return: {expected_market_return:.4f}")

# Calculate the market risk premium as the difference between the expected market return and the risk-free rate
market_risk_premium = expected_market_return - risk_free_rate
print(f"Market Risk Premium: {market_risk_premium:.4f}")
Expected Market Return: 0.1646
Market Risk Premium: 0.1254

2.6.2 Cost of Equity

Finally, we calculate the Cost of Equity using the CAPM:

cost_of_equity = risk_free_rate + beta * market_risk_premium
print(f"Cost of Equity: {cost_of_equity*100:.2f}%")
Cost of Equity: 26.30%

2.7 Calculting WACC

The WACC formula represents the average rate a company is expected to pay its security holders to finance its assets.

It combines the cost of equity and the after-tax cost of debt, weighted by their proportions in the company’s capital structure. Here’s the formula we’ll use:

2.7.1 Shares Outstanding

First, we fetch the current market price of the stock and the number of outstanding shares. These are necessary to calculate the company’s market capitalization, which forms the equity component in the WACC formula.

# Fetch current market price
current_price = yf.download(ticker, period="1d")['Adj Close'].iloc[-1]
print(f"Current Market Price: ${current_price:.2f}")

# Fetch outstanding shares using FMP API
shares_url = f"https://financialmodelingprep.com/api/v4/shares_float?symbol={ticker}&apikey={FMP_API_KEY}"
shares_response = requests.get(shares_url)
shares_data = shares_response.json()

if not shares_data or 'outstandingShares' not in shares_data[0]:
    print(f"Error: Could not retrieve 'outstandingShares' for {ticker}.")
    outstanding_shares = None
else:
    outstanding_shares = shares_data[0]['outstandingShares']
    print(f"Outstanding Shares: {outstanding_shares:,}")
Current Market Price: $119.37
Outstanding Shares: 24,530,000,000

2.7.2 Market Capitalization

With the current market price and the number of outstanding shares, we can now calculate the market capitalization:

# Calculate market capitalization
market_cap = current_price * outstanding_shares
print(f"Market Capitalization: ${market_cap:,.2f}")
Market Capitalization: $2,928,146,167,373.66

2.7.2 Weighted Average Cost of Capital

Finally, we calculate the WACC by determining the weights of equity and debt in the company’s capital structure, and applying the respective costs:

equity_value = market_cap  # Already calculated
total_value = equity_value + total_debt  # Sum of equity and debt

weight_of_equity = equity_value / total_value
weight_of_debt = total_debt / total_value

wacc = (weight_of_equity * cost_of_equity) + (weight_of_debt * after_tax_cost_of_debt)
print(f"WACC: {wacc*100:.2f}%")
WACC: 26.22%

As you see, the cost of Capital for Nvidia is quite high! This means that investors demand a substantial return to compensate for the risks associated with holding the stock.

for Nvidia in particular, a high cost of equity is primarily driven by its high beta (high market volatility). This higher risk, along with the intense competition and high growth expectations in the semiconductor and AI markets, pushes investors to expect higher returns.

2.8 Projecting Future Growth

2.8.1 Future Growth Forecast

Estimating future growth potential is the key to projecting future cash flows. We’ll pull in estimates for EPS growth automatically.

We’ll get this data from Finviz, where analysts provide forecasts.

Specifically, we’ll grab the EPS growth estimate for next year and the average growth estimate for the next five years.

Figure 4. EPS Future Growth from Finviz. Source: https://finviz.com/quote.ashx?t=NVDA&p=d

Alternatively, you may choose to specify your own growth estimates based on your research or other sources you trust.

def get_finviz_data(ticker):
    url = f"https://finviz.com/quote.ashx?t={ticker}"
    headers = {'User-Agent': 'Mozilla/5.0'}
    response = requests.get(url, headers=headers)
    soup = BeautifulSoup(response.content, 'html.parser')

data = {}
    try:
        # Fetch Beta
        beta = soup.find(text="Beta").find_next(class_='snapshot-td2').text
        data['Beta'] = float(beta)
        # Fetch EPS growth next year (percentage)
        eps_next_y_growth = soup.find_all(text="EPS next Y")[1].find_next(class_='snapshot-td2').text
        data['EPS Next Year Growth'] = float(eps_next_y_growth.strip('%')) / 100
        # Fetch EPS growth next 5 years (percentage)
        eps_next_5y = soup.find(text="EPS next 5Y").find_next(class_='snapshot-td2').text
        data['EPS Next 5Y'] = float(eps_next_5y.strip('%')) / 100
    except Exception as e:
        print("Error fetching data from Finviz:", e)
        exit()
    return data
# Example Usage
finviz_data = get_finviz_data(ticker_symbol)
eps_growth_next_year = finviz_data['EPS Next Year Growth']
eps_growth_next_5y = finviz_data['EPS Next 5Y']
print("Finviz Data:")
print(f"EPS Growth Next Year: {eps_growth_next_year * 100:.2f}%")
print(f"EPS Growth Next 5 Years (per annum): {eps_growth_next_5y * 100:.2f}%\n")
Finviz Data:
EPS Growth Next Year: 39.80%
EPS Growth Next 5 Years (per annum): 46.35%

The growth expectations are quite high for Nvidia. 40+% EPS Growth per year!

You should adjust this value according to your own research to determine if NVDA is currently over value or under valued.

2.8.2 Projecting Future Free Cash Flows

We’ll project the company’s Free Cash Flows over the next 10 years to estimate its future value using the EPS growth rates obtained earlier.

Year 1 to 5

For the first five years, we use the initial EPS growth rate:

Year 6 to 10

From year 6 onward, we assume a slower growth rate, calculated as:

# Correctly access the freeCashFlow from the cash_flow_ttm DataFrame
recent_fcf = cash_flow_ttm.loc['freeCashFlow', 'Trailing Twelve Months']  # Using the summed TTM free cash flow

# Define growth rates
initial_growth_rate = eps_growth_next_5y  # Already in decimal form
later_growth_rate = initial_growth_rate / 2  # Assuming growth slows down after 5 years

# Initialize a list to store projected FCFs
projected_fcf = []

# Project Free Cash Flows for the desired number of years
projections_years = 10  # Number of years to project
for year in range(1, projections_years + 1):
    if year <= 5:
        fcf = recent_fcf * (1 + initial_growth_rate) ** year
    else:
        fcf = projected_fcf[-1] * (1 + later_growth_rate)
    projected_fcf.append(fcf)

# Generate projection years
projection_years = [pd.Timestamp.today().year + i for i in range(1, projections_years + 1)]
projected_fcf_df = pd.DataFrame({
    'Year': projection_years,
    'Projected_FCF': projected_fcf
})

print("Projected Free Cash Flows:")
projected_fcf_df
Projected Free Cash Flows:
   Year  Projected_FCF
0 2025 7.136269e+10
1 2026 1.088495e+11
2 2027 1.660281e+11
3 2028 2.532427e+11
4 2029 3.862711e+11
5 2030 4.877253e+11
6 2031 6.158263e+11
7 2032 7.775731e+11
8 2033 9.818027e+11
9 2034 1.239673e+12

2.8.3 Projecting Terminal Value

The terminal value represents the value of all future free cash flows beyond the projection period.

We calculate it using the last projected FCF and a terminal growth rate, which reflects the expected long-term growth of the company (i.e. the rate at which the company will grow for ever).

The terminal growth rate should be conservative, often slightly above the long-term inflation rate or aligned with the broader economy’s growth expectations (i.e. GPD growth).

last_projected_fcf = projected_fcf_df.iloc[-1]['Projected_FCF']
terminal_growth_rate = 0.03  # Example terminal growth rate

terminal_value = (last_projected_fcf * (1 + terminal_growth_rate)) / (wacc - terminal_growth_rate)
print(f"Terminal Value: {terminal_value}")
Terminal Value: 6850825116299.405

2.9 Discount Future Cash Flows and Terminal Value

To determine the enterprise value of the company, we need to discount the projected Free Cash Flows and the terminal value back to their present value using the discount rate we got using the WACC formula.

2.9.1 Present Value of Cash Flows

For each year in our projection, we discount the projected FCF to its present value. The formula to calculate the discounted FCF is:

projected_fcf_df['Discount_Factor'] = 1 / ((1 + wacc) ** projected_fcf_df.index)
projected_fcf_df['Discounted_FCF'] = projected_fcf_df['Projected_FCF'] * projected_fcf_df['Discount_Factor']

2.9.2 Discounted Terminal Value

Similarly, we discount the terminal value to its present value using:

terminal_discount_factor = 1 / ((1 + wacc) ** projected_fcf_df.shape[0])
discounted_terminal_value = terminal_value * terminal_discount_factor

2.9.3 Total Enterprise Present Value

Finally, the enterprise value is the sum of all discounted FCFs and the discounted terminal value:

total_present_value = projected_fcf_df['Discounted_FCF'].sum() + discounted_terminal_value
print(f"Total Present Value of Cash Flows: {total_present_value}")
Total Present Value of Cash Flows: 2223235929540.989

2.10 Intrinsic Value Per Share

To determine the intrinsic value per share, which reflects what is left for equity investors after accounting for debt, we follow these steps:

1. Calculate Net Debt: This represents the total debt of the company minus its cash and cash equivalents.

2. Calculate Equity Value: Subtract the net debt from the enterprise value to find the equity value.

3. Calculate Intrinsic Value Per Share: Divide the equity value by the number of shares outstanding.

cash_and_equivalents = balance_sheet_df.loc[0, 'cashAndShortTermInvestments']

equity_value = total_present_value - total_debt + cash_and_equivalents
intrinsic_value_per_share = equity_value / outstanding_shares
print(f"Intrinsic Value per Share: {intrinsic_value_per_share}")
Intrinsic Value per Share: 91.64373948393758

The current stock price $119, so as you see we are not too far away. Reaching this intrinsic value requires assuming a high growth rate.

It’s up to you to decide whether NVIDIA is currently overvalued or undervalued based on these growth projections.

2.11 Margin of Safety

The margin of safety quantifies how much a stock is potentially under or overvalued. It is calculated by comparing the intrinsic value per share, which we derived from our DCF analysis, with the current market price.

A positive margin of safety suggests that the stock price is below its intrinsic value, providing a buffer against potential errors in our assumptions or unexpected market conditions.

# Fetch the current market price of the stock from Yahoo Finance
print(f"Current Market Price: ${stock_data.iloc[-1]:.2f}")

# Calculate the margin of safety
margin_of_safety = ((intrinsic_value_per_share - stock_data.iloc[-1]) / intrinsic_value_per_share) * 100
print(f"Margin of Safety: {margin_of_safety:.2f}%")
Current Market Price: $119.37
Margin of Safety: -30.25%

2.12 Sensitivity of WACCs, Growth and Fair Values

We can generate a matrix of possible intrinsic values under different assumptions of WACC and growth rates.

This approach helps visualize how sensitivity the intrinsic value is to changes in these two key assumptions.

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# Use the variables calculated from your DCF model
recent_fcf = projected_fcf[0]  # Assuming the first year FCF as a starting point
net_debt = total_debt - cash_and_equivalents  # Calculated from your balance sheet data
shares_outstanding = outstanding_shares  

# Define extended ranges for WACC and growth rate
wacc_range = np.arange(0.05, 0.25, 0.01)  # 5% to 25%
growth_rate_range = np.arange(0.05, 0.50, 0.01)  # 5% to 50%
fair_value_matrix = np.zeros((len(growth_rate_range), len(wacc_range)))

# Fixed perpetual growth rate for terminal value calculation
perpetual_growth_rate = 0.04  # 4%

# Reproject cash flows and calculate fair values for different WACC and growth rates
for i, growth_rate in enumerate(growth_rate_range):
    projected_fcfs = [recent_fcf * (1 + growth_rate)**year for year in range(1, 6)]

    for j, wacc in enumerate(wacc_range):
        discounted_fcfs = [fcf / ((1 + wacc) ** year) for year, fcf in enumerate(projected_fcfs, start=1)]
        terminal_value = projected_fcfs[-1] * (1 + perpetual_growth_rate) / (wacc - perpetual_growth_rate)
        discounted_terminal_value = terminal_value / ((1 + wacc) ** 5)
        enterprise_value = sum(discounted_fcfs) + discounted_terminal_value
        equity_value = enterprise_value - net_debt
        fair_value_per_share = equity_value / shares_outstanding  # Changed variable name here
        fair_value_matrix[i, j] = round(fair_value_per_share)

# Convert to DataFrame for heatmap
fair_value_df = pd.DataFrame(fair_value_matrix, index=(growth_rate_range * 100).astype(int), columns=(wacc_range * 100).astype(int))

# Plot heatmap with smaller annotation size and no decimals in axis labels
plt.figure(figsize=(10, 6))
sns.heatmap(fair_value_df, annot=True, fmt='.0f', cmap="YlOrRd", cbar_kws={'label': 'Fair Value ($)'}, annot_kws={"size": 7})
plt.title('Heatmap of Fair Value vs. WACC and Growth Rate')
plt.xlabel('WACC (%)', fontsize=8)
plt.ylabel('Growth Rate (%)', fontsize=8)
plt.xticks(fontsize=8)
plt.yticks(fontsize=8)
plt.show()

2.13 Levered Discounted Cash Flow

From the FMP API, we can automate all all of the process above by retrieving the fair value of a given stock automatically.

However, this comes at a cost of flexibility if you wanted to input your own assumptions as we did above.

Let’s compare the intrinsic value calculated from our discounted cash flow analysis with values retrieved directly and automatically from the FMP API using both standard and levered DCF models.

This comparison helps validate our findings and provides an additional layer of analysis.

import requests
import plotly.graph_objects as go

# Assuming these variables are calculated earlier in your code:
# total_present_value, total_debt, cash_and_equivalents, outstanding_shares, ticker_symbol, current_price

# Calculate intrinsic value per share
equity_value = total_present_value - total_debt + cash_and_equivalents
intrinsic_value_per_share = equity_value / outstanding_shares
print(f"Intrinsic Value per Share: {intrinsic_value_per_share}")

# Function to get the DCF Valuation
def get_dcf_valuation(ticker, api_key):
    url = f"https://financialmodelingprep.com/api/v3/discounted-cash-flow/{ticker}?apikey={api_key}"
    response = requests.get(url)
    if response.status_code == 200:
        data = response.json()
        if data:
            dcf_value = data[0]['dcf']  # Access the first element in the list
            print(f"Retrieved Automatic DCF Valuation: {dcf_value}")
            return dcf_value
    print("Error fetching Automatic DCF valuation.")
    return None

# Function to get the Levered DCF Valuation
def get_levered_dcf_valuation(ticker, api_key):
    url = f"https://financialmodelingprep.com/api/v4/advanced_levered_discounted_cash_flow?symbol={ticker}&apikey={api_key}"
    response = requests.get(url)
    if response.status_code == 200:
        data = response.json()
        if data:
            levered_dcf_value = data[0]['equityValuePerShare']  # Access the first element in the list
            print(f"Retrieved Levered DCF Valuation: {levered_dcf_value}")
            return levered_dcf_value
    print("Error fetching Levered DCF valuation.")
    return None

# Retrieve DCF and Levered DCF valuations
automatic_dcf_valuation = get_dcf_valuation(ticker, FMP_API_KEY)
levered_dcf_valuation = get_levered_dcf_valuation(ticker, FMP_API_KEY)

# Function to plot the bar chart
def plot_intrinsic_value_vs_stock_price(ticker, current_price, intrinsic_value, auto_dcf, levered_dcf):
    fig = go.Figure(data=[
        go.Bar(name='Current Stock Price',
               x=[ticker],
               y=[current_price],
               marker_color='orange',
               text=[f"${current_price:.2f}"],
               textposition='auto'),
        go.Bar(name='Intrinsic Value per Share',
               x=[ticker],
               y=[intrinsic_value],
               marker_color='blue',
               text=[f"${intrinsic_value:.2f}"],
               textposition='auto'),
        go.Bar(name='Automatic DCF Valuation',
               x=[ticker],
               y=[auto_dcf],
               marker_color='purple',
               text=[f"${auto_dcf:.2f}"],
               textposition='auto'),
        go.Bar(name='Levered DCF Valuation',
               x=[ticker],
               y=[levered_dcf],
               marker_color='red',
               text=[f"${levered_dcf:.2f}"],
               textposition='auto')
    ])

    fig.update_layout(barmode='group',
                      title='Intrinsic Value, DCF Valuations vs Current Stock Price',
                      xaxis_title='Ticker',
                      yaxis_title='Value',
                      yaxis=dict(tickformat=".2f"))
    fig.show()

# Plot the results using the calculated values
plot_intrinsic_value_vs_stock_price(ticker, current_price, intrinsic_value_per_share, automatic_dcf_valuation, levered_dcf_valuation)

3. Discussion

Second, please note that the FMP API offers a lot of the metrics that we computed here manually such as:

  • Cash Flow Historical Growths (Which can be used to project future cash flow at a realistic rate)

  • Trailing Twelve Month Metrics. While we computed these manually, the database offers these calculations automaticaly

  • Entreprise Values. Instead of performing all the steps we performed, you may choose to retrieve this value automatically.

  • Automatic DCF, Levered DCF, Advanced DFC, etc. For example for Apple, instead of calculating all the metrics ‘manually’ you may call the API to get all the necessary inputs:

[
 {
  "symbol": "AAPL",
  "price": 140.56,
  "beta": 1.25,
  "finalTaxRate": 13.3,
  "totalDebt": 124719000000,
  "totalEquity": 2370533014640,
  "totalCapital": 2495252014640,
  "dilutedSharesOutstanding": 16864919000,
  "debtWeighting": 5,
  "equityWeighting": 95,
  "year": "2017",
  "period": "FY",
  "revenue": 229234000000,
  "ebitda": 76569000000,
  "operatingCashFlow": 63598000000,
  "ebit": 66412000000,
  "weightedAverageShsOutDil": 21006768000,
  "netDebt": 95391000000,
  "inventories": 4855000000,
  "receivables": 35673000000,
  "payable": 49049000000,
  "inventoriesChange": 2723000000,
  "receivablesChange": 6374000000,
  "payableChange": 11755000000,
  "capitalExpenditure": -12795000000,
  "previousRevenue": 215639000000,
  "revenuePercentage": 0,
  "taxRate": 13.3,
  "ebitdaPercentage": 33.4,
  "receivablesPercentage": 15.56,
  "inventoriesPercentage": 2.12,
  "payablePercentage": 21.4,
  "ebitPercentage": 28.97,
  "capitalExpenditurePercentage": -5.58,
  "operatingCashFlowPercentage": 27.74,
  "afterTaxCostOfDebt": 1.84,
  "marketRiskPremium": 4.72,
  "longTermGrowthRate": 2,
  "costOfEquity": 10.56,
  "wacc": 10.11,
  "taxRateCash": 24556477,
  "ebiat": -15644326940,
  "ufcf": 44807553059,
  "riskFreeRate": 4.66,
  "sumPvUfcf": 0,
  "terminalValue": 563455390558,
  "presentTerminalValue": 348096433212,
  "enterpriseValue": 348096433212,
  "equityValue": 252705433212,
  "equityValuePerShare": 12.03,
  "freeCashFlowT1": 45703704120,
  "costofDebt": 2.12,
  "depreciation": 10157000000,
  "totalCash": 74181000000,
  "depreciationPercentage": 4.43,
  "totalCashPercentage": 32.36
 }
]

4. Limitations of Discounted Cash Flow Model

DCF relies heavily on projections. Predicting future cash flows and growth rates isn’t an exact science, and even small changes in assumptions will significantly alter the outcome. This sensitivity means that the DCF model can easily lead to inaccurate valuations, especially when looking far into the future.

Another issue with the DCF model is the difficulty in pinpointing the right discount rate. WACC depends on various factors like market conditions and the company’s capital structure. Both of these can change over time. The DCF model also assumes a company will grow at a constant rate indefinitely, which is rarely the case in reality.

Additionally, the DCF model doesn’t directly account for external factors like market conditions or competition. It focuses solely on a company’s intrinsic value based on its financials, potentially overlooking significant influences on the stock price.

5. More Valuation Methods worth Exploring

It’s always smart to explore complementary methods to calculate the fair value of stocks and get a more complete picture of a company’s worth. One useful approach is the ‘Comparable Companies Analysis’.

This method involves comparing a company to its peers by looking at multiples like Price-to-Earnings (P/E) or Enterprise Value-to-EBITDA. Financial Modeling prep makes this simple this simple by accessing its key financial metrics API.

Another approach is the ‘Precedent Transactions Analysis’. This method examines the prices paid for similar companies in past mergers or acquisitions. It offers insight into what buyers have been willing to pay in actual transactions, making it particularly useful for valuing private companies or during times of market volatility.

The ‘Dividend Discount Model’ (DDM) is another method, especially for companies with a history of stable dividend payments. This model calculates the fair value of a stock based on the present value of expected future dividends. This is particularly relevant for mature companies where dividends play a significant role in returns.

Lastly, the ‘Sum-of-the-Parts’ (SOTP) analysis can be beneficial for conglomerates or companies with various business units. By valuing each division separately and then summing these values, investors can estimate the overall company’s worth. This method ensures that each business unit’s value is properly recognized.

Concluding Thoughts

Calculating the fair value of stocks is essential for serious investors who are committed to thorough due diligence.

The DCF model offers a straightforward approach to estimate this value, especially when data is readily available to project future cash flows and assess the cost of capital.

However, the DCF model has its limitations, as it depends on assumptions. To gain a more comprehensive understanding, it’s advisable to use additional and complementary valuation methods.

logo

Subscribe to our premium content to read the rest.

Become a paying subscriber to get access to this post and other subscriber-only content.

Upgrade

Keep Reading