Quant Quickstart IV: Adding Fundamental Data

Leo Smigel
May 11, 2020

New to the Quant Quickstart series? Read parts one, two, and three.

Hello world, it's Leo Smigel. I'm back again discussing my favorite python trading framework. In this post, we're going to add fundamentals to our price data. Before we dive in, let's make sure we're clear on what fundamentals are.

Financial statement

Fundamentals

The SEC requires publicly traded companies to file annual and quarterly reports on an ongoing basis. These reports detail the financial results of operations, the financial position, and the cash flow of the organization. If you're interested, you can learn more about how to read financial statements. From these financial statements, we can calculate various metrics and ratios that can provide insight into the nature of the company or how it's performing. Thankfully, you don't have to import the financial statements and calculate these for yourself -- Intrinio has already done that for us.

Financial Calculations & Metrics

Intrinio provides us with the needed calculations and metrics. For this post, let's add the classic price-to-book ratio (P/B) ratio. We'll start by exploring the API through the REPL.

Exploring the Intrinio Fundamentals API

Start by activating the environment we created in part one, importing what we need, and grabbing both the CompanyApi and FundamentalsApi.

source env/bin/activate
python3
import csv
import intrinio_sdk
intrinio_sdk.ApiClient().configuration.api_key['api_key'] = apikey
company_api = intrinio_sdk.CompanyApi()
fundamentals_api = intrinio_sdk.FundamentalsApi()

Now let's use the CompanyApi to get the 2018 filings for Apple. We'll add statement_code='calculations' to filter our data to receive only the calculations.

api_response = company_api.get_company_fundamentals('AAPL', fiscal_year=2018, statement_code='calculations')

Let's get the FY calculations.

calculations = {}
for filing in api_response.fundamentals_dict:
	if filing['fiscal_period'] == 'FY':
		calcluations = filing
print(calculations)

Now we have the id of the calculations filing for 2018. Now it's time to grab the data!

api_response = fundamentals_api.get_fundamental_standardized_financials(calcluations['id'])

Now let's loop through the api_response to get the P/B using the tag pricetobook.

pricetobook = None
for calc in api_response.standardized_financials_dict:
	if calc['data_tag']['tag'] == 'pricetobook':
		pricetobook = calc['value']
print(pricetobook)
10.4128

Congratulations! You just grabbed your first fundamental value!

Adding Fundamentals to Data Feed

While there are many ways you can store the data, I prefer to add fundamental and alternative data directly to the data feed I'm working with. If you remember from part one, we created a CSV file with the OHLCV fields. We'll append pricetobook to the end of these values. We'll need to loop through each page and add that to our prices dictionary.

security_api = intrinio_sdk.SecurityApi()
api_response = security_api.get_security_stock_prices('AAPL', start_date='2018-01-01', end_date='2018-12-31')
aapl_prices = api_response.stock_prices_dict
while api_response.next_page:
	api_response = security_api.get_security_stock_prices('AAPL', start_date='2018-01-01', end_date='2018-12-31', next_page=api_response.next_page)
	aapl_prices.extend(api_response.stock_prices_dict)

Pandas Data Manipulation

As you progress on your journey, you'll want to be able to slice and dice data to observe relationships and build various trading indicators. For this, you'll need Pandas.

pip install pandas

Pandas was developed at hedge fund AQR by Wes McKinney to enable quick analysis of financial data. Pandas is an extension of NumPy that supports vectorized operations, enabling fast manipulation of financial information. While out of scope for these posts, I would consider Pandas required learning for systematic and algorithmic trading. You can learn more by reading How to Manipulate Data with Pandas and Python.

With that out of the way, let's append our price to book to our OHLC values. First, we'll import pandas and read in our list of dictionaries to a pandas dataframe.


df = pd.DataFrame(aapl_prices)

date intraperiod frequency open high … adj_open adj_high adj_low adj_close adj_volume
0 2018-12-31 False daily 158.530 159.360 … 155.392897 156.206472 153.383464 154.618530 35003466.0
1 2018-12-28 False daily 157.500 158.520 … 154.383279 155.383095 151.491656 153.138411 42291424.0
2 2018-12-27 False daily 155.840 156.770 … 152.756128 153.667725 147.100309 153.059994 53117065.0
3 2018-12-26 False daily 148.300 157.230 … 145.365335 154.118622 143.816601 154.059809 58582544.0
4 2018-12-24 False daily 148.150 151.550 … 145.218304 148.551022 143.689174 143.924425 37169232.0
.. … … … … … … … … … … …
95 2018-08-14 False daily 210.155 210.560 … 205.280052 205.675657 203.429010 204.884447 20748010.0
96 2018-08-13 False daily 207.700 210.952 … 202.882001 206.058564 202.882001 204.024860 25890880.0
97 2018-08-10 False daily 207.360 209.100 … 202.549887 204.249525 201.875893 202.715944 24611202.0
98 2018-08-09 False daily 207.280 209.780 … 201.764139 204.197612 201.686268 203.321562 23492626.0
99 2018-08-08 False daily 206.050 207.810 … 200.566870 202.280035 199.077584 201.734937 22525487.0

Let's update our dataframe only to contain our adjusted values in OHLCV + BV format.

df.set_index('date', inplace=True)
df = df[['adj_open', 'adj_high', 'adj_low', 'adj_close', 'adj_volume']]
df.loc[:,'pb'] = pricetobook

adj_open adj_high adj_low adj_close adj_volume pb
date
2018-12-31 155.392897 156.206472 153.383464 154.618530 35003466.0 10.4128
2018-12-28 154.383279 155.383095 151.491656 153.138411 42291424.0 10.4128
2018-12-27 152.756128 153.667725 147.100309 153.059994 53117065.0 10.4128
2018-12-26 145.365335 154.118622 143.816601 154.059809 58582544.0 10.4128
2018-12-24 145.218304 148.551022 143.689174 143.924425 37169232.0 10.4128
… … … … … … …
2018-08-14 205.280052 205.675657 203.429010 204.884447 20748010.0 10.4128
2018-08-13 202.882001 206.058564 202.882001 204.024860 25890880.0 10.4128
2018-08-10 202.549887 204.249525 201.875893 202.715944 24611202.0 10.4128
2018-08-09 201.764139 204.197612 201.686268 203.321562 23492626.0 10.4128
2018-08-08 200.566870 202.280035 199.077584 201.734937 22525487.0 10.4128

Writing the data from a pandas dataframe to a CSV file is easy.

df.to_csv('aapl.csv')

You've now learned to add Intrinio calculations and fundamentals to your data. Before next month's post, try adding this and other fundamental data into Backtrader.

Sorry, we no longer support Internet Explorer as a web browser.

Please download one of these alternatives and return for the full Intrinio Experience.

Google Chrome web browser icon
Chrome
Mozilla Firefox web browser icon
Firefox
Safari web browser icon
Safari
Microsoft Edge web browser icon
Microsoft Edge