Skip to content

Stock Data

Access historical OHLCV (Open, High, Low, Close, Volume) market data with automatic interval aggregation.

MethodEndpointAuthDescription
GET/stocksNoList available symbols
GET/stocks/{symbol}/ohlcvNoGet OHLCV data for symbol
GET/stocks/batchNoGet data for multiple symbols

Get all available stock symbols in the database.

GET /api/v1/stocks?limit=100
ParameterTypeDefaultDescription
limitinteger100Max symbols to return (1-1000)

Retrieve candlestick data for a specific symbol with automatic interval aggregation.

GET /api/v1/stocks/AAPL/ohlcv?interval=15m&start_date=2025-01-01&end_date=2025-01-31&limit=1000
ParameterTypeDescription
symbolstringStock ticker symbol (e.g., AAPL, MSFT)
ParameterTypeDefaultDescription
intervalstring15mData interval (see below)
start_datedate-Filter start date (YYYY-MM-DD)
end_datedate-Filter end date (YYYY-MM-DD)
limitinteger1000Max records (1-10,000)
allow_aggregationbooleantrueAuto-aggregate from finer intervals
market_hours_onlybooleanfalseFilter to 9:30 AM - 4:00 PM ET only
IntervalDescription
1m1 minute
5m5 minutes
15m15 minutes
30m30 minutes
1h1 hour
1d1 day (daily)
FieldTypeDescription
timedatetimeCandle timestamp (UTC)
symbolstringStock symbol
openfloatOpening price
highfloatHighest price
lowfloatLowest price
closefloatClosing price
volumeintegerTrading volume
vwapfloatVolume-weighted average price
HeaderValuesDescription
X-Data-Sourcestored, aggregatedWhether data was stored or aggregated
X-Market-Hourstrue, falseWhether market hours filter was applied

When the requested interval doesn’t exist in the database, the API automatically aggregates from finer-grained data using TimescaleDB’s time_bucket() function.

1m ──► 5m ──► 15m ──► 30m ──► 1h
│ │ │ │
└──────┴───────┴───────┴──── Can aggregate to
Source IntervalCan Aggregate To
1m5m, 15m, 30m, 1h
5m15m, 30m, 1h
15m30m, 1h
30m1h
FieldAggregation Method
openFirst value in bucket
highMaximum in bucket
lowMinimum in bucket
closeLast value in bucket
volumeSum of all values
vwapVolume-weighted average
// Request 15-minute data
const response = await fetch('/api/v1/stocks/AAPL/ohlcv?interval=15m');
// Check if data was aggregated
console.log(response.headers.get('X-Data-Source'));
// Output: "aggregated" (if 15m data didn't exist but 1m did)
const data = await response.json();

Retrieve OHLCV data for multiple symbols in a single request.

GET /api/v1/stocks/batch?symbols=AAPL,MSFT,GOOGL&start_date=2025-01-01&end_date=2025-01-31&limit=100
ParameterTypeDescription
symbolsstringRequired. Comma-separated symbols (max 20)
start_datedateStart date filter
end_datedateEnd date filter
limitintegerMax records per symbol (default: 1000)

import axios from 'axios';
const api = axios.create({
baseURL: 'http://localhost:8501/api/v1'
});
// Get daily AAPL data for 2024
async function getStockData() {
const { data, headers } = await api.get('/stocks/AAPL/ohlcv', {
params: {
interval: '1d',
start_date: '2024-01-01',
end_date: '2024-12-31',
limit: 365
}
});
console.log(`Fetched ${data.length} candles`);
console.log(`Data source: ${headers['x-data-source']}`);
// Calculate simple statistics
const closes = data.map(d => d.close);
const avgClose = closes.reduce((a, b) => a + b, 0) / closes.length;
const maxClose = Math.max(...closes);
const minClose = Math.min(...closes);
console.log(`Average close: $${avgClose.toFixed(2)}`);
console.log(`High: $${maxClose.toFixed(2)}, Low: $${minClose.toFixed(2)}`);
return data;
}
// Get intraday data with market hours filter
async function getIntradayData(symbol) {
const { data } = await api.get(`/stocks/${symbol}/ohlcv`, {
params: {
interval: '15m',
market_hours_only: true,
limit: 2000
}
});
return data;
}
// Batch request for portfolio
async function getPortfolioData(symbols) {
const { data } = await api.get('/stocks/batch', {
params: {
symbols: symbols.join(','),
start_date: '2025-01-01',
limit: 100
}
});
// Group by symbol
const bySymbol = data.reduce((acc, candle) => {
if (!acc[candle.symbol]) acc[candle.symbol] = [];
acc[candle.symbol].push(candle);
return acc;
}, {});
return bySymbol;
}
// Usage
const appleData = await getStockData();
const portfolio = await getPortfolioData(['AAPL', 'MSFT', 'GOOGL']);
import requests
import pandas as pd
from datetime import datetime, timedelta
BASE_URL = "http://localhost:8501/api/v1"
def get_stock_data(
symbol: str,
interval: str = "1d",
start_date: str = None,
end_date: str = None,
limit: int = 1000
) -> pd.DataFrame:
"""Fetch OHLCV data and return as DataFrame."""
params = {
"interval": interval,
"limit": limit
}
if start_date:
params["start_date"] = start_date
if end_date:
params["end_date"] = end_date
response = requests.get(
f"{BASE_URL}/stocks/{symbol}/ohlcv",
params=params
)
response.raise_for_status()
# Check data source
data_source = response.headers.get("X-Data-Source", "unknown")
print(f"Data source: {data_source}")
# Convert to DataFrame
data = response.json()
df = pd.DataFrame(data)
df["time"] = pd.to_datetime(df["time"])
df.set_index("time", inplace=True)
return df
def get_batch_data(symbols: list, **kwargs) -> dict:
"""Fetch data for multiple symbols."""
response = requests.get(
f"{BASE_URL}/stocks/batch",
params={
"symbols": ",".join(symbols),
**kwargs
}
)
response.raise_for_status()
data = response.json()
df = pd.DataFrame(data)
df["time"] = pd.to_datetime(df["time"])
# Group by symbol
return {symbol: group for symbol, group in df.groupby("symbol")}
# Usage examples
if __name__ == "__main__":
# Get AAPL daily data
aapl = get_stock_data("AAPL", interval="1d", limit=252)
print(f"AAPL: {len(aapl)} trading days")
print(aapl.tail())
# Calculate returns
aapl["returns"] = aapl["close"].pct_change()
print(f"Average daily return: {aapl['returns'].mean():.4%}")
print(f"Volatility (std): {aapl['returns'].std():.4%}")
# Get 15-minute data
aapl_intraday = get_stock_data(
"AAPL",
interval="15m",
start_date="2025-01-15",
end_date="2025-01-15"
)
print(f"Intraday candles: {len(aapl_intraday)}")
# Batch request
portfolio = get_batch_data(
["AAPL", "MSFT", "GOOGL"],
start_date="2025-01-01",
limit=50
)
for symbol, df in portfolio.items():
print(f"{symbol}: {len(df)} records")
Terminal window
# Get daily AAPL data
curl "http://localhost:8501/api/v1/stocks/AAPL/ohlcv?interval=1d&limit=100"
# Get 15-minute data with date range
curl "http://localhost:8501/api/v1/stocks/AAPL/ohlcv?\
interval=15m&\
start_date=2025-01-15&\
end_date=2025-01-15&\
market_hours_only=true"
# Batch request
curl "http://localhost:8501/api/v1/stocks/batch?\
symbols=AAPL,MSFT,GOOGL&\
start_date=2025-01-01&\
limit=50"
# Check response headers
curl -I "http://localhost:8501/api/v1/stocks/AAPL/ohlcv?interval=5m"
# Look for: X-Data-Source: aggregated

Use Date Ranges

Always specify start_date and end_date to limit data transfer and improve performance.

Batch Requests

Use /stocks/batch for multiple symbols instead of making separate requests.

Check Headers

Check X-Data-Source header to know if data was aggregated from finer intervals.

Appropriate Intervals

Use daily data for long-term analysis, 15m or 1h for intraday strategies.

  1. Limit data volume: Use limit and date ranges to fetch only what you need
  2. Cache responses: OHLCV data is immutable - cache aggressively
  3. Use aggregation: Let the API aggregate rather than fetching 1m data and aggregating client-side
  4. Market hours filter: Use market_hours_only=true to exclude pre/post market noise

StatusCauseResponse
404Symbol not found or no data{"detail": "No data found for symbol XXXX"}
400Invalid interval{"detail": "Invalid interval"}
400Too many batch symbols{"detail": "Maximum 20 symbols allowed per request"}