| """ |
| Massive.com (APIBricks) API Endpoints |
| Provides comprehensive financial data from Massive.com API |
| """ |
|
|
| import time |
| import logging |
| import os |
| from datetime import datetime |
| from typing import Optional, List |
| from fastapi import APIRouter, Depends, Query, HTTPException |
|
|
| from api.hf_auth import verify_hf_token |
| from utils.logger import setup_logger |
|
|
| logger = setup_logger("massive_endpoints") |
|
|
| router = APIRouter(prefix="/api/massive", tags=["massive"]) |
|
|
|
|
| |
| _provider_instance = None |
|
|
| def get_provider(): |
| """Get or create Massive provider instance""" |
| global _provider_instance |
| if _provider_instance is None: |
| try: |
| from hf_data_engine.providers.massive_provider import MassiveProvider |
| api_key = os.getenv("MASSIVE_API_KEY", "PwI1oqICvx9hNMzkGTHnGzA7v2VCE7JE") |
| _provider_instance = MassiveProvider(api_key=api_key) |
| logger.info("✅ Massive.com provider initialized") |
| except Exception as e: |
| logger.error(f"❌ Failed to initialize Massive provider: {e}") |
| raise HTTPException(status_code=503, detail="Massive provider not available") |
| return _provider_instance |
|
|
|
|
| @router.get("/health") |
| async def massive_health(auth: bool = Depends(verify_hf_token)): |
| """Check Massive.com provider health""" |
| try: |
| provider = get_provider() |
| health = await provider.get_health() |
| |
| return { |
| "success": True, |
| "provider": "massive", |
| "status": health.status, |
| "latency": health.latency, |
| "last_check": health.lastCheck, |
| "error": health.errorMessage, |
| "timestamp": int(time.time() * 1000) |
| } |
| except Exception as e: |
| logger.error(f"Massive health check failed: {e}") |
| return { |
| "success": False, |
| "provider": "massive", |
| "error": str(e), |
| "timestamp": int(time.time() * 1000) |
| } |
|
|
|
|
| @router.get("/dividends") |
| async def get_dividends( |
| ticker: Optional[str] = Query(None, description="Stock ticker (e.g., AAPL)"), |
| limit: int = Query(100, ge=1, le=1000, description="Number of records"), |
| auth: bool = Depends(verify_hf_token) |
| ): |
| """ |
| Get dividend records from Massive.com API |
| |
| Example response for AAPL: |
| { |
| "ticker": "AAPL", |
| "cash_amount": 0.25, |
| "currency": "USD", |
| "declaration_date": "2024-10-31", |
| "ex_dividend_date": "2024-11-08", |
| "pay_date": "2024-11-14", |
| "record_date": "2024-11-11", |
| "dividend_type": "CD", |
| "frequency": 4 |
| } |
| |
| Args: |
| ticker: Optional stock ticker to filter |
| limit: Number of records to return |
| |
| Returns: |
| JSON with dividend records |
| """ |
| try: |
| provider = get_provider() |
| |
| logger.info(f"Fetching Massive dividends: ticker={ticker}, limit={limit}") |
| |
| |
| dividends = await provider.fetch_dividends(ticker=ticker, limit=limit) |
| |
| return { |
| "success": True, |
| "source": "massive", |
| "count": len(dividends), |
| "results": dividends, |
| "timestamp": int(time.time() * 1000) |
| } |
| |
| except Exception as e: |
| logger.error(f"Massive dividends fetch failed: {e}") |
| raise HTTPException( |
| status_code=500, |
| detail=f"Failed to fetch dividends from Massive: {str(e)}" |
| ) |
|
|
|
|
| @router.get("/splits") |
| async def get_splits( |
| ticker: Optional[str] = Query(None, description="Stock ticker (e.g., AAPL)"), |
| limit: int = Query(100, ge=1, le=1000, description="Number of records"), |
| auth: bool = Depends(verify_hf_token) |
| ): |
| """ |
| Get stock split records from Massive.com API |
| |
| Args: |
| ticker: Optional stock ticker to filter |
| limit: Number of records to return |
| |
| Returns: |
| JSON with stock split records |
| """ |
| try: |
| provider = get_provider() |
| |
| logger.info(f"Fetching Massive splits: ticker={ticker}, limit={limit}") |
| |
| |
| splits = await provider.fetch_splits(ticker=ticker, limit=limit) |
| |
| return { |
| "success": True, |
| "source": "massive", |
| "count": len(splits), |
| "results": splits, |
| "timestamp": int(time.time() * 1000) |
| } |
| |
| except Exception as e: |
| logger.error(f"Massive splits fetch failed: {e}") |
| raise HTTPException( |
| status_code=500, |
| detail=f"Failed to fetch splits from Massive: {str(e)}" |
| ) |
|
|
|
|
| @router.get("/quotes/{ticker}") |
| async def get_quotes( |
| ticker: str, |
| auth: bool = Depends(verify_hf_token) |
| ): |
| """ |
| Get real-time quotes for a ticker from Massive.com API |
| |
| Args: |
| ticker: Stock ticker (e.g., AAPL, TSLA) |
| |
| Returns: |
| JSON with quote data |
| """ |
| try: |
| provider = get_provider() |
| |
| logger.info(f"Fetching Massive quote for: {ticker}") |
| |
| |
| prices = await provider.fetch_prices([ticker]) |
| |
| if not prices: |
| raise HTTPException(status_code=404, detail=f"No quote found for {ticker}") |
| |
| price = prices[0] |
| |
| return { |
| "success": True, |
| "source": "massive", |
| "ticker": ticker.upper(), |
| "price": price.price, |
| "volume": price.volume24h, |
| "lastUpdate": price.lastUpdate, |
| "timestamp": int(time.time() * 1000) |
| } |
| |
| except HTTPException: |
| raise |
| except Exception as e: |
| logger.error(f"Massive quote fetch failed: {e}") |
| raise HTTPException( |
| status_code=500, |
| detail=f"Failed to fetch quote from Massive: {str(e)}" |
| ) |
|
|
|
|
| @router.get("/trades/{ticker}") |
| async def get_trades( |
| ticker: str, |
| limit: int = Query(100, ge=1, le=5000, description="Number of trades"), |
| auth: bool = Depends(verify_hf_token) |
| ): |
| """ |
| Get recent trades for a ticker from Massive.com API |
| |
| Args: |
| ticker: Stock ticker (e.g., AAPL, TSLA) |
| limit: Number of trades to return |
| |
| Returns: |
| JSON with trade data |
| """ |
| try: |
| provider = get_provider() |
| |
| logger.info(f"Fetching Massive trades: {ticker} x{limit}") |
| |
| |
| trades = await provider.fetch_trades(ticker, limit=limit) |
| |
| return { |
| "success": True, |
| "source": "massive", |
| "ticker": ticker.upper(), |
| "count": len(trades), |
| "trades": trades, |
| "timestamp": int(time.time() * 1000) |
| } |
| |
| except Exception as e: |
| logger.error(f"Massive trades fetch failed: {e}") |
| raise HTTPException( |
| status_code=500, |
| detail=f"Failed to fetch trades from Massive: {str(e)}" |
| ) |
|
|
|
|
| @router.get("/aggregates/{ticker}") |
| async def get_aggregates( |
| ticker: str, |
| interval: str = Query("1h", description="Time interval (1m, 5m, 15m, 1h, 4h, 1d, 1w)"), |
| limit: int = Query(100, ge=1, le=5000, description="Number of candles"), |
| auth: bool = Depends(verify_hf_token) |
| ): |
| """ |
| Get OHLCV aggregates (candlestick data) from Massive.com API |
| |
| Args: |
| ticker: Stock ticker (e.g., AAPL, TSLA) |
| interval: Time interval (1m, 5m, 15m, 1h, 4h, 1d, 1w) |
| limit: Number of candles to return |
| |
| Returns: |
| JSON with OHLCV data |
| """ |
| try: |
| provider = get_provider() |
| |
| logger.info(f"Fetching Massive aggregates: {ticker} {interval} x{limit}") |
| |
| |
| ohlcv_data = await provider.fetch_ohlcv(ticker, interval, limit) |
| |
| return { |
| "success": True, |
| "source": "massive", |
| "ticker": ticker.upper(), |
| "interval": interval, |
| "count": len(ohlcv_data), |
| "data": [ |
| { |
| "timestamp": candle.timestamp, |
| "open": candle.open, |
| "high": candle.high, |
| "low": candle.low, |
| "close": candle.close, |
| "volume": candle.volume |
| } |
| for candle in ohlcv_data |
| ], |
| "timestamp": int(time.time() * 1000) |
| } |
| |
| except Exception as e: |
| logger.error(f"Massive aggregates fetch failed: {e}") |
| raise HTTPException( |
| status_code=500, |
| detail=f"Failed to fetch aggregates from Massive: {str(e)}" |
| ) |
|
|
|
|
| @router.get("/ticker/{ticker}") |
| async def get_ticker_details( |
| ticker: str, |
| auth: bool = Depends(verify_hf_token) |
| ): |
| """ |
| Get detailed information about a ticker from Massive.com API |
| |
| Args: |
| ticker: Stock ticker (e.g., AAPL, TSLA) |
| |
| Returns: |
| JSON with ticker details |
| """ |
| try: |
| provider = get_provider() |
| |
| logger.info(f"Fetching Massive ticker details for: {ticker}") |
| |
| |
| details = await provider.fetch_ticker_details(ticker) |
| |
| return { |
| "success": True, |
| "source": "massive", |
| "ticker": ticker.upper(), |
| "details": details, |
| "timestamp": int(time.time() * 1000) |
| } |
| |
| except Exception as e: |
| logger.error(f"Massive ticker details fetch failed: {e}") |
| raise HTTPException( |
| status_code=500, |
| detail=f"Failed to fetch ticker details from Massive: {str(e)}" |
| ) |
|
|
|
|
| @router.get("/market-status") |
| async def get_market_status(auth: bool = Depends(verify_hf_token)): |
| """ |
| Get current market status from Massive.com API |
| |
| Returns: |
| JSON with market status information |
| """ |
| try: |
| provider = get_provider() |
| |
| logger.info("Fetching Massive market status") |
| |
| |
| status_data = await provider.fetch_market_status() |
| |
| return { |
| "success": True, |
| "source": "massive", |
| "data": status_data, |
| "timestamp": int(time.time() * 1000) |
| } |
| |
| except Exception as e: |
| logger.error(f"Massive market status fetch failed: {e}") |
| raise HTTPException( |
| status_code=500, |
| detail=f"Failed to fetch market status from Massive: {str(e)}" |
| ) |
|
|