| import os |
| import requests |
| import yfinance as yf |
| from dotenv import load_dotenv |
| from agents import function_tool |
| from core.logger import log_call |
| from datetime import datetime, timedelta |
|
|
| |
| load_dotenv() |
|
|
|
|
| |
| |
| |
| class FinanceTools: |
| """ |
| FinanceTools provides a set of function tools for interacting with Yahoo Finance for **Financial Data** only. |
| These tools can be used by an AI agent to fetch stock, ETF, or crypto data, |
| analyze recent market trends, market sentiments, and generate market insights. |
| """ |
|
|
| @staticmethod |
| @function_tool |
| @log_call |
| def get_summary(symbol: str, period: str = "1d", interval: str = "1h") -> str: |
| """ |
| Fetch the latest summary information and intraday price data for a given ticker. |
| Ensures recent data is retrieved by calculating start/end dates dynamically. |
| |
| Parameters: |
| ----------- |
| symbol : str |
| The ticker symbol (e.g., "AAPL", "GOOG", "BTC-USD"). |
| period : str, optional (default="1d") |
| Time range for price data. Examples: "1d", "5d", "1mo", "3mo". |
| interval : str, optional (default="1h") |
| Granularity of the data. Examples: "1m", "5m", "1h", "1d". |
| |
| Returns: |
| -------- |
| str |
| A formatted string containing: |
| - Company/ticker name |
| - Current price and change |
| - Open, High, Low prices |
| - Volume |
| - Period and interval used |
| """ |
| try: |
| ticker = yf.Ticker(symbol) |
|
|
| |
| end_date = datetime.today() |
| if period.endswith("d"): |
| days = int(period[:-1]) |
| elif period.endswith("mo"): |
| days = int(period[:-2]) * 30 |
| elif period.endswith("y"): |
| days = int(period[:-1]) * 365 |
| else: |
| days = 30 |
| start_date = end_date - timedelta(days=days) |
|
|
| |
| data = ticker.history( |
| start=start_date.strftime("%Y-%m-%d"), |
| end=end_date.strftime("%Y-%m-%d"), |
| interval=interval |
| ) |
|
|
| if data.empty: |
| return f"No data found for symbol '{symbol}'." |
|
|
| latest = data.iloc[-1] |
| current_price = round(latest["Close"], 2) |
| open_price = round(latest["Open"], 2) |
| change = round(current_price - open_price, 2) |
| pct_change = round((change / open_price) * 100, 2) |
|
|
| info = ticker.info |
| long_name = info.get("longName", symbol) |
| currency = info.get("currency", "USD") |
|
|
| formatted = [ |
| f"📈 {long_name} ({symbol})", |
| f"Current Price: {current_price} {currency}", |
| f"Change: {change} ({pct_change}%)", |
| f"Open: {open_price} | High: {round(latest['High'], 2)} | Low: {round(latest['Low'], 2)}", |
| f"Volume: {int(latest['Volume'])}", |
| f"Period: {period} | Interval: {interval}", |
| ] |
| return "\n".join(formatted) |
|
|
| except Exception as e: |
| return f"Error fetching data for '{symbol}': {e}" |
|
|
| @staticmethod |
| @function_tool |
| @log_call |
| def get_market_sentiment(symbol: str, period: str = "1mo") -> str: |
| """ |
| Analyze recent price changes and provide a simple market sentiment. |
| Uses dynamic start/end dates to ensure recent data. |
| |
| This tool computes the percentage change over the specified period and |
| classifies the sentiment as: |
| - Bullish (if price increased >2%) |
| - Bearish (if price decreased >2%) |
| - Neutral (otherwise) |
| |
| Parameters: |
| ----------- |
| symbol : str |
| The ticker symbol (e.g., "AAPL", "GOOG", "BTC-USD"). |
| period : str, optional (default="1mo") |
| Time range to analyze. Examples: "7d", "1mo", "3mo". |
| |
| Returns: |
| -------- |
| str |
| A human-readable sentiment string including percentage change. |
| """ |
| try: |
| ticker = yf.Ticker(symbol) |
|
|
| |
| end_date = datetime.today() |
| if period.endswith("d"): |
| days = int(period[:-1]) |
| elif period.endswith("mo"): |
| days = int(period[:-2]) * 30 |
| elif period.endswith("y"): |
| days = int(period[:-1]) * 365 |
| else: |
| days = 30 |
| start_date = end_date - timedelta(days=days) |
|
|
| data = ticker.history( |
| start=start_date.strftime("%Y-%m-%d"), |
| end=end_date.strftime("%Y-%m-%d") |
| ) |
|
|
| if data.empty: |
| return f"No data for {symbol}." |
|
|
| recent_change = data["Close"].iloc[-1] - data["Close"].iloc[0] |
| pct_change = (recent_change / data["Close"].iloc[0]) * 100 |
|
|
| sentiment = "Neutral" |
| if pct_change > 2: |
| sentiment = "Bullish" |
| elif pct_change < -2: |
| sentiment = "Bearish" |
|
|
| return f"{symbol} market sentiment ({period}): {sentiment} ({pct_change:.2f}% change)" |
|
|
| except Exception as e: |
| return f"Error fetching market sentiment for '{symbol}': {e}" |
|
|
| @staticmethod |
| @function_tool |
| @log_call |
| def get_history(symbol: str, period: str = "1mo") -> str: |
| """ |
| Fetch historical price data for a given ticker. |
| Ensures recent data is retrieved dynamically using start/end dates. |
| |
| Parameters: |
| ----------- |
| symbol : str |
| The ticker symbol (e.g., "AAPL", "GOOG", "BTC-USD"). |
| period : str, optional (default="1mo") |
| The length of historical data to retrieve. Examples: "1d", "5d", "1mo", "3mo", "1y", "5y". |
| |
| Returns: |
| -------- |
| str |
| A formatted string showing the last 5 rows of historical prices (Open, High, Low, Close, Volume). |
| """ |
| try: |
| ticker = yf.Ticker(symbol) |
|
|
| |
| end_date = datetime.today() |
| if period.endswith("d"): |
| days = int(period[:-1]) |
| elif period.endswith("mo"): |
| days = int(period[:-2]) * 30 |
| elif period.endswith("y"): |
| days = int(period[:-1]) * 365 |
| else: |
| days = 30 |
| start_date = end_date - timedelta(days=days) |
|
|
| data = ticker.history( |
| start=start_date.strftime("%Y-%m-%d"), |
| end=end_date.strftime("%Y-%m-%d") |
| ) |
|
|
| if data.empty: |
| return f"No historical data found for '{symbol}'." |
| return f"Historical data for {symbol} ({period}):\n{data.tail(5).to_string()}" |
|
|
| except Exception as e: |
| return f"Error fetching historical data for '{symbol}': {e}" |
|
|