chatbot-app / src /chatbot /tools /yahoo_tools.py
mishrabp's picture
Upload folder using huggingface_hub
6b50ab8 verified
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 environment variables
load_dotenv()
# ============================================================
# 🔹 YAHOO FINANCE TOOLSET
# ============================================================
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)
# Calculate start and end dates based on period
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 # default 1 month
start_date = end_date - timedelta(days=days)
# Fetch recent data explicitly
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)
# Calculate start/end dynamically
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)
# Calculate start/end dynamically
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}"