EOD Historical Data
EODHD — End-of-day prices for 150,000 tickers on 60 exchanges, plus fundamentals — a free tier for testing
When coverage beyond the US matters — KOSPI or Nikkei constituents, European mid-caps — and you are prepared to pay a small monthly fee for it; the free tier is for testing the schema.
Reach for it when…
When coverage beyond the US matters — KOSPI or Nikkei constituents, European mid-caps — and you are prepared to pay a small monthly fee for it; the free tier is for testing the schema.
Not for: Free-tier production use (20 calls a day, US only, one year), tick data, anything you will redistribute.
Units, revisions, traps
Units. Prices in the listing currency; adjusted_close carries splits and dividends. Exchange suffixes matter: .US, .KO (Korea), .TSE (Tokyo), .XETRA.
Revisions. Adjusted prices change with corporate actions; unadjusted only with corrections.
- The demo token works for a fixed set of tickers; a 'not found' with demo is not real.
- Symbols need the exchange suffix; 005930.KO is Samsung Electronics.
- The free tier returns one year of history no matter what you ask for.
Classic mistake: Charting 'close' when 'adjusted_close' was the question.
Three recipes
- Recipe 1 · End-of-day bars, JSON
- Recipe 2 · A Korean or Japanese ticker (paid plan)
- Recipe 3 · Fundamentals for one ticker
Each recipe: Python · Excel · Sheets, with how to read the result. Python recipes run under pandas; recipe 1 is re-run by the weekly check where the source allows it.
How to use it in your own work
Copy the snippet, change the series id, read the result the way the footer says. Replace YOUR_…_KEY with your own key where one is needed.
Recipe 1End-of-day bars, JSON
import requests, pandas as pd
TOKEN = "demo" # MCD.US works with demo; use your token for anything else
u = f"https://eodhd.com/api/eod/MCD.US?api_token={TOKEN}&fmt=json&from=2026-01-01"
df = pd.DataFrame(requests.get(u, timeout=30).json()).set_index("date")
print(df[["close", "adjusted_close", "volume"]].tail())- Data → From Web → the same URL with &fmt=csv → Load.
=IMPORTDATA("https://eodhd.com/api/eod/MCD.US?api_token=demo&fmt=csv&from=2026-01-01")Recipe 2A Korean or Japanese ticker (paid plan)
import requests, pandas as pd
TOKEN = "YOUR_EODHD_TOKEN"
u = f"https://eodhd.com/api/eod/005930.KO?api_token={TOKEN}&fmt=json&from=2025-01-01" # Samsung Electronics
df = pd.DataFrame(requests.get(u, timeout=30).json()).set_index("date")
print(df[["close", "adjusted_close"]].tail())- From Web with &fmt=csv.
=IMPORTDATA with &fmt=csv.Recipe 3Fundamentals for one ticker
import requests
TOKEN = "YOUR_EODHD_TOKEN"
j = requests.get(f"https://eodhd.com/api/fundamentals/AAPL.US?api_token={TOKEN}", timeout=60).json()
print(j["General"]["Name"], j["Highlights"]["MarketCapitalization"], j["Highlights"]["PERatio"])- Use the Python recipe.
- Use the Python recipe.
Series → question map
The ids we use from EODHD, each with the question it answers. The catalog's compare view reads the concept tags behind these rows.
| Series | Answers | Region | Concept |
|---|---|---|---|
| eod · MCD.US | Daily OHLC and adjusted close for a stock | United States | ohlc_daily |
| eod · 005930.KO | Korean and Japanese tickers, daily | Korea | ohlc_daily |
| fundamentals | Statements and ratios for a ticker | global | fundamentals |
| intraday | Intraday bars | global | intraday |
Compare with
Same question, different source: Twelve Data, Polygon.io, Stooq. The compare view lines up coverage, frequency, history and access side by side and lists what the combination makes possible.
Questions readers ask
Is EODHD free?
A free tier for testing (20 calls a day, US only, one year); real use is a paid plan.
Does it cover Korea and Japan?
Yes on paid plans — KRX (.KO, .KQ) and Tokyo (.TSE) among 60 exchanges.
Where do the fundamentals come from?
Normalised from filings and vendor feeds; the filed number is on EDGAR or DART.
Educational only — we explain, we never advise · snippet licence: public domain · corrections to [email protected], fixed within a day and logged in the changelog.