Analysing Cash Flow Statements with Python

In this post we are going to learn how to analyse cash flow statements with Python. We will build a Common-Size Cash Flow Statement to analyse how companies are generating and using cash.

During the first part of the post, we will focus on understanding what a cash flow statement is. Then, in the second part ,we will build our Python for Finance script to analyse the cash flow Statement of Apple.

Analysing Cash Flow Statements with Python
Photo by Pixabay from Pexels

Understanding Cash Flow

Cash flow statements can tell us a lot on how firms generate and spend cash. A cash flow statement can let us know how much cash receipts and payments a company made during a period of time. It help investors to understand if a firm will be in need of additional financing. In general, it provides very useful information to analyse firms solvency and liquidity.

Firms classify cash receipts and payments into three different categories using the cash flow statement:

  • Cash from Operating Activities: Cash payments and receipts generated from transactions affecting net income.
  • Cash from Investing Activities. Cash payments and receipts generated from acquisition or sales of long-term assets
  • Cash from Financing Activities. Cash payments and receipts generated from transactions affecting the capital structure of firms.

Non cash transactions are not included in the Cash Flow Statement since the do not represent cash outflows or inflows.

How to interpret the different Cash Flows categories

When a firm is growing, it is very likely that it will have a negative cash flow from operations. That is because a growing firm will probably have big outflow of cash in order to build up inventory. At the same time, a growing company will accumulate receivables over time as the business grow.

To finance a firm’s negative operating cash flow, a firm will need to get a loan or issue equity leading to a positive cash from financing activities. However, over the years companies need to turn negative operating cash flow into positive since it is not sustainable to always relay on external sources of finance.

Another thing to take into account is how the firm is generating positive operating cash flow. Is the firm having a positive operating cash flow because the firm suddenly sold a lot of inventory bringing it inventory levels close to 0? If that is the case, we need to watch out since the positive operating cash flow may not be related to the firm main core activities.

Investing Activities and Free Cash Flow

Another element of importance is capital expenditures. Growing firms are normally increasing capital expenditures since they invest in long term assets to support future sales.

Ideally, a firm would generate enough operating cash flow to cover its capital expenditures. Free Cash Flow (FCF) is a valuation measure often used by analysts to understand how much cash a company has generated after covering its capital expenditures:

FCF = Operating Cash Flow − Capital Expenditures

On the contrary, firms may sale PP&E and obtain cash out of it. This should not be seen as a good source of cash since long-term assets are required to generate cash from earning-related activities.

Common-Size Cash Flow – Analysing CF Statements with Python

One of the best ways to analyse firms cash flow is using Common-Size Cash Flow Statements. That is, we take a firm cash flow and express each cash flow line item as a percentage of revenue.

A Common-Size Cash Flow statement will help us to identify how firm cash sources are changing over time. It helps us to see the cash flow as a trend analysis.

We are going to build a Python script in order to express the cash flow statement of firms as percentage of revenues. We can easily do that with a financial API, fmpcloud. It offers a few free calls per day which is more than enough for this kind of analysis. Our analysis will focus on the cash flow from the last three years.

Starting the Cash Flow Python code

First thing we need to do is to make an api call to the API end point to retrieve the cash flow Statement of the firm that we are interested in. For instance, Apple.

As you can see below, we pass within the url the ticker from Apple, AAPL, in order to retrieve the cash flow statement from the API. We retrieve the income statement as well since we will need the company revenue to express the cash flow statement as a percentage of revenue.

Then, we also create an empty dictionary CF_3Y where we will store the last three years cash flow statements:

import requests
import pandas as pd

api_key = 'demo'

CF = requests.get(f'https://fmpcloud.io/api/v3/cash-flow-statement/AAPL?apikey={api_key}').json()

count= 0
#Create an empty dictionary 
CF_3Y = {}
IS = requests.get(f'https://fmpcloud.io/api/v3/income-statement/AAPL?apikey={api_key}').json()

print(CF)
#outcome
[{'accountsPayables': -1923000000,
  'accountsReceivables': 245000000,
  'acquisitionsNet': -624000000,
  'capitalExpenditure': 10495000000,
  'cashAtBeginningOfPeriod': 25913000000,
  'cashAtEndOfPeriod': 50224000000,
  'changeInWorkingCapital': 42628000000,
  'commonStockIssued': 781000000,
  'commonStockRepurchased': -66897000000,
  'date': '2019-09-28',
  'debtRepayment': -8805000000,
  'deferredIncomeTax': 340000000,
  'depreciationAndAmortization': 12547000000,
  'dividendsPaid': -14119000000,
  'effectOfForexChangesOnCash': 0.0,
  'fillingDate': '2019-10-31',
  'finalLink': 'https://www.sec.gov/Archives/edgar/data/320193/000032019319000119/a10-k20199282019.htm',
  'freeCashFlow': 58896000000,
  'inventory': -289000000,
  'investmentsInPropertyPlantAndEquipment': -10495000000,
  'link': 'https://www.sec.gov/Archives/edgar/data/320193/000032019319000119/0000320193-19-000119-index.htm',
  'netCashProvidedByOperatingActivites': 69391000000,
  'netCashUsedForInvestingActivites': 45896000000,
  'netCashUsedProvidedByFinancingActivities': -90976000000,
  'netChangeInCash': 24311000000,
  'netIncome': 55256000000,
  'operatingCashFlow': 69391000000,
  'otherFinancingActivites': -1936000000,
  'otherInvestingActivites': 65819000000,
  'otherNonCashItems': 0.0,
  'otherWorkingCapital': 57101000000,
  'period': 'FY',
  'purchasesOfInvestments': -107528000000,
  'salesMaturitiesOfInvestments': 98724000000,
  'stockBasedCompensation': 6068000000,
  'symbol': 'AAPL'},
 {'accountsPayables': 9175000000,

The outcome is a list of dictionaries. Each dictionary contains a different period. Therefore, we loop through the three first elements of the list since they will give us the last three year cash flow statements. In addition, we also obtain the last three years of revenue and include them in the CF3Y dictionary:

for item in CF:
  if count < 3:
    date = item['date']
    CF_3Y[date] = item
    #we add revenue as well to the dictionary since we need it to calculate the common-size cash flow
    CF_3Y[date]['Revenue'] = IS[count]['revenue']
    count += 1

print(CF_3Y)
{'2017-09-30': {'Revenue': 229234000000,
  'accountsPayables': 9618000000,
  'accountsReceivables': -2093000000,
  'acquisitionsNet': -329000000,
  'capitalExpenditure': 12795000000,
  'cashAtBeginningOfPeriod': 20484000000,....

Building a Pandas DataFrame

Now, we can transform the dictionary into a Pandas DataFrame:

CF_Common_Size = pd.DataFrame.from_dict(CF_3Y, orient='index')
CF_Common_Size = CF_Common_Size.T
print(CF_Common_Size)
Python for Finance - Common-Size Cash Flow Statement
Python for Finance – Common-Size Cash Flow Statement

Revenue can be extracted from the last row of the Pandas DataFrame. So we can easily extract it to the variable Revenue:

Revenue = CF_Common_Size.iloc[-1]

Now we have the last three years cash flow statements from Apple. We need to clean up the first four rows since the Cash Flow Statement should start with Net Income. In addition, we get rid of the last three rows of the DataFrame.

CF_Common_Size = CF_Common_Size.iloc[5:-3,:]

Finally, to express the Cash Flow Statement as a percentage of revenue, we only need to divide each row by the revenues:

CF_Common_Size = (CF_Common_Size/Revenue) * 100

#show as percentage:
pd.options.display.float_format = '{:.2f}%'.format
print(CF_Common_Size)
Python for Finance - Common-Size Cash Flow Statements
Python for Finance – Common-Size Cash Flow Statements

Wrapping Up

And just with that few lines of code, we have built a common-size income statement with Python. You can apply it to any company you are interested in by simple changing the company ticker in the url.

What we see in the example above for Apple is that the net cash from operating activities has decreased by 3% in terms of revenues, from 29.15% to 26.67% compared to the previous year. This seems to be due to a 0.4% increasing inventories from 2018 to 2019 (i.e. more cash used to buy inventory) and mainly to a decrease on the deferred income tax from 2018 to 2019.

On the other side, Apple significantly generated more cash out of changes in working capital. But in overall, in 2019 Apple generated less cash from operating activities in terms of revenues than in 2018.

Follow Coding and Fun in the social media channels for new articles on Python for Finance!

See below video tutorial version of the article:

Video Tutorial on Cash Flow Analysis

2 thoughts on “Analysing Cash Flow Statements with Python

  1. When I try to express the CF as a % of Revenue, using the following command:

    CF_Common_Size = (CF_Common_Size/Revenue) * 100

    I get:

    TypeError: unsupported operand type(s) for /: ‘str’ and ‘int’

    I assume this means that the two variables are of data types that are not valid for division with Python?

    Using type(Revenue) I see it is a pandas.core.series.Series.

    Using type(CF_Common_Size) I see it is a pandas.core.frame.DataFrame.

    Thanks in advance, I really appreciate these tutorials.

    1. That is because one of the rows in your dataframe contains strings.

      replace in your code
      CF_Common_Size = CF_Common_Size.iloc[4:-3,:]
      by
      CF_Common_Size = CF_Common_Size.iloc[5:-3,:]

      That will get rid of the row containing the string ‘FY’ and will make your code work.

Comments are closed.