Discounted Cash Flow (DCF) is a valuation method that calculates what a business or project is worth today by looking at the cash it is expected to generate in the future. The idea is simple: cash received in the future is worth less than cash in your hand now, so future cash flows are discounted back to present value using a rate that reflects the risk of the investment. When you add up these discounted amounts you arrive at an estimate of the enterprise value. Investors use this technique to decide whether a share or project is fairly priced.

Why discounted cash flow matters

There are several reasons to use a discounted cash flow model. It forces a structured examination of the underlying business, including revenue growth, margins and capital expenditure. Because it is based on cash rather than accounting profits, it can be a more accurate reflection of economic reality. It is also flexible; you can adjust assumptions about growth and risk to see how sensitive the valuation is to these inputs. This makes it a useful tool for corporate finance teams evaluating acquisitions, venture capitalists assessing start‑ups and individual investors thinking about buying or selling a share.

What you need to build a model

Three ingredients are essential for a discounted cash flow calculation. First, you need free cash flow, which is the cash generated by operations after investing in capital assets. Second, you need a discount rate, often the weighted average cost of capital for a company, which represents the return required by investors. Third, you need an assumption about long term growth, used when calculating the terminal value of the business beyond the explicit forecast period. With these inputs you can project future cash flows, discount them back to the present and sum them up.

Getting data from the EODHD fundamentals API

Gathering free cash flow and other inputs manually can be time consuming. The EODHD Fundamentals API makes it easy by returning comprehensive financial statements for thousands of companies. In the cash flow statement section you will find fields such as operating cash flow, capital expenditure and, in many cases, free cash flow. By calling the API for a symbol like AAPL.US you receive several years of free cash flow figures, which can be used as the base for your projections. The example below uses the free demo token provided by EODHD, but a subscription unlocks more markets and higher limits.

Discounted cash flow formula

The discounted cash flow method values a business by summing the present value of the cash it will generate in the future. You take each projected cash flow and discount it back to today using a rate that reflects the risk or return you expect. The basic formula looks like this:

DCF = CF1 ÷ (1 + r)^1  +  CF2 ÷ (1 + r)^2  +  …  +  CFn ÷ (1 + r)^n

In this equation each CF represents the expected cash flow for that year, r is the discount rate and n is the number of years into the future. You can then calculate an equity value per share by taking the resulting enterprise value, subtracting any net debt and dividing by the number of shares outstanding.

Register & Get Data

Breaking down a Python script to make light work of calculations

I have provided a self‑contained discounted cash flow calculator and I set up the environment by importing the handful of Python modules it needs. There is a module for parsing command‑line options so you can pass in your own parameters when they run it. I import a module for simple data structures called data classes to keep the classes neat and easy to read, and I bring in support for handling dates and times. I also specify the types of data used throughout the script to improve clarity and ensure consistency, and I import a library for making web requests.

#!/usr/bin/env python3
"""DCF calculator using the EODHD fundamentals API."""
from __future__ import annotations

import argparse
from dataclasses import dataclass
from datetime import datetime
from typing import Dict, List, Optional, Tuple

import requests


class EODHDAPIClient:
    """Client for interacting with the EODHD fundamentals API."""

    def __init__(self, api_token: str, base_url: str | None = None) -> None:
        if not api_token:
            raise ValueError("An API token is required to use the EODHD API.")
        self.api_token = api_token
        self.base_url = base_url or "https://eodhd.com/api/fundamentals"

    def get_fundamentals(self, symbol: str, fmt: str = "json") -> Dict:
        """Retrieve fundamental data for a given ticker."""
        params = {
            "api_token": self.api_token,
            "fmt": fmt,
        }
        response = requests.get(f"{self.base_url}/{symbol}", params=params, timeout=30)
        response.raise_for_status()
        return response.json()

To talk to the EODHD fundamentals service I define a small class. It needs your API token when you create an instance and optionally lets you override the default base URL if the service changes. The class stores these values and has a single method that fetches fundamentals for a specified ticker symbol. When you call that method it builds the right URL with the token and format, sends an HTTP GET request and checks for any errors. If the response is successful it returns the data in dictionary form so the rest of the code can use it.

@dataclass
class FreeCashFlowService:
    """Service for extracting free cash flow history from fundamentals data."""

    api_client: EODHDAPIClient

    def get_free_cash_flow_history(
        self, symbol: str, years: int = 5
    ) -> List[Tuple[int, float]]:
        """Return a list of (year, free cash flow) tuples for the most recent years."""
        data = self.api_client.get_fundamentals(symbol)
        try:
            cash_flow_yearly = data["Financials"]["Cash_Flow"]["yearly"]
        except KeyError as exc:
            raise RuntimeError(f"Cash flow data missing for {symbol}: {exc}") from exc

        items = list(cash_flow_yearly.items())
        if not items:
            raise RuntimeError(f"No cash flow data available for {symbol}.")

        # Sort by date descending
        items.sort(key=lambda item: item[0], reverse=True)
        result: List[Tuple[int, float]] = []
        for date_str, record in items:
            if len(result) >= years:
                break
            year = datetime.strptime(date_str, "%Y-%m-%d").year
            fcf = self._extract_free_cash_flow(record)
            if fcf is not None:
                result.append((year, fcf))
        return result

    def _extract_free_cash_flow(self, record: Dict) -> Optional[float]:
        """Extract free cash flow from a cash flow record. Compute if missing."""
        fcf = record.get("freeCashFlow") or record.get("free_cash_flow")
        if fcf is not None:
            return float(fcf)
        # Fallback calculation: operating cash flow – capital expenditure
        op_cash = record.get("operatingCashFlow") or record.get(
            "cash_from_operating_activities"
        )
        capex = record.get("capitalExpenditures") or record.get("capital_expenditure")
        if op_cash is None or capex is None:
            return None
        try:
            return float(op_cash) - float(capex)
        except (TypeError, ValueError):
            return None

For extracting usable numbers from the raw data I wrap the parsing into another class. This service takes the client I just described and calls it to obtain the company’s fundamentals. It then looks specifically at the cash flow section, picks out the most recent annual entries and orders them from latest to oldest. For each year it tries to read the free cash flow directly. If that value isn’t provided, it calculates it by subtracting capital expenditure from operating cash flow. It assembles these year and cash flow pairs into a list and returns them.

@dataclass
class DiscountedCashFlowCalculator:
    """Perform DCF projections and valuations. Optionally allows overriding
    the projected growth rate instead of using the historical average."""

    discount_rate: float
    projection_years: int = 5
    terminal_growth_rate: float = 0.025

    def __post_init__(self) -> None:
        if self.discount_rate <= 0:
            raise ValueError("Discount rate must be positive.")

    def calculate_average_growth(self, cash_flows: List[float]) -> float:
        """Compute the average year‑over‑year growth rate."""
        if len(cash_flows) < 2:
            return 0.0
        growth_rates: List[float] = []
        for previous, current in zip(cash_flows[1:], cash_flows[:-1]):
            if previous == 0:
                continue
            growth_rates.append((current / previous) - 1)
        return sum(growth_rates) / len(growth_rates) if growth_rates else 0.0

    def project_cash_flows(
        self, last_cash_flow: float, growth_rate: float
    ) -> List[float]:
        """Project future free cash flows based on the last cash flow and growth rate."""
        projected: List[float] = []
        fcf = last_cash_flow
        for _ in range(self.projection_years):
            fcf *= 1 + growth_rate
            projected.append(fcf)
        return projected

    def discount_cash_flows(self, cash_flows: List[float]) -> List[float]:
        """Discount each projected cash flow back to present value."""
        discounted: List[float] = []
        for idx, fcf in enumerate(cash_flows, start=1):
            discounted.append(fcf / ((1 + self.discount_rate) ** idx))
        return discounted

    def calculate_terminal_value(self, last_cash_flow: float) -> float:
        """Calculate the terminal value using the Gordon growth model."""
        return (
            last_cash_flow
            * (1 + self.terminal_growth_rate)
            / (self.discount_rate - self.terminal_growth_rate)
        )

    def discount_terminal_value(self, terminal_value: float) -> float:
        """Discount the terminal value back to present."""
        return terminal_value / ((1 + self.discount_rate) ** self.projection_years)

    def run(
        self,
        free_cash_flow_history: List[Tuple[int, float]],
        shares_outstanding: Optional[float] = None,
        growth_override: Optional[float] = None,
    ) -> Dict[str, object]:
        """Run the DCF calculation and return a results dictionary.

        If ``growth_override`` is provided, use it as the projected growth rate
        rather than computing an average from historical free cash flows.
        """
        historical_flows = [fcf for _, fcf in free_cash_flow_history]
        if growth_override is not None:
            avg_growth = growth_override
        else:
            avg_growth = self.calculate_average_growth(historical_flows)

        last_fcf = historical_flows[0] if historical_flows else 0
        projected_flows = self.project_cash_flows(last_fcf, avg_growth)
        discounted_flows = self.discount_cash_flows(projected_flows)

        terminal_value = self.calculate_terminal_value(projected_flows[-1])
        pv_terminal = self.discount_terminal_value(terminal_value)

        enterprise_value = sum(discounted_flows) + pv_terminal

        result: Dict[str, object] = {
            "historical": free_cash_flow_history,
            "average_growth_rate": avg_growth,
            "projected_cash_flows": projected_flows,
            "present_values": discounted_flows,
            "terminal_value": terminal_value,
            "present_value_terminal": pv_terminal,
            "enterprise_value": enterprise_value,
        }

        if shares_outstanding:
            result["intrinsic_value_per_share"] = enterprise_value / shares_outstanding

        return result

The core financial logic is encapsulated in a calculator class. When you construct it you specify a discount rate and can adjust how many future years to forecast and what terminal growth rate to assume. Given a list of historical cash flows, it first works out an average growth rate from year to year. It then uses that rate to project the cash flow forward over the chosen number of years. Each of those forecasts is discounted back to today using the discount rate. The final cash flow in the series is used to estimate a terminal value using a steady growth formula. The calculator discounts that value back to today, sums everything to give an enterprise value and, if you provide a share count, divides by the shares to produce an intrinsic value per share.

@dataclass
class DCFReportFormatter:
    """Format a dictionary of DCF results into a human‑readable report."""

    currency_symbol: str = "$"

    def format_report(self, dcf_result: Dict[str, object], symbol: str) -> str:
        lines: List[str] = []
        lines.append(f"Discounted Cash Flow Analysis for {symbol}")
        lines.append("-" * 60)
        lines.append("\nHistorical Free Cash Flow:")
        for year, value in dcf_result["historical"]:
            lines.append(f"  {year}: {self.currency_symbol}{value:,.0f}")

        avg_growth = dcf_result["average_growth_rate"]
        lines.append(
            f"\nAverage annual growth rate used for projections: {avg_growth * 100:.2f}%"
        )

        lines.append("\nProjected Free Cash Flows:")
        for idx, fcf in enumerate(dcf_result["projected_cash_flows"], start=1):
            lines.append(f"  Year +{idx}: {self.currency_symbol}{fcf:,.2f}")

        lines.append("\nPresent Value of Projected Cash Flows:")
        for idx, pv in enumerate(dcf_result["present_values"], start=1):
            lines.append(f"  Year +{idx}: {self.currency_symbol}{pv:,.2f}")

        lines.append(
            f'\nTerminal value (undiscounted): {self.currency_symbol}{dcf_result["terminal_value"]:,.2f}'
        )
        lines.append(
            f'Present value of terminal value: {self.currency_symbol}{dcf_result["present_value_terminal"]:,.2f}'
        )
        lines.append(
            f'Enterprise value: {self.currency_symbol}{dcf_result["enterprise_value"]:,.2f}'
        )

        if "intrinsic_value_per_share" in dcf_result:
            lines.append(
                f'Intrinsic value per share: {self.currency_symbol}{dcf_result["intrinsic_value_per_share"]:,.2f}'
            )

        return "\n".join(lines)

Once the calculations are complete I want to present the results clearly, so I define a formatter. This class takes the dictionary of outputs from the calculator along with the stock’s ticker symbol and builds a human‑readable report. It starts with a title and a separator line, then lists each historical cash flow by year. It notes the average growth rate used in the projections and lays out each projected cash flow along with its present value. It then states the terminal value, the present value of the terminal value and the resulting enterprise value. If a per‑share figure has been computed, it includes that too at the end of the report.

def main() -> None:
    parser = argparse.ArgumentParser(
        description="Compute a discounted cash flow valuation for a stock."
    )
    parser.add_argument("symbol", help="Stock ticker symbol (e.g. AAPL.US)")
    parser.add_argument("--token", required=True, help="EODHD API token")
    parser.add_argument(
        "--discount", type=float, default=0.09, help="Discount rate (e.g. 0.09 for 9%)"
    )
    parser.add_argument(
        "--growth",
        type=float,
        default=0.025,
        help="Terminal growth rate (e.g. 0.025 for 2.5%)",
    )
    parser.add_argument(
        "--years", type=int, default=5, help="Number of projection years"
    )
    parser.add_argument("--shares", type=float, help="Number of shares outstanding")
    parser.add_argument(
        "--project-growth",
        type=float,
        help="Override the projected growth rate (e.g. 0.152 for 15.2%%). If not provided, use the historical average.",
    )
    args = parser.parse_args()

    client = EODHDAPIClient(api_token=args.token)
    fcf_service = FreeCashFlowService(api_client=client)
    history = fcf_service.get_free_cash_flow_history(args.symbol, years=args.years)

    calculator = DiscountedCashFlowCalculator(
        discount_rate=args.discount,
        projection_years=args.years,
        terminal_growth_rate=args.growth,
    )
    results = calculator.run(
        history, shares_outstanding=args.shares, growth_override=args.project_growth
    )

    formatter = DCFReportFormatter()
    report = formatter.format_report(results, args.symbol)
    print(report)


if __name__ == "__main__":
    main()

The script ends with a main function that glues everything together. It sets up the command‑line parser so you can enter the stock symbol, your API token, discount and growth assumptions, the number of years you want to forecast and optionally the number of shares outstanding. It then creates an API client, uses the cash flow service to get the historical free cash flows, passes them to the calculator to generate the valuation and, finally, hands the results to the formatter to produce a report. The report is printed to the console so that you can see the full discounted cash flow analysis when you run the programme.

What the script produces

When run with Apple’s recent free cash flows and assumptions of a nine per cent discount rate and a two and a half per cent terminal growth rate, the script generates a report that looks like this:

% python3 dcf_calculator.py --token 6694f8f1ad3951.60000586 --discount 0.11 --growth 0.04 --years 10 --shares 14815307000 --project-growth 0.152 AAPL.US
Discounted Cash Flow Analysis for AAPL.US
------------------------------------------------------------

Historical Free Cash Flow:
  2025: $98,767,000,000
  2024: $108,807,000,000
  2023: $99,584,000,000
  2022: $111,443,000,000
  2021: $92,953,000,000
  2020: $73,365,000,000
  2019: $58,896,000,000
  2018: $64,121,000,000
  2017: $50,803,000,000
  2016: $52,276,000,000

Average annual growth rate used for projections: 15.20%

Projected Free Cash Flows:
  Year +1: $113,779,584,000.00
  Year +2: $131,074,080,768.00
  Year +3: $150,997,341,044.74
  Year +4: $173,948,936,883.54
  Year +5: $200,389,175,289.83
  Year +6: $230,848,329,933.89
  Year +7: $265,937,276,083.84
  Year +8: $306,359,742,048.58
  Year +9: $352,926,422,839.97
  Year +10: $406,571,239,111.64

Present Value of Projected Cash Flows:
  Year +1: $102,504,129,729.73
  Year +2: $106,382,664,368.15
  Year +3: $110,407,954,371.27
  Year +4: $114,585,552,644.78
  Year +5: $118,921,222,204.31
  Year +6: $123,420,944,125.56
  Year +7: $128,090,925,795.17
  Year +8: $132,937,609,473.91
  Year +9: $137,967,681,183.73
  Year +10: $143,188,079,931.22

Terminal value (undiscounted): $6,040,486,981,087.25
Present value of terminal value: $2,127,365,758,978.17
Enterprise value: $3,345,772,522,805.99
Intrinsic value per share: $225.83

Apple’s free cash flow can grow at 15.2 percent annually for ten years, with a discount rate of 11 percent and a terminal growth rate of 4  percent. Based on historical cash flows that range from about 52 billion to nearly 111 billion dollars over the past decade, the model projects future cash flows rising from roughly 113.8 billion in year one to more than 406 billion dollars in year ten. Discounting these projections at 11 per cent produces present values between 102.5 billion and 143.2 billion. The terminal value representing all cash flows beyond year ten comes out at over six trillion dollars undiscounted, contributing about 2.127 trillion to the present value when discounted. Summing these amounts yields an enterprise value of roughly 3.346 trillion dollars. When divided by the 14.8 billion shares outstanding, this gives an intrinsic value of around $225.83 per share.

Turning the calculator into a REST API

The same logic can be exposed as a web service. Using Flask, a lightweight web framework, you can create an endpoint that accepts a share code and returns a JSON response with the valuation. Here is a simple example:

from flask import Flask, jsonify, request
from dcf_calculator import EODHDAPIClient, FreeCashFlowService, DiscountedCashFlowCalculator

app = Flask(__name__)

@app.route('/dcf/<symbol>')
def dcf(symbol):
    api_token = request.args.get('token')
    years = int(request.args.get('years', 5))
    discount_rate = float(request.args.get('discount_rate', 0.09))
    terminal_growth = float(request.args.get('terminal_growth', 0.025))
    shares = request.args.get('shares')
    shares_outstanding = float(shares) if shares else None

    # Optional override for projected growth rate (e.g. 0.152 for 15.2%)
    project_growth = request.args.get('project_growth')
    growth_override = float(project_growth) if project_growth else None

    api_client = EODHDAPIClient(api_token)
    fcf_service = FreeCashFlowService(api_client)
    history = fcf_service.get_free_cash_flow_history(symbol, years)

    calculator = DiscountedCashFlowCalculator(
        discount_rate,
        projection_years=years,
        terminal_growth_rate=terminal_growth
    )

    # Use the override growth rate if provided
    dcf_result = calculator.run(
        history,
        shares_outstanding=shares_outstanding,
        growth_override=growth_override
    )

    return jsonify(dcf_result)

if __name__ == '__main__':
    app.run(debug=True)

This REST API allows you to make a GET request to an address like

/dcf/AAPL.US?token=6694f8f1ad3951.60000586&years=10&discount_rate=0.11&terminal_growth=0.04&shares=14815307000&project_growth=0.152


and receive a JSON object containing the historical free cash flows, the projected cash flows, their present values, the terminal value, the present value of the terminal and the enterprise value. Including the number of shares will also produce a per share value. You can deploy this service to a cloud platform or integrate it into an existing system, making it easy for other applications to fetch valuations on demand. Combining the EODHD fundamentals API with a well structured Python script and a simple Flask wrapper offers a powerful and flexible way to analyse investments.

Do you enjoy our articles?

We can send new ones right to your email box