A lightweight FastAPI microservice that wraps yfinance, exposing RESTful finance API endpoints and a ready-to-run yfinance Docker container for production deployments. Ideal for non-Python projects, microservice architectures, and monitorable deployments.
- Language-agnostic HTTP API: Expose Yahoo Finance data to any platform without embedding Python.
- Containerized deployment: Ready Docker image and compose stack for Prometheus + Grafana.
- Extendable FastAPI app: Easy to add routes, middleware, or auth.
- Caching & instrumentation: Includes a TTL in-memory cache with async locks and Prometheus metrics.
- Robust yfinance wrapper: Calls are wrapped with timeouts,
lru_cacheticker caching, and async-to-thread execution to reduce upstream variability. - Observability:
/metricsendpoint and sample Grafana dashboards for latency, cache, and error monitoring.
| Feature | Description |
|---|---|
| Quote API | Fetch latest market quotes (OHLCV) for ticker symbols. |
| Historical API | Retrieve historical data with flexible intervals (1h, 1d, 1wk, 1mo). |
| Info API | Get company fundamentals (sector, market cap, etc.). |
| News API | Get news about company |
| Earnings API | Retrieve normalized earnings history with EPS, revenue, and surprise data. |
| Snapshot API | Combined info + quote in a single request with caching. |
| Splits API | Retrieve historical stock split data (dates and ratios) for ticker symbols. |
| Health Check | /health and /ready endpoints for liveness & readiness probes. |
| Prometheus Metrics | /metrics endpoint for request count, errors, latency, cache stats. |
| Endpoint | Description | Example |
|---|---|---|
GET /quote/{symbol} |
Latest quote for a symbol | /quote/AAPL |
GET /quote?symbols=SYM1,SYM2 |
Bulk quotes (CSV) | /quote?symbols=AAPL,MSFT |
GET /historical/{symbol}?start=&end=&interval= |
Historical OHLCV data | /historical/AAPL?start=2024-01-01&end=2024-02-01&interval=1d |
GET /info/{symbol} |
Company details | /info/TSLA |
GET /news/{symbol}?count={count}&tab={tab} |
Company news (Allowed tab values are news (default), press-releases and all) |
/news/TSLA?count=5&tab=news |
GET /health |
Health check | /health |
GET /metrics |
Prometheus metrics | /metrics |
GET /earnings/{symbol}?frequency={period} |
Earnings history (EPS, revenue, surprise) | /earnings/AAPL?frequency=quarterly |
GET /snapshot/{symbol} |
Combined info + quote | /snapshot/AAPL |
GET /ready |
Readiness check (yfinance connectivity) | /ready |
GET /splits/{symbol} |
List of stock splits (date and ratio) for the given symbol | /splits/AAPL |
docker pull ghcr.io/vorckea/yfinance-service:latest
docker run -p 8000:8000 ghcr.io/vorckea/yfinance-service:latestThen visit:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
poetry install
poetry run uvicorn app.main:app --reloaddocker compose up --buildAccess:
- API: http://localhost:8000
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000
Relevant files:
- Prometheus config:
monitoring/infra/prometheus.yml - Alert rules:
monitoring/infra/alert.rules.yml - Dashboards:
monitoring/grafana/dashboards/
| Variable | Description | Default | Example |
|---|---|---|---|
LOG_LEVEL |
Logging level (CRITICAL/ERROR/WARNING/INFO/DEBUG/NOTSET) | INFO |
LOG_LEVEL=DEBUG |
MAX_BULK_CONCURRENCY |
Max concurrent requests for bulk quote endpoint | 10 |
MAX_BULK_CONCURRENCY=20 |
EARNINGS_CACHE_TTL |
Cache TTL for earnings data in seconds (0 = disable caching) | 3600 |
EARNINGS_CACHE_TTL=1800 |
EARNINGS_CACHE_MAXSIZE |
Max entries for earnings cache | 128 |
EARNINGS_CACHE_MAXSIZE=256 |
INFO_CACHE_TTL |
Cache TTL for company info (seconds) | 300 |
INFO_CACHE_TTL=300 |
INFO_CACHE_MAXSIZE |
Max entries for info cache | 256 |
INFO_CACHE_MAXSIZE=512 |
CORS_ENABLED |
Enable CORS | False |
CORS_ENABLED=True |
CORS_ALLOWED_ORIGINS |
Allowed origins (comma-separated list) | * (Any) |
CORS_ALLOWED_ORIGINS="https://example.org,https://www.example.org" |
SPLITS_CACHE_TTL |
Time-to-live (in seconds) for the stock splits cache | 3600 |
SPLITS_CACHE_TTL=1800 |
API_KEY_ENABLED |
Enable API key authentication | False |
API_KEY_ENABLED=True |
API_KEY |
API key for authentication (required if enabled) | "" |
API_KEY=your-secret-key-here |
Optionally protect endpoints with API key authentication:
# Enable authentication
API_KEY_ENABLED=true
API_KEY=your-secret-key-hereUsage:
# Include API key in X-API-Key header
curl -H "X-API-Key: your-secret-key-here" http://localhost:8000/quote/AAPLProtected endpoints:
/quote/*- Stock quotes/historical/*- Historical data/info/*- Company information/snapshot/*- Combined snapshots/earnings/*- Earnings data
Unprotected endpoints:
/health,/ready- Health checks/metrics- Prometheus metrics/docs,/redoc- API documentation
Running natively (example)
# Increase bulk quote concurrency to 20
MAX_BULK_CONCURRENCY=20 poetry run uvicorn app.main:app
# Disable earnings caching
EARNINGS_CACHE_TTL=0 poetry run uvicorn app.main:app
# Reduce earnings cache to 30 minutes
EARNINGS_CACHE_TTL=1800 poetry run uvicorn app.main:app
# Enable API key authentication
API_KEY_ENABLED=true API_KEY=my-secret-key poetry run uvicorn app.main:appDocker compose (example)
services:
yfinance-service:
build: .
image: ghcr.io/vorckea/yfinance-service:latest
env_file: .env # local use only; do not commit secrets to repo
environment:
- LOG_LEVEL=INFO
- MAX_BULK_CONCURRENCY=10
- EARNINGS_CACHE_TTL=3600
- API_KEY_ENABLED=true
- API_KEY=${API_KEY} # Load from .env file or environment
ports:
- "8000:8000"Kubernetes (example)
# secret.yaml (sensitive values like API keys)
apiVersion: v1
kind: Secret
metadata:
name: yfinance-secret
type: Opaque
stringData:
API_KEY: "your-secret-key-here"
# configmap.yaml (non-sensitive configuration)
apiVersion: v1
kind: ConfigMap
metadata:
name: yfinance-config
data:
LOG_LEVEL: "INFO"
MAX_BULK_CONCURRENCY: "10"
EARNINGS_CACHE_TTL: "3600"
API_KEY_ENABLED: "true"
# deployment.yaml (connects ConfigMap as env vars and uses a Secret for sensitive values)
apiVersion: apps/v1
kind: Deployment
metadata:
name: yfinance-service
spec:
replicas: 1
selector:
matchLabels:
app: yfinance-service
template:
metadata:
labels:
app: yfinance-service
spec:
containers:
- name: yfinance-service
image: ghcr.io/vorckea/yfinance-service:latest
ports:
- containerPort: 8000
envFrom:
- configMapRef:
name: yfinance-config
- secretRef:
name: yfinance-secret
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 15
periodSeconds: 20Get the latest quote for Apple:
# Without authentication (if API_KEY_ENABLED=false)
curl http://localhost:8000/quote/AAPL
# With authentication (if API_KEY_ENABLED=true)
curl -H "X-API-Key: your-secret-key-here" http://localhost:8000/quote/AAPLResponse:
{
"symbol": "AAPL",
"current_price": 178.72,
"previous_close": 177.49,
"open_price": 177.52,
"high": 179.63,
"low": 176.21,
"volume": 62456800
}Fetch quotes for multiple symbols:
curl http://localhost:8000/quote?symbols=AAPL,MSFT,GOOGLGet company info for Tesla:
curl http://localhost:8000/info/TSLAFetch quarterly earnings for Apple:
curl http://localhost:8000/earnings/AAPL?frequency=quarterlyFetch annual earnings for Apple:
curl http://localhost:8000/earnings/AAPL?frequency=annualPrometheus query for average latency (5-minute window):
rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m])
Contributions are welcome!
- Open an issue for bugs or new features.
- Look for good first issue labels to get started.
- Please see CONTRIBUTING.md
MIT License. See LICENSE for details.
Aksel Heggland Schrader (@Vorckea)
Keywords: yfinance docker, yahoo finance api, stock market api, yfinance rest api, yfinance microservice, stock data api, financial data api, python finance api, fastapi stock api
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!