Skip to main content

Loading Historical Price Data

Historical market prices typically come in the form of OHLC+V - open, high, low, close, volume. There may be additional fields returned by a provider, but those are the expected columns.

Granularity and amount of historical data will vary by provider and subscription status. Visit their websites to understand what your entitlements are.

info

These examples will assume that the OpenBB Platform is initialized in a Python session.

from openbb import obb
import pandas as pd

Historical OHLC

Details

The historical function is located under a submodule for each asset type. In the openbb-equity module.

help(obb.equity.price.historical)
  • This endpoint has the most number of providers out of any function. At the time of writing, choices are:

['alpha_vantage', 'cboe', 'fmp', 'intrinio', 'polygon', 'tiingo', 'tmx', 'tradier', 'yfinance']

  • Common parameters have been standardized across all sources, start_date, end_date, interval.

  • The default interval will be 1d.

  • The depth of historical data and choices for granularity will vary by provider and subscription status. Refer to the website and documentation of each source understand your specific entitlements.

  • Despite being in the equity module, it's might be possible to get other asset types, like currencies or crypto, from the same endpoint.

  • For demonstration purposes, we will use the openbb-yfinance data extension.

df_daily = obb.equity.price.historical(symbol = "spy", provider="yfinance")
df_daily.to_df().head(1)
dateopenhighlowclosevolumedividendsstock splitscapital gains
2022-11-22396.63400.07395.15399.960429000000

To load the entire history available from a source, pick a starting date well beyond what it might be. For example, 1900-01-01

df_daily =(
obb.equity.price.historical(symbol = "spy", start_date = "1990-01-01", provider="yfinance")
.to_df()
)
df_daily.head(1)
dateopenhighlowclosevolumedividendsstock splitscapital gains
1993-01-2943.9743.9743.7543.941003200000
Intervals

The intervals are entered according to this pattern:

  • 1m = One Minute
  • 1h = One Hour
  • 1d = One Day
  • 1W = One Week
  • 1M = One Month

The date for monthly value is the first or last, depending on the provider. This can be easily resampled from daily data.

df_monthly = (
obb.equity.price.historical("spy", start_date="1990-01-01", interval="1M", provider="yfinance")
.to_df()
)
df_monthly.tail(2)
dateopenhighlowclosevolumedividendsstock splitscapital gains
2023-10-01426.62438.14409.21418.21999149700000
2023-11-01419.2456.38418.65455.021161239576000
Resample a Time Series

yfinance returns the monthly data for the first day of each month. Let's resample it to take from the last, using the daily information captured in the previous cells.

(
df_daily[["open", "high", "low", "close", "volume"]]
.resample("M")
.agg(
{"open": "first", "high": "max", "low": "min", "close": "last", "volume": "sum"}
).tail(2)
)
dateopenhighlowclosevolume
2023-10-31426.62438.14409.21418.21999149700
2023-11-30419.2456.38418.65455.021210484176

We can see that the current month's total volume is higher when we resample the daily time series. It is difficult to know where the discrepancy lays, and it may just be a temporary glitch. However, we can verify that the total volume, according to YahooFinance, is the number we just sampled.

note

If you are following along, the results will not match exactly what is displayed here.

df_daily.loc["2023-11-01":].sum()["volume"]
1210484176
Differences Between Sources

To demonstrate the difference between sources, let's compare values for daily volume from several sources.

# Collect the data

yahoo = obb.equity.price.historical("spy", provider="yfinance").to_df()
alphavantage = obb.equity.price.historical("spy", provider = "alpha_vantage").to_df()
intrinio = obb.equity.price.historical("spy", provider="intrinio").to_df()
fmp = obb.equity.price.historical("spy", provider="fmp").to_df()

# Make a new DataFrame with just the volume columns
compare = pd.DataFrame()
compare["AV Volume"] = alphavantage["volume"].tail(10)
compare["FMP Volume"] = fmp["volume"].tail(10)
compare["Intrinio Volume"] = intrinio["volume"].tail(10)
compare["Yahoo Volume"] = yahoo["volume"].tail(10)

compare
dateAV VolumeFMP VolumeIntrinio VolumeYahoo Volume
2023-11-0983174417830714178317441783174400
2023-11-1089558054895580548955805489462200
2023-11-1352236068521925685223606852236100
2023-11-1497176935971305039717693597176900
2023-11-1577327573773275737732757377327600
2023-11-1666665797666544686666579766665800
2023-11-1783193902831939028319390283133200
2023-11-2070055633696146337005563369936200
2023-11-2149244639492446394924463949244600
2023-11-2259446573593138205820578059394900

Other Types of Symbols

Details

Other types of assets and ticker symbols can be loaded from obb.equity.price.historical(), below are some examples but not an exhaustive list.

Share Classes

Some sources use - as the distinction between a share class, e.g., BRK-A and BRK-B. Other formats include:

  • A period: BRK.A
  • A slash: BRK/A
  • No separator, the share class becomes the fourth or fifth letter.
obb.equity.price.historical("brk.b", provider="polygon")
obb.equity.price.historical("brk-b", provider="fmp")

While some providers handle the different formats on their end, others do not.

This is something to consider when no results are returned from one source.

Some may even use a combination, or accept multiple variations. Sometimes there is no real logic behind the additional characters, GOOGL vs. GOOG.

These are known unknown variables of ticker symbology, what's good for one source may return errors from another.

Regional Identifiers

With providers supporting market data from multiple jurisdictions, the most common method for requesting data outside of US-listings is to append a suffix to the ticker symbol (e.g., RELIANCE.NS).

Formats may be unique to a provider, so it is best to review the source's documentation for an overview of their specific conventions.

This page on Yahoo describes how they format symbols, which many others follow to some degree.

openbb-tmx follows the composite convention, "SPY:US". When the symbol is for its domestic Canadian market, "CNQ", no identifier is required.

Indices

Sources will have their own treatment of these symbols, some examples are:

  • YahooFinance/FMP/CBOE: ^RUT
  • Polygon: I:NDX
obb.equity.price.historical("^RUT", provider="cboe").to_df().tail(1)
dateopenhighlowclosevolume
2023-11-221796.371804.961785.931792.920
obb.equity.price.historical("^RUT", provider="fmp").to_df().tail(1)
dateopenhighlowclosevolumevwaplabeladj_closeunadjusted_volumechangechange_percentchange_over_time
2023-11-221792.511803.121789.881795.5401796.18November 22, 231795.5403.028930.168980.0016898
info

For an endpoint geared more specifically towards indices, try obb.index.price.historical()

Currencies

FX symbols face the same dilemma as share classes, there are several variations of the same symbol.

  • YahooFinance: EURUSD=X
  • Polygon: C:EURUSD
  • AlphaVantage/FMP: EURUSD
info

The symbol prefixes are handled internally when obb.currency.price.historical() is used, enter as a pair with no extra characters.

obb.equity.price.historical("EURUSD=X", provider="yfinance").to_df().tail(1)
dateopenhighlowclosevolumedividendsstock splits
2023-11-221.09181.09231.08551.0918000
obb.equity.price.historical("C:EURUSD", provider="polygon").to_df().tail(1)
dateopenhighlowclosevolumevwaptransactions
2023-11-211.091681.09231.08511.08881558271.0893155827
Crypto

Similar, but different to FX tickers.

  • YahooFinance: BTC-USD
  • Polygon: X:BTCUSD
  • AlphaVantage/FMP: BTCUSD
info

The symbol prefixes are handled internally when obb.crypto.price.historical() is used, enter as a pair with no extra characters and placing the fiat currency second.

obb.equity.price.historical("X:BTCUSD", provider="polygon").to_df().tail(1)
dateopenhighlowclosevolumevwaptransactions
2023-11-2135756379003563337433.830411.436841.5464907

As noted above, X: or other prefixes are not required when using the crypto version of this same endpoint.

obb.crypto.price.historical("BTCUSD", provider="polygon").to_df().tail(1)
dateopenhighlowclosevolumevwaptransactions
2023-11-2135756379003563337433.830411.436841.5464907
Futures

Historical prices for the continuation chart, can be fetched by the fmp or yfinance data extensions. Individual active contracts are returned by yfinance.

  • Continuous front-month: CL=F
  • December 2023 contract: CLZ24.NYM
  • March 2024 contract: CLH24.NYM

Individual contracts will require knowing which of the CME venues the future is listed on. ["NYM", "NYB", "CME", "CBT"].

obb.equity.price.historical("CL=F", provider="fmp").to_df().tail(1)
dateopenhighlowclosevolumevwaplabeladj_closeunadjusted_volumechangechange_percentchange_over_time
2023-11-2277.7777.9773.7976.7836868676.18November 22, 2376.78368686-0.99-1.27-0.0127
obb.equity.price.historical("CLZ24.NYM", provider="yfinance").to_df().tail(1)
dateopenhighlowclosevolumedividendsstock splits
2023-11-2274.0774.0773.4173.4661000
Options

Individual options contracts are also loadable from openbb.equity.price.historical().

  • YahooFinance: SPY241220P00400000
  • Polygon: O:SPY241220P00400000
obb.equity.price.historical("SPY241220P00400000", provider="yfinance").to_df().tail(1)
dateopenhighlowclosevolumedividendsstock splits
2023-11-22 00:00:0010.510.8210.2510.617700
obb.equity.price.historical("O:SPY241220P00400000", provider="polygon").to_df().tail(1)
dateopenhighlowclosevolumevwaptransactions
2023-11-2010.910.9510.7510.751710.837610