SPB Git

spb/vquant Public MIT

VibeQuant — AI-powered institutional-grade financial intelligence platform.

TypeScript 84.3% Python 11.7% JavaScript 1.6% CSS 1.5% HTML 0.7%
4.9 KB · 158 lines python
Raw Blame History
1#!/usr/bin/env python32# =============================================================================3#  VibeQuant (vquant) — AI-Powered Financial Intelligence Platform4# -----------------------------------------------------------------------------5#  File:      server/services/fmpClient.py6#7#  Author:    Simon-Pierre Boucher8#  Contact:   contact@spboucher.ai9#  Website:   https://www.spboucher.ai10#  Demo:      https://www.vquant.ai11#  License:   MIT (see LICENSE)12#13#  Copyright © 2026 Simon-Pierre Boucher. All rights reserved.14# =============================================================================1516"""17FMP API Client for Python Services18Fetches financial data directly from Financial Modeling Prep API19"""2021import os22import requests23from typing import List, Dict, Any, Optional24import sys2526# Get API key from environment27FMP_API_KEY = os.environ.get('FMP_API_KEY')28FMP_BASE_URL = 'https://financialmodelingprep.com/stable'2930def get_historical_prices(symbol: str, from_date: Optional[str] = None, to_date: Optional[str] = None) -> Dict[str, Any]:31    """32    Fetch historical stock prices from FMP API3334    Args:35        symbol: Stock ticker symbol (e.g., 'AAPL')36        from_date: Start date in YYYY-MM-DD format (optional)37        to_date: End date in YYYY-MM-DD format (optional)3839    Returns:40        Dictionary with symbol and historical price data41    """42    if not FMP_API_KEY:43        raise ValueError("FMP_API_KEY environment variable not set")4445    url = f"{FMP_BASE_URL}/historical-price-eod/full"46    params = {'apikey': FMP_API_KEY, 'symbol': symbol}4748    if from_date:49        params['from'] = from_date50    if to_date:51        params['to'] = to_date5253    try:54        response = requests.get(url, params=params, timeout=15)55        response.raise_for_status()56        data = response.json()5758        # Stable API returns flat array; wrap to match legacy format59        if isinstance(data, list):60            historical = data61        else:62            historical = data.get('historical', [])6364        # Limit to 504 most recent data points (2 years) for performance65        if len(historical) > 504:66            historical = historical[:504]6768        return {'symbol': symbol, 'historical': historical}69    except requests.exceptions.RequestException as e:70        raise Exception(f"Failed to fetch data from FMP API: {str(e)}")717273def get_stock_quote(symbol: str) -> Dict[str, Any]:74    """75    Fetch current stock quote from FMP API7677    Args:78        symbol: Stock ticker symbol (e.g., 'AAPL')7980    Returns:81        Dictionary with current stock quote data82    """83    if not FMP_API_KEY:84        raise ValueError("FMP_API_KEY environment variable not set")8586    url = f"{FMP_BASE_URL}/quote"87    params = {'apikey': FMP_API_KEY, 'symbol': symbol}8889    try:90        response = requests.get(url, params=params, timeout=15)91        response.raise_for_status()92        data = response.json()9394        if not data or len(data) == 0:95            raise ValueError(f"No quote data found for symbol {symbol}")9697        return data[0]  # Return first item98    except requests.exceptions.RequestException as e:99        raise Exception(f"Failed to fetch quote from FMP API: {str(e)}")100101102def calculate_historical_volatility(prices: List[float], annualize: bool = True) -> float:103    """104    Calculate historical volatility from price data105106    Args:107        prices: List of historical prices108        annualize: Whether to annualize the volatility (default: True, uses 252 trading days)109110    Returns:111        Annualized volatility as a decimal (e.g., 0.25 for 25%)112    """113    import numpy as np114115    if len(prices) < 2:116        raise ValueError("Need at least 2 prices to calculate volatility")117118    # Calculate daily returns119    prices_array = np.array(prices)120    returns = np.diff(prices_array) / prices_array[:-1]121122    # Calculate standard deviation of returns123    volatility = np.std(returns)124125    # Annualize if requested (252 trading days per year)126    if annualize:127        volatility = volatility * np.sqrt(252)128129    return float(volatility)130131132if __name__ == "__main__":133    # Test the module134    try:135        print("Testing FMP Client...")136137        # Test historical prices138        print("\n1. Testing get_historical_prices('AAPL')...")139        hist_data = get_historical_prices('AAPL')140        print(f"   ✓ Fetched {len(hist_data['historical'])} historical records")141142        # Test stock quote143        print("\n2. Testing get_stock_quote('AAPL')...")144        quote = get_stock_quote('AAPL')145        print(f"   ✓ Current price: ${quote['price']}")146147        # Test volatility calculation148        print("\n3. Testing calculate_historical_volatility()...")149        prices = [h['close'] for h in hist_data['historical'][:30]]  # Last 30 days150        vol = calculate_historical_volatility(prices)151        print(f"   ✓ 30-day volatility: {vol*100:.2f}%")152153        print("\n✓ All tests passed!")154155    except Exception as e:156        print(f"\n✗ Error: {e}", file=sys.stderr)157        sys.exit(1)158