Financial data service
FastAPI service for fetching financial market data using yfinance
The Financial Data service is a FastAPI-based microservice that provides REST API endpoints for fetching financial market data. It serves as a dedicated Python service for financial data operations, separate from the main Next.js application.
Architecture
The service is built using FastAPI and follows a clean architecture pattern:
packages/financial-data/
├── src/financial_data_api/
│ ├── core/config.py # Application configuration
│ ├── main.py # FastAPI application entry point
│ ├── routers/ # API route handlers
│ │ ├── current.py # Current price endpoints
│ │ ├── historical.py # Historical data endpoints
│ │ └── multiple.py # Batch ticker endpoints
│ ├── schemas/financial.py # Pydantic data models
│ └── services/ # Business logic
│ └── yfinance_service.py # Yahoo Finance integration
├── requirements.txt # Python dependencies
└── package.json # Turborepo integrationTechnology stack
- FastAPI: Modern, fast web framework for building APIs
- yfinance: Yahoo Finance data source with HTTP connection pooling
- Pydantic: Data validation and serialization
- pandas: Data manipulation and analysis
- uvicorn: ASGI server for production deployment
- requests: HTTP connection pooling and retry strategies
Security
Root endpoint protection
The root endpoint (/) is secured and returns a 404 error with no service information:
GET /Response:
{
"errors": [
{
"code": "not_found",
"detail": "Not found"
}
]
}Authentication
All API endpoints require authentication via the X-API-Key header:
X-API-Key: your-api-key-hereAPI endpoints
Base URL
- Local Development:
http://localhost:8000 - Production: Set via
FINANCIAL_API_URLenvironment variable
Health check
GET /health
GET /v1/financial-data/healthReturns service health status, available endpoints, and connection pooling information.
Response:
{
"status": "healthy",
"service": "Financial Data API",
"version": "0.1.0",
"endpoints": {
"historical": "/v1/financial-data/historical",
"current": "/v1/financial-data/current",
"multiple": "/v1/financial-data/multiple"
},
"connection_pooling": {
"enabled": true,
"pool_connections": 10,
"pool_maxsize": 20,
"session_active": true
}
}Historical data
POST /v1/financial-data/historical
GET /v1/financial-data/historical?symbol=AAPL&start_date=2024-01-01&end_date=2024-12-31&simplified_response=falseHeaders:
X-API-Key: your-api-key-here
Content-Type: application/jsonRequest Body (POST):
{
"symbol": "AAPL",
"start_date": "2024-01-01",
"end_date": "2024-12-31",
"validate_ticker": true,
"simplified_response": false
}Response:
{
"success": true,
"symbol": "AAPL",
"ticker_info": {
"symbol": "AAPL",
"name": "Apple Inc.",
"currency": "USD",
"exchange": "NASDAQ"
},
"price_data": [
{
"date": "2024-01-01",
"open": 150.00,
"high": 155.00,
"low": 149.00,
"close": 154.00,
"adj_close": 154.00,
"volume": 50000000,
"close_cents": 15400
}
],
"data_points": 252,
"date_range": {
"start_date": "2024-01-01",
"end_date": "2024-12-31",
"actual_start": "2024-01-02",
"actual_end": "2024-12-30"
}
}Simplified Response
For bandwidth optimization, you can request a simplified response containing only essential price data:
GET /v1/financial-data/historical?symbol=AAPL&start_date=2024-01-01&end_date=2024-12-31&simplified_response=trueSimplified Response:
{
"success": true,
"symbol": "AAPL",
"ticker_info": {
"symbol": "AAPL",
"name": "Apple Inc.",
"currency": "USD",
"exchange": "NASDAQ"
},
"price_data": [
{
"date": "2024-01-01",
"close": 154.00,
"close_cents": 15400
}
],
"data_points": 252
}Current price
POST /v1/financial-data/current
GET /v1/financial-data/current?symbol=AAPLHeaders:
X-API-Key: your-api-key-here
Content-Type: application/jsonRequest Body (POST):
{
"symbol": "AAPL"
}Response:
{
"success": true,
"symbol": "AAPL",
"ticker_info": {
"symbol": "AAPL",
"name": "Apple Inc.",
"currency": "USD",
"exchange": "NASDAQ"
},
"current_price": {
"price": 154.25,
"price_cents": 15425,
"currency": "USD",
"timestamp": "2024-01-15T16:00:00Z"
}
}Multiple tickers
POST /v1/financial-data/multiple
GET /v1/financial-data/multiple?symbols=AAPL,MSFT,GOOGL&start_date=2024-01-01&end_date=2024-12-31Headers:
X-API-Key: your-api-key-here
Content-Type: application/jsonRequest Body (POST):
{
"symbols": ["AAPL", "MSFT", "GOOGL"],
"start_date": "2024-01-01",
"end_date": "2024-12-31"
}Response:
{
"success": true,
"results": {
"AAPL": {
"success": true,
"symbol": "AAPL",
"price_data": [...],
"data_points": 252
},
"MSFT": {
"success": true,
"symbol": "MSFT",
"price_data": [...],
"data_points": 252
}
},
"total_symbols": 3,
"successful_symbols": 2
}Development
Setup
# Navigate to financial-data package
cd packages/financial-data
# Install Python dependencies
pip install -r requirements.txt
# Start development server
python -m uvicorn src.financial_data_api.main:app --reload --port 8000The service will start on http://localhost:8000 with:
- API Documentation:
/docs - Alternative Documentation:
/redoc - OpenAPI Schema:
/openapi.json
Integration with main app
The main Next.js application makes HTTP requests to the FastAPI service using the financial data query functions:
// Example usage in apps/app/src/lib/queries/financial-data.query.ts
const response = await fetch(`${baseUrl}/v1/financial-data/historical?${params}`, {
headers: {
"X-API-Key": apiKey,
},
});The application automatically detects the environment:
- Local Development: Uses
http://localhost:8000 - Production: Uses the
FINANCIAL_API_URLenvironment variable
Deployment
Environment variables
FINANCIAL_API_URL: Production FastAPI service URLFINANCIAL_API_KEY: API key for authenticating requestsFINANCIAL_API_DEBUG: Enable debug mode (default: false)FINANCIAL_API_HOST: Server host (default: 0.0.0.0)FINANCIAL_API_PORT: Server port (default: 8000)
Performance configuration
The service includes HTTP infrastructure optimizations:
- YFinance sessions: Managed internally by yfinance using curl_cffi for optimal performance
- Backup connection pools: 10 connection pools cached (configurable) for future extensions
- Retry strategy: Built into yfinance for reliable data fetching
- Timeouts: Configured for optimal balance of reliability and performance
- Keep-alive: HTTP connections managed efficiently by yfinance
Production deployment
The service can be deployed as a separate Python application to any platform supporting ASGI applications:
# Production server
uvicorn src.financial_data_api.main:app --host 0.0.0.0 --port 8000Configuration
Configuration is managed through src/financial_data_api/core/config.py:
class Settings(BaseSettings):
app_name: str = "Financial Data API"
version: str = "0.1.0"
debug: bool = False
host: str = "0.0.0.0"
port: int = 8000
# CORS Configuration
allowed_origins: List[str] = [
"http://localhost:3000", # Next.js dev server
"http://localhost:3100", # Website dev server
"https://withaffluent.com", # Production domain
"https://*.vercel.app", # Vercel preview domains
]
# Rate limiting
rate_limit_requests: int = 100
rate_limit_window: int = 60
# Connection pooling configuration
http_pool_connections: int = 10
http_pool_maxsize: int = 20
http_connect_timeout: int = 5
http_read_timeout: int = 30
# Authentication
api_key: str = Field(alias="FINANCIAL_API_KEY")Data models
All API responses use Pydantic models for type safety and validation:
HistoricalResponse: Historical price data with metadataCurrentResponse: Real-time price informationMultipleResponse: Batch ticker resultsTickerInfo: Company/security informationPriceRecord: Individual price data point with cents precisionErrorResponse: Standardized error format
Error handling
API endpoints error format
Standard API endpoints return consistent error responses:
{
"success": false,
"error": "Invalid ticker symbol: INVALID",
"detail": "The provided ticker symbol was not found"
}Root endpoint error format
The secured root endpoint returns:
{
"errors": [
{
"code": "not_found",
"detail": "Not found"
}
]
}HTTP status codes
200: Success400: Bad Request (invalid parameters)401: Unauthorized (missing or invalid API key)404: Not Found (secured endpoints)422: Unprocessable Entity (business logic error)429: Too Many Requests (rate limit exceeded)500: Internal Server Error
Limitations
- Rate Limits: 100 requests per minute per API key
- Batch Size: Maximum 10 symbols per multiple ticker request
- Data Source: Limited to Yahoo Finance data coverage and availability
- Market Hours: Real-time data subject to market hours and delays
- Symbol Validation: Depends on Yahoo Finance symbol recognition
- Authentication: All endpoints require valid API key except health checks