Get 10+ years of daily OHLCV stock data as JSON or CSV with a few lines of code, load it into pandas, and calculate returns and moving averages. The stock-prices endpoint is available on the free plan (300 requests/day), so you can try everything below without paying.
- API docs: https://financialdata.net/documentation
- Stock Prices API page: https://financialdata.net/stock-prices-api
- Pricing / free key: https://financialdata.net/pricing
- Official Python SDK: https://pypi.org/project/fdnpy/
Sign up at financialdata.net and copy your key. Every request takes it as a query parameter: ?key=YOUR_API_KEY (or &key=... if other parameters are present).
export FDN_API_KEY="your_api_key_here"GET https://financialdata.net/api/v1/stock-prices
| Parameter | Required | Description | Example |
|---|---|---|---|
identifier |
yes | Ticker symbol | MSFT |
offset |
no | Records to skip (default 0); page size is 300 records |
300 |
format |
no | json (default) or csv |
csv |
key |
yes | Your API key | YOUR_KEY |
Each record contains trading_symbol, date, open, high, low, close and volume. Results come back newest first.
Example record (MSFT, 2026-09-28):
{
"trading_symbol": "MSFT",
"date": "2026-09-28",
"open": 505.47,
"high": 513.33,
"low": 502.22,
"close": 509.22,
"volume": 19626940.0
}curl "https://financialdata.net/api/v1/stock-prices?identifier=MSFT&key=$FDN_API_KEY"
# Next page of history (older data)
curl "https://financialdata.net/api/v1/stock-prices?identifier=MSFT&offset=300&key=$FDN_API_KEY"
# CSV output
curl "https://financialdata.net/api/v1/stock-prices?identifier=MSFT&format=csv&key=$FDN_API_KEY" -o msft.csvimport os
import time
import requests
import pandas as pd
API_KEY = os.environ["FDN_API_KEY"]
BASE_URL = "https://financialdata.net/api/v1/stock-prices"
PAGE_SIZE = 300 # records per request
def get_price_history(symbol: str, max_pages: int = 5) -> pd.DataFrame:
"""Download daily OHLCV history for `symbol`, newest first, then sort oldest -> newest."""
rows = []
for page in range(max_pages):
resp = requests.get(
BASE_URL,
params={"identifier": symbol, "offset": page * PAGE_SIZE, "key": API_KEY},
timeout=30,
)
resp.raise_for_status()
batch = resp.json()
if not batch:
break
rows.extend(batch)
if len(batch) < PAGE_SIZE:
break
time.sleep(0.5) # be polite; free plan is 300 requests/day
df = pd.DataFrame(rows)
df["date"] = pd.to_datetime(df["date"])
return df.sort_values("date").set_index("date")
df = get_price_history("MSFT", max_pages=3) # roughly 3 years of trading days
print(df[["open", "high", "low", "close", "volume"]].tail())df["return"] = df["close"].pct_change()
df["sma_20"] = df["close"].rolling(20).mean()
df["sma_50"] = df["close"].rolling(50).mean()
df["volatility_20d"] = df["return"].rolling(20).std() * (252 ** 0.5) # annualized
print(df[["close", "sma_20", "sma_50", "volatility_20d"]].tail())import matplotlib.pyplot as plt
ax = df[["close", "sma_20", "sma_50"]].plot(figsize=(11, 5), title="MSFT close with 20/50-day SMA")
ax.set_ylabel("USD")
plt.tight_layout()
plt.show()symbols = ["MSFT", "AAPL", "NVDA"]
closes = pd.concat(
{s: get_price_history(s, max_pages=2)["close"] for s in symbols}, axis=1
).dropna()
normalized = closes / closes.iloc[0] * 100 # rebased to 100
normalized.plot(figsize=(11, 5), title="Price performance (rebased to 100)")If you would rather not write the HTTP and pagination code yourself:
pip install fdnpyfrom fdnpy import FinancialDataClient
# Create the client with your API key (see the PyPI page for the current setup options)
client = FinancialDataClient(api_key="YOUR_API_KEY")
prices = client.get_stock_prices(identifier="MSFT")
print(prices[0])The SDK handles automatic pagination and retries with exponential backoff. See the PyPI page for the current client options.
const API_KEY = process.env.FDN_API_KEY;
async function getPrices(symbol, offset = 0) {
const url = new URL("https://financialdata.net/api/v1/stock-prices");
url.searchParams.set("identifier", symbol);
url.searchParams.set("offset", offset);
url.searchParams.set("key", API_KEY);
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
getPrices("MSFT").then((rows) => {
const latest = rows[0];
console.log(`${latest.trading_symbol} closed at ${latest.close} on ${latest.date}`);
});- Rate limits: the free plan allows 300 requests per day.
- Bulk analysis: use
format=csvfor quick loads into spreadsheets orpandas.read_csv. - Other datasets: the same API covers symbol lists, ETF and index prices, international stocks, crypto, forex, financial statements, insider trades and more. See the full endpoint list. Some datasets need a paid plan, so check the plan shown next to each endpoint.