Files
discord-stock-bot/stock_api/finnhub_api.py
Michael Simard 45d9965638 Update stock notifications with company names and new schedule times
Add full company names to stock price notifications displayed alongside tickers. Update scheduled message times from hourly to three specific times: market open (9:30 AM ET), noon (12:00 PM ET), and market close (4:00 PM ET).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 20:18:08 -06:00

93 lines
2.9 KiB
Python

import finnhub
import logging
from typing import Optional, Dict, Any
from .base import StockAPIBase
from datetime import datetime
import pytz
logger = logging.getLogger(__name__)
class FinnhubAPI(StockAPIBase):
"""Finnhub implementation of stock price provider."""
def __init__(self, api_key: str):
"""
Initialize Finnhub API client.
Args:
api_key: Finnhub API key
"""
self.client = finnhub.Client(api_key=api_key)
self.api_key = api_key
def get_stock_price(self, ticker: str) -> Optional[Dict[str, Any]]:
"""
Retrieve stock price data from Finnhub.
Args:
ticker: Stock ticker symbol
Returns:
Dictionary with stock data or None if unavailable
"""
try:
# Get company name from company profile
company_name = None
try:
profile = self.client.company_profile2(symbol=ticker)
company_name = profile.get('name') or ticker.upper()
except Exception as e:
logger.warning(f"Could not fetch company name for {ticker}: {e}")
company_name = ticker.upper()
# Get current quote data
quote = self.client.quote(ticker)
if not quote or quote.get('c') is None or quote.get('c') == 0:
logger.warning(f"No data available for ticker: {ticker}")
return None
current_price = float(quote['c']) # Current price
previous_close = float(quote['pc']) # Previous close
if current_price == 0 or previous_close == 0:
logger.warning(f"Invalid price data for ticker: {ticker}")
return None
change_dollar = current_price - previous_close
change_percent = (change_dollar / previous_close) * 100
# Use MarketHours utility for accurate market status
from market_hours import MarketHours
market_open = MarketHours.is_market_open()
return {
'ticker': ticker.upper(),
'company_name': company_name,
'current_price': round(current_price, 2),
'previous_close': round(previous_close, 2),
'change_dollar': round(change_dollar, 2),
'change_percent': round(change_percent, 2),
'market_open': market_open
}
except Exception as e:
logger.error(f"Error fetching data for {ticker}: {e}")
return None
def is_available(self) -> bool:
"""
Check if Finnhub API is accessible.
Returns:
True if accessible, False otherwise
"""
try:
test_quote = self.client.quote("AAPL")
return test_quote is not None and test_quote.get('c') is not None
except Exception as e:
logger.error(f"Finnhub API unavailable: {e}")
return False