Exploring the finnhub.io API

Articles From: Robot Wealth
Website: Robot Wealth

Excerpt

The changing face of market data providers

Over the last few years, a number of new market data providers have come online. They tend to have modern websites, broad coverage, and well-documented RESTful APIs. Their services are often priced very competitively – especially for personal use – and usually have generous free tiers.

One such newcomer is finnhub.io (https://robotwealth.com/finnhub-api/finnhub.io) Its offering includes stock, bond, crpto, and FX historical price data and real time trades and quotes. Their fundamental data offering is noticably broad and includes current values and point-in-time snapshots for numerous metrics. There are also some interesting alternative data sets including measures of social media sentiment, insider transactions and insider sentiment, senate lobbying, government spending, and others. In addition, there’s a real-time newsfeed delivered over websockets.

The free tier is quite generous and offers more than enough for doing proof of concept work and testing ideas. While you only get a year’s worth of historical data per API call on the free tier (more if you specify a lower resolution, like monthly), you can make up to 50 calls per minute.

In this post, we’ll explore the finnhub.io free tier via its REST API.

Get started

A nice python library for working with the finnhub.io is available: pip install finnhub-python

To access the API, you’ll need an API key. Get one here.

To get started, import the libraries we need and set up a finnhub.Client with your API key:

import finnhub
import os
import time
import datetime
from zoneinfo import ZoneInfo
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# Set up client
# Note the FINNHUB_KEY environment variable stores my API key
finnhub_client = finnhub.Client(api_key=os.environ['FINNHUB_KEY'])

OHLCV stock prices

The stock prices endpoint requires a symbol, a resolution (‘D’ for daily data), and a date range consisting of ‘from’ and ‘to’ values as UNIX timestamps.

We’ll get a week’s worth of AAPL data from February 2023.

# helper function for making UNIX timestamps
def unix_timestamp_from_date(date, format='%Y-%m-%d'):
    '''Transform human readable date string to UNIX timestamp'''
    return int(
        datetime.datetime.strptime(date, format)
        .replace(tzinfo=ZoneInfo('US/Eastern'))
        .timestamp()
    )

# api query paramters
symbol = 'AAPL'
resolution = 'D'
from_date = unix_timestamp_from_date('2023-02-06')
to_date =  unix_timestamp_from_date('2023-02-10')

# make request and print
res = finnhub_client.stock_candles(
        symbol,
        resolution,
        from_date,
        to_date
      )

display(res)
{'c': [151.73, 154.65, 151.92, 150.87, 151.01],
 'h': [153.1, 155.23, 154.58, 154.33, 151.3401],
 'l': [150.78, 150.64, 151.168, 150.42, 149.22],
 'o': [152.575, 150.64, 153.88, 153.775, 149.46],
 's': 'ok',
 't': [1675641600, 1675728000, 1675814400, 1675900800, 1675987200],
 'v': [69858306, 83322551, 64120079, 56007143, 57450708]}

The data comes down as a dictionary of lists. The docs state that prices are adjusted for splits. Spot checking some data against other sources suggests it’s also adjusted for dividends.

The dictionary keys consist of letters that represent:

  • c: close prices
  • h: high prices
  • l: low prices
  • o: open prices
  • s: status
  • t: timestamps
  • v: volume traded

We’ll want to transform that response data into a pandas DataFrame:

# Ditch the status code
try:
  res.pop('s')
except KeyError as e:
  print("Already ditched status code")

# Create dataframe from remaining records
df = pd.DataFrame(res) \
  .rename(columns={
    'c': 'close',
    'h': 'high',
    'l': 'low',
    'o': 'open',
    't': 'timestamp',
    'v': 'volume'
    }) \
  .set_index(keys = 'timestamp')

# I like things in a certain order
df = df[['open', 'high', 'low', 'close', 'volume']]

# Convert index to human-readable date format
df.index = pd.to_datetime(df.index, unit='s')

display(df)
openhighlowclosevolume
timestamp
2023-02-06152.575153.1000150.780151.7369858306
2023-02-07150.640155.2300150.640154.6583322551
2023-02-08153.880154.5800151.168151.9264120079
2023-02-09153.775154.3300150.420150.8756007143
2023-02-10149.460151.3401149.220151.0157450708

Looks good!

Fundamental data

The basic company financials endpoint serves quite a lot of data. The response object is a dictionary of dictionaries that includes current values for various metrics (under the metric outer key) as well as historical point-in-time snapshots (under the series outer key).

# Get basic company financials
financials = finnhub_client.company_basic_financials(symbol, 'all')

# Outer keys of response object
display(financials.keys())
dict_keys(['metric', 'metricType', 'series', 'symbol'])

Originally posted on Robot Wealth Blog. Visit Robot Wealth to read the full article.

Disclosure: Interactive Brokers

Information posted on IBKR Campus that is provided by third-parties does NOT constitute a recommendation that you should contract for the services of that third party. Third-party participants who contribute to IBKR Campus are independent of Interactive Brokers and Interactive Brokers does not make any representations or warranties concerning the services offered, their past or future performance, or the accuracy of the information provided by the third party. Past performance is no guarantee of future results.

This material is from Robot Wealth and is being posted with its permission. The views expressed in this material are solely those of the author and/or Robot Wealth and Interactive Brokers is not endorsing or recommending any investment or trading discussed in the material. This material is not and should not be construed as an offer to buy or sell any security. It should not be construed as research or investment advice or a recommendation to buy, sell or hold any security or commodity. This material does not and is not intended to take into account the particular financial conditions, investment objectives or requirements of individual customers. Before acting on this material, you should consider whether it is suitable for your particular circumstances and, as necessary, seek professional advice.

Disclosure: API Examples Discussed

Throughout the lesson, please keep in mind that the examples discussed are purely for technical demonstration purposes, and do not constitute trading advice. Also, it is important to remember that placing trades in a paper account is recommended before any live trading.

Disclosure: Forex

There is a substantial risk of loss in foreign exchange trading. The settlement date of foreign exchange trades can vary due to time zone differences and bank holidays. When trading across foreign exchange markets, this may necessitate borrowing funds to settle foreign exchange trades. The interest rate on borrowed funds must be considered when computing the cost of trades across multiple markets.