logoAffluent docs

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 integration

Technology 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-here

API endpoints

Base URL

  • Local Development: http://localhost:8000
  • Production: Set via FINANCIAL_API_URL environment variable

Health check

GET /health
GET /v1/financial-data/health

Returns 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=false

Headers:

X-API-Key: your-api-key-here
Content-Type: application/json

Request 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=true

Simplified 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=AAPL

Headers:

X-API-Key: your-api-key-here
Content-Type: application/json

Request 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-31

Headers:

X-API-Key: your-api-key-here
Content-Type: application/json

Request 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 8000

The 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_URL environment variable

Deployment

Environment variables

  • FINANCIAL_API_URL: Production FastAPI service URL
  • FINANCIAL_API_KEY: API key for authenticating requests
  • FINANCIAL_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 8000

Configuration

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 metadata
  • CurrentResponse: Real-time price information
  • MultipleResponse: Batch ticker results
  • TickerInfo: Company/security information
  • PriceRecord: Individual price data point with cents precision
  • ErrorResponse: 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: Success
  • 400: 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