Historical Stock Price Data using Python APIs
By: Sugath Mudali
Tags: Python, Data Science, Stock Market, API

Get daily and minute level historical stock data using Yahoo! Finance & Tiingo APIs, Pandas and plot them using Matplotlib

Stock market data APIs offer real-time or historical data on financial assets that are being traded on the stock exchanges. See The ultimate guide to (free) stock market APIs for 2020 for a list recommended API providers.

This article assumes that you have some Python fundamentals, Pandas and Matplotlib knowledge. The focus is on the following packages to access stock data:

yfinance — Yahoo! Finance

yfinance package provides access to Yahoo! Financial market data despite unavailability of Yahoo! Finance APIs since 2017. Follow the package link for more information on installation and documentation.

Tiingo has its own API to access data, but we will be using pandas-datareader for this article. An advantage of using the pandas-datareader package is that it converts data into a Panda’s DataFrame object. Access to Tiingo data requires an API key which can be obtained free by signing up for the starter package.

Accessing the Data

The code below shows how to get historical stock price data for Stock symbol MSFT (Microsoft) from 2019 to May 30 2020 using yfinance package.

import yfinance as yf

df = yf.download('MSFT', start='2019-01-01', end='2020-05-30')['Adj Close']

pandas-datareader adopts a similar approach for Tiingo data:

import pandas_datareader as pdr df = pdr.get_data_tiingo('MSFT', start='2019-01-01', end='2020-05-30', api_key='your API key')['adjClose']

DataFrame from yfinance is indexed on Date and the DataFrame from pandas-datareader is indexed on Stock Symbol and Date.

Let’s check the first 5 rows and some basic statistical details like percentile, mean, std etc. from Yahoo! Finance

>>> df.head() Date

2018-12-31 99.540192

2019-01-02 99.099190

2019-01-03 95.453529

2019-01-04 99.893005

2019-01-07 100.020401

Name: Adj Close, dtype: float64 >>> df1.describe() count 356.000000

mean 140.159973

std 23.215575

min 95.453529

25% 124.212427

50% 136.895386

75% 156.751591

max 187.663330

Name: Adj Close, dtype: float64

Similar results from Tiingo:

>>> df.head() symbol date

MSFT 2019-01-02 00:00:00+00:00 99.095845

2019-01-03 00:00:00+00:00 95.450309

2019-01-04 00:00:00+00:00 99.889631

2019-01-07 00:00:00+00:00 100.017029

2019-01-08 00:00:00+00:00 100.742216

Name: adjClose, dtype: float64 >>> df.describe() count 355.000000

mean 140.275875

std 23.151313

min 95.450309

25% 124.253615

50% 136.900906

75% 156.786183

max 187.672002

Name: adjClose, dtype: float64

Let’s plot the Adjusted Close prices from Yahoo! Finance using matplotlib

import matplotlib.pyplot as plt

import pandas as pd # Register the converters

pd.plotting.register_matplotlib_converters() # Load the data

df = get_adjusted_close() # Set the style to seaborn for plotting

plt.style.use('seaborn')

fig, ax = plt.subplots(figsize=(12, 6)) # Plot the cumulative returns fot each symbol

ax.plot(df)

ax.legend() plt.title('Adjusted Close Price - MSFT', fontsize=16) # Define the labels for x-axis and y-axis

plt.ylabel('Adjusted Close Price', fontsize=14) plt.xlabel('Year', fontsize=14)

plt.show()

plt.close()

Here is the output:

Adjusted close price for MSFT

Plotting data from Tiingo is similar except for passing data to plot as shown below:

ax.plot(df.loc[‘MSFT’])

Cumulative Return

Expressed as a percentage, cumulative return is the total change in the price of an investment over a set time period — an aggregate return (see Cumulative Return vs. Annualized Return). It shows you an overall picture of how a company performs financially. It also allows comparison between multiple stocks as values are expressed in percentages.

Both yfinance and pandas-datareader packages accept a list of stock symbols to download data as shown below. The stock symbol SPY is included as it tracks the popular US index, the S&P 500.

Using yfinance:

import yfinance as yf tickers = [‘GOOG’, ‘MSFT’, ‘SPY’]

df = yf.download(tickers, start=’2019–1–1', end=’2020–05–30')[‘Adj Close’]

Using pandas-datareader:

import pandas_datareader as pdr tickers = [‘GOOG’, ‘MSFT’, ‘SPY’]

df = pdr.get_data_tiingo(tickers, start=’2019–01–01', end=’2020–05–30', api_key=’your API key’)[‘adjClose’]

Let’s plot Cumulative Returns for all 3 stocks using Yahoo! Finance data:

# imports omitted… # Set the style to seaborn for plotting

plt.style.use(‘seaborn’) fig, ax = plt.subplots(figsize=(12, 6)) # Plot the cumulative returns for each symbol

for ticker in tickers:

ax.plot((df[ticker].pct_change()+1).cumprod()-1, label=ticker) ax.legend() # Show y axis in %

ax.yaxis.set_major_formatter(mtick.PercentFormatter(1.0)) title = ‘Cumulative Returns — ‘ + ‘, ‘.join(s for s in tickers)

plt.title(title, fontsize=16) # Define the labels for x-axis and y-axis

plt.ylabel(‘Cumulative Returns %’, fontsize=14)

plt.xlabel(‘Year’, fontsize=14) plt.show()

plt.close()

And the output:

As you can see above, the Cumulative Returns from MSFT is significantly higher from mid 2019 onwards. However, all suffered a significant drop in 2020 Q1 for well known reasons.

Plotting Tiingo data is very similar to Yahoo! Finance except for accessing data for stock symbols as the DataFrame is indexed by Stock Symbol and Date.

# Plot the cumulative returns for each symbol

for ticker in tickers:

ax.plot((df.loc[ticker].pct_change()+1).cumprod()-1, label=ticker)

Moving Average

Moving Average (MA) is a simple, technical analysis tool. Moving averages are usually calculated to identify the trend direction of a stock or to determine its support and resistance levels.

Here is the code to calculate and plot 20 day MA and 100 day MA.

# Load the stock symbol MSFT – Tiingo (method not shown)

msft = get_adjusted_close().loc['MSFT'] # Set the style to seaborn for plotting

plt.style.use('seaborn') fig, ax = plt.subplots(figsize=(12, 6)) # Calculate the 20 and 100 days moving averages of the closing prices

msft_20_ma = msft.rolling(window=20).mean()

msft_100_ma = msft.rolling(window=100).mean() # Start from 24/05/2019 as there are no data before for 100-day MA

start_date = '2019-05-24 00:00:00+00:00'

ax.plot(msft[start_date:], label='MSFT')

ax.plot(msft_20_ma[start_date:], label='20 days MA')

ax.plot(msft_100_ma[start_date:], label='100 days MA') ax.legend() plt.title('Adjusted Close Price - MSFT', fontsize=16) # Define the labels for x-axis and y-axis

plt.ylabel('Adjusted Close Price ($)', fontsize=14)

plt.xlabel('Year', fontsize=14) plt.show()

plt.close()

And the output:

Further Reading:

1. Python for Finance, Part I: Yahoo & Google Finance API, pandas, and matplotlib