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