Spaces:
Runtime error
Runtime error
| #!/usr/bin/env python | |
| # coding=utf-8 | |
| # Copyright 2024 The Footscray Coding Collective. All rights reserved. | |
| """ | |
| Financial Data and Analysis Tools | |
| -------------------------------------- | |
| A comprehensive suite of tools for retrieving financial market data through the Alpha Vantage API. | |
| These tools enable accessing real-time stock quotes, company fundamentals, financial statements, | |
| price history, market news, and sentiment analysis with proper error handling and caching. | |
| The Alpha Vantage tools follow the Zhou Protocol for financial data retrieval: | |
| - Singleton pattern for API client management | |
| - Comprehensive error handling with failed request tracking | |
| - In-memory request caching to minimize API usage | |
| - Detailed docstrings with usage examples | |
| Key Financial Tools: | |
| - search_symbols: Find ticker symbols for companies by keywords | |
| - get_stock_quote_data: Real-time stock quote information | |
| - get_company_overview_data: Company profiles and fundamentals | |
| - get_earnings_data: Quarterly and annual earnings information | |
| - get_income_statement_data: Income statement analysis | |
| - get_balance_sheet_data: Balance sheet information | |
| - get_cash_flow_data: Cash flow statement analysis | |
| - get_time_series_daily: Historical price and volume data | |
| - get_market_news_sentiment: News and sentiment analysis | |
| Financial Analysis Tools: | |
| - FinancialCalculatorTool: Calculate financial metrics (growth rates, margins, CAGR) | |
| - DataVisualizationTool: Generate visual representations of financial data | |
| - TrendAnalysisTool: Perform year-over-year trend analysis on financial metrics | |
| """ | |
| import io | |
| import logging | |
| import os | |
| import traceback | |
| from typing import Any, Dict, Optional, Set | |
| # Third-party imports in alphabetical order with dotenv first | |
| try: | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| except ImportError: | |
| pass | |
| import matplotlib.pyplot as plt # Plot the chart | |
| import pandas as pd # Store dataframe | |
| import requests | |
| from smolagents import Tool, tool | |
| class AlphaVantageClient: | |
| """Centralized client for Alpha Vantage API requests with caching and error handling.""" | |
| def __init__(self): | |
| """Initialize the client with empty caches.""" | |
| self._api_key: Optional[str] = None | |
| self._failed_requests: Set[str] = set() | |
| self._data_cache: Dict[str, Dict[str, Any]] = {} | |
| def get_api_key(self) -> str: | |
| """ | |
| Get Alpha Vantage API key from environment or cache. | |
| Returns: | |
| API key string or error message | |
| """ | |
| if self._api_key: | |
| return self._api_key | |
| api_key = os.getenv("ALPHA_VANTAGE_API_KEY") | |
| if not api_key: | |
| return "Error: No API key found. Set ALPHA_VANTAGE_API_KEY in your environment." | |
| self._api_key = api_key | |
| return api_key | |
| def make_request(self, function: str, symbol: str, **params: Any) -> Dict[str, Any]: | |
| """ | |
| Make a request to Alpha Vantage API with error handling and caching. | |
| Args: | |
| function (str): API function name | |
| symbol (str): Stock symbol | |
| **params (Any): Additional parameters for the request, excluding 'function' and 'symbol' | |
| Returns: | |
| Dict[str, Any]: Raw JSON response data | |
| """ | |
| # Validate params | |
| if "function" in params or "symbol" in params: | |
| raise ValueError("function and symbol should not be included in params") | |
| # Generate cache key | |
| cache_key = f"{function}:{symbol}:{hash(frozenset(params.items()))}" | |
| # Return cached data if available | |
| if cache_key in self._data_cache: | |
| return self._data_cache[cache_key] | |
| # Check if this request has failed before | |
| if cache_key in self._failed_requests: | |
| return { | |
| "Error": f"Previously failed request for {symbol} with function {function}" | |
| } | |
| # Get API key | |
| api_key = self.get_api_key() | |
| if api_key.startswith("Error:"): | |
| return {"Error Message": api_key} | |
| # Build request URL and parameters | |
| url = "https://www.alphavantage.co/query" | |
| request_params = { | |
| "function": function, | |
| "symbol": symbol, | |
| "apikey": api_key, | |
| **params, | |
| } | |
| try: | |
| # Make request with timeout for responsiveness | |
| response = requests.get(url, params=request_params, timeout=10) | |
| response.raise_for_status() | |
| data = response.json() | |
| # Check for API errors | |
| if "Error Message" in data or "Information" in data or not data: | |
| self._failed_requests.add(cache_key) | |
| return data | |
| # Cache successful response | |
| self._data_cache[cache_key] = data | |
| return data | |
| except requests.RequestException as e: | |
| error_data = {"Error Message": f"API request failed: {str(e)}"} | |
| self._failed_requests.add(cache_key) | |
| return error_data | |
| except ValueError as e: | |
| error_data = {"Error Message": f"Failed to parse response: {str(e)}"} | |
| self._failed_requests.add(cache_key) | |
| return error_data | |
| def clear_cache( | |
| self, function: Optional[str] = None, symbol: Optional[str] = None | |
| ) -> None: | |
| """ | |
| Clear the data cache, optionally filtering by function and/or symbol. | |
| Args: | |
| function: Optional function name to filter cache entries | |
| symbol: Optional symbol to filter cache entries | |
| """ | |
| if not function and not symbol: | |
| self._data_cache.clear() | |
| return | |
| keys_to_remove = [] | |
| for key in self._data_cache: | |
| parts = key.split(":") | |
| if function and parts[0] != function: | |
| continue | |
| if symbol and parts[1] != symbol: | |
| continue | |
| keys_to_remove.append(key) | |
| for key in keys_to_remove: | |
| del self._data_cache[key] | |
| # Create a singleton instance of the client | |
| _client = AlphaVantageClient() | |
| def get_stock_quote_data(symbol: str) -> Dict[str, Any]: | |
| """ | |
| Retrieve raw real-time stock quote information from Alpha Vantage. | |
| This tool fetches current market data for a specified stock ticker, | |
| returning the raw data for custom processing and analysis. | |
| Args: | |
| symbol: The stock ticker symbol (e.g., 'AAPL', 'MSFT', 'IBM') | |
| Returns: | |
| Raw JSON data containing: | |
| - Global Quote object with price, volume, and trading information | |
| - Error information if the request failed | |
| Example: | |
| ```python | |
| # Get raw quote data | |
| data = get_stock_quote_data("MSFT") | |
| # Extract price | |
| if "Global Quote" in data: | |
| quote = data["Global Quote"] | |
| price = float(quote.get("05. price", 0)) | |
| change = float(quote.get("09. change", 0)) | |
| print(f"MSFT: ${price:.2f} ({change:+.2f})") | |
| ``` | |
| """ | |
| return _client.make_request("GLOBAL_QUOTE", symbol) | |
| def get_company_overview_data(symbol: str) -> Dict[str, Any]: | |
| """ | |
| Retrieve raw company information and metrics from Alpha Vantage. | |
| This tool provides comprehensive information about a company, returning | |
| raw data for custom analysis and presentation. | |
| Args: | |
| symbol: The stock ticker symbol (e.g., 'AAPL', 'MSFT', 'IBM') | |
| Returns: | |
| Raw JSON data containing: | |
| - Company profile (name, sector, industry) | |
| - Financial metrics (market cap, P/E ratio, etc.) | |
| - Performance indicators (ROE, ROA, etc.) | |
| - Company description | |
| - Error information if the request failed | |
| Example: | |
| ```python | |
| # Get company data | |
| data = get_company_overview_data("AAPL") | |
| # Create custom analysis | |
| if "Sector" in data: | |
| sector = data.get("Sector") | |
| market_cap = float(data.get("MarketCapitalization", 0)) | |
| pe_ratio = float(data.get("PERatio", 0)) | |
| print(f"AAPL is in the {sector} sector") | |
| print(f"Market Cap: ${market_cap/1e9:.2f}B") | |
| print(f"P/E Ratio: {pe_ratio:.2f}") | |
| ``` | |
| """ | |
| return _client.make_request("OVERVIEW", symbol) | |
| def get_earnings_data(symbol: str) -> Dict[str, Any]: | |
| """ | |
| Retrieve raw earnings data for a company from Alpha Vantage. | |
| This tool fetches quarterly and annual earnings data, returning | |
| raw information for custom analysis and trend evaluation. | |
| Args: | |
| symbol: The stock ticker symbol (e.g., 'AAPL', 'MSFT', 'IBM') | |
| Returns: | |
| Raw JSON data containing: | |
| - quarterlyEarnings array with fiscal dates, reported EPS, and surprises | |
| - annualEarnings array with yearly EPS figures | |
| - Error information if the request failed | |
| Example: | |
| ```python | |
| # Get earnings data | |
| data = get_earnings_data("MSFT") | |
| # Analyze earnings surprises | |
| if "quarterlyEarnings" in data: | |
| quarterly = data["quarterlyEarnings"] | |
| # Calculate average earnings surprise percentage | |
| surprises = [float(q.get("surprisePercentage", 0)) for q in quarterly[:4]] | |
| avg_surprise = sum(surprises) / len(surprises) | |
| print(f"Average earnings surprise (last 4Q): {avg_surprise:.2f}%") | |
| # Find biggest positive surprise | |
| max_surprise = max(surprises) | |
| print(f"Largest positive surprise: {max_surprise:.2f}%") | |
| ``` | |
| """ | |
| return _client.make_request("EARNINGS", symbol) | |
| def get_income_statement_data(symbol: str) -> Dict[str, Any]: | |
| """ | |
| Retrieve raw income statement data for a company from Alpha Vantage. | |
| This tool fetches annual and quarterly income statements, returning | |
| raw financial data for custom analysis and profit trend evaluation. | |
| Args: | |
| symbol: The stock ticker symbol (e.g., 'AAPL', 'MSFT', 'IBM') | |
| Returns: | |
| Raw JSON data containing: | |
| - annualReports array with yearly income statements | |
| - quarterlyReports array with quarterly income statements | |
| - Error information if the request failed | |
| Example: | |
| ```python | |
| # Get income statement data | |
| data = get_income_statement_data("AAPL") | |
| # Analyze profitability trends | |
| if "annualReports" in data and len(data["annualReports"]) >= 3: | |
| reports = data["annualReports"][:3] # Last 3 years | |
| # Extract revenue and profit | |
| revenues = [float(r.get("totalRevenue", 0)) for r in reports] | |
| net_incomes = [float(r.get("netIncome", 0)) for r in reports] | |
| # Calculate profit margins | |
| margins = [ni/rev*100 if rev else 0 for ni, rev in zip(net_incomes, revenues)] | |
| for i, margin in enumerate(margins): | |
| year = reports[i].get("fiscalDateEnding", "Unknown") | |
| print(f"{year}: Profit margin = {margin:.2f}%") | |
| ``` | |
| """ | |
| return _client.make_request("INCOME_STATEMENT", symbol) | |
| def get_balance_sheet_data(symbol: str) -> Dict[str, Any]: | |
| """ | |
| Retrieve raw balance sheet data for a company from Alpha Vantage. | |
| This tool fetches annual and quarterly balance sheets, returning | |
| raw financial data for custom analysis of a company's financial position. | |
| Args: | |
| symbol: The stock ticker symbol (e.g., 'AAPL', 'MSFT', 'IBM') | |
| Returns: | |
| Raw JSON data containing: | |
| - annualReports array with yearly balance sheets | |
| - quarterlyReports array with quarterly balance sheets | |
| - Error information if the request failed | |
| Example: | |
| ```python | |
| # Get balance sheet data | |
| data = get_balance_sheet_data("MSFT") | |
| # Calculate debt-to-equity ratio | |
| if "annualReports" in data and data["annualReports"]: | |
| latest = data["annualReports"][0] | |
| total_debt = float(latest.get("shortTermDebt", 0)) + float(latest.get("longTermDebt", 0)) | |
| equity = float(latest.get("totalShareholderEquity", 0)) | |
| if equity: | |
| debt_to_equity = total_debt / equity | |
| print(f"Debt-to-Equity Ratio: {debt_to_equity:.2f}") | |
| # Calculate current ratio | |
| current_assets = float(latest.get("totalCurrentAssets", 0)) | |
| current_liabilities = float(latest.get("totalCurrentLiabilities", 0)) | |
| if current_liabilities: | |
| current_ratio = current_assets / current_liabilities | |
| print(f"Current Ratio: {current_ratio:.2f}") | |
| ``` | |
| """ | |
| return _client.make_request("BALANCE_SHEET", symbol) | |
| def get_cash_flow_data(symbol: str) -> Dict[str, Any]: | |
| """ | |
| Retrieve raw cash flow statement data for a company from Alpha Vantage. | |
| This tool fetches annual and quarterly cash flow statements, returning | |
| raw financial data for analyzing a company's cash generation and usage. | |
| Args: | |
| symbol: The stock ticker symbol (e.g., 'AAPL', 'MSFT', 'IBM') | |
| Returns: | |
| Raw JSON data containing: | |
| - annualReports array with yearly cash flow statements | |
| - quarterlyReports array with quarterly cash flow statements | |
| - Error information if the request failed | |
| Example: | |
| ```python | |
| # Get cash flow data | |
| data = get_cash_flow_data("AMZN") | |
| # Analyze free cash flow | |
| if "annualReports" in data and data["annualReports"]: | |
| reports = data["annualReports"][:3] # Last 3 years | |
| for report in reports: | |
| year = report.get("fiscalDateEnding", "Unknown") | |
| operating_cf = float(report.get("operatingCashflow", 0)) | |
| capex = float(report.get("capitalExpenditures", 0)) | |
| # Free cash flow = Operating cash flow - Capital expenditures | |
| free_cf = operating_cf - abs(capex) | |
| print(f"{year}: Free Cash Flow = ${free_cf/1e9:.2f}B") | |
| ``` | |
| """ | |
| return _client.make_request("CASH_FLOW", symbol) | |
| def get_time_series_daily(symbol: str, outputsize: str = "compact") -> Dict[str, Any]: | |
| """ | |
| Retrieve daily time series stock price data from Alpha Vantage. | |
| This tool fetches historical daily OHLCV (Open, High, Low, Close, Volume) data | |
| for specified ticker symbols, supporting both compact (100 data points) and | |
| full (20+ years) history. | |
| Args: | |
| symbol: The stock ticker symbol (e.g., 'AAPL', 'MSFT', 'IBM') | |
| outputsize: Data size, either 'compact' (last 100 points) or 'full' (20+ years) | |
| Returns: | |
| Raw JSON data containing: | |
| - "Meta Data" object with information about the data series | |
| - "Time Series (Daily)" object with date-keyed OHLCV data points | |
| - Error information if the request failed | |
| Example: | |
| ```python | |
| # Get daily prices (compact = last 100 days) | |
| data = get_time_series_daily("TSLA") | |
| # Calculate moving averages | |
| if "Time Series (Daily)" in data: | |
| time_series = data["Time Series (Daily)"] | |
| dates = sorted(time_series.keys()) | |
| # Extract closing prices | |
| prices = [float(time_series[date]["4. close"]) for date in dates] | |
| # Calculate 20-day moving average | |
| if len(prices) >= 20: | |
| ma_20 = sum(prices[-20:]) / 20 | |
| print(f"20-day Moving Average: ${ma_20:.2f}") | |
| # Get latest price | |
| latest_price = prices[-1] | |
| print(f"Latest price: ${latest_price:.2f}") | |
| # Compare to moving average | |
| diff_pct = (latest_price / ma_20 - 1) * 100 | |
| print(f"Price is {diff_pct:+.2f}% from 20-day MA") | |
| ``` | |
| """ | |
| return _client.make_request("TIME_SERIES_DAILY", symbol, outputsize=outputsize) | |
| # Ensure that the default value IS specified | |
| def search_symbols(keywords: str) -> Dict[str, Any]: | |
| """ | |
| [FINANCIAL DISCOVERY] Search for stock symbols matching the provided keywords. | |
| WHEN TO USE: ALWAYS use this tool FIRST when you don't know the exact stock symbol for a company. | |
| This tool helps find relevant ticker symbols when you don't know the exact symbol, | |
| matching companies by name, description, or partial symbols. | |
| Args: | |
| keywords: Search term (e.g., 'microsoft', 'tech', 'MSFT') | |
| Returns: | |
| Raw JSON data containing: | |
| - bestMatches array with matching companies (symbol, name, type, region) | |
| - Error information if the request failed | |
| Example: | |
| ```python | |
| # Search for companies related to "electric vehicles" | |
| results = search_symbols("electric vehicles") | |
| # Print matched symbols and names | |
| if "bestMatches" in results: | |
| matches = results["bestMatches"] | |
| print(f"Found {len(matches)} matches:") | |
| for match in matches: | |
| symbol = match.get("1. symbol", "") | |
| name = match.get("2. name", "") | |
| market = match.get("4. region", "") | |
| print(f"{symbol} - {name} ({market})") | |
| ``` | |
| """ | |
| return _client.make_request("SYMBOL_SEARCH", "", keywords=keywords) | |
| def clear_api_cache() -> str: | |
| """ | |
| Clear all cached API data to force fresh requests. | |
| Returns: | |
| Confirmation message | |
| """ | |
| _client._data_cache.clear() | |
| return "API cache cleared successfully." | |
| def get_market_news_sentiment( | |
| tickers: Optional[str] = None, | |
| topics: Optional[str] = None, | |
| time_from: Optional[str] = None, | |
| time_to: Optional[str] = None, | |
| sort: str = "LATEST", | |
| limit: int = 50, | |
| ) -> Dict[str, Any]: | |
| """ | |
| Retrieve market news and sentiment data from Alpha Vantage. | |
| This tool fetches live and historical market news with sentiment analysis from premier | |
| news outlets worldwide, covering stocks, cryptocurrencies, forex, and various market topics. | |
| Args: | |
| tickers: Optional comma-separated list of symbols (e.g., 'AAPL,MSFT' or 'COIN,CRYPTO:BTC,FOREX:USD') | |
| topics: Optional comma-separated list of news topics (e.g., 'technology,ipo') | |
| Available topics: blockchain, earnings, ipo, mergers_and_acquisitions, financial_markets, | |
| economy_fiscal, economy_monetary, economy_macro, energy_transportation, finance, | |
| life_sciences, manufacturing, real_estate, retail_wholesale, technology | |
| time_from: Optional start time in YYYYMMDDTHHMM format (e.g., '20220410T0130') | |
| time_to: Optional end time in YYYYMMDDTHHMM format | |
| sort: Sorting order - 'LATEST' (default), 'EARLIEST', or 'RELEVANCE' | |
| limit: Maximum number of results to return (default: 50, max: 1000) | |
| Returns: | |
| Raw JSON data containing: | |
| - feed: Array of news articles with title, summary, url, time_published, authors, and more | |
| - sentiment scores for each article (if available) | |
| - Error information if the request failed | |
| Example: | |
| ```python | |
| # Get latest news about Apple | |
| apple_news = get_market_news_sentiment(tickers="AAPL") | |
| # Get news articles at the intersection of technology and IPOs | |
| tech_ipo_news = get_market_news_sentiment(topics="technology,ipo") | |
| # Get Bitcoin news from a specific time period | |
| btc_news = get_market_news_sentiment( | |
| tickers="CRYPTO:BTC", | |
| time_from="20230101T0000", | |
| time_to="20230201T0000" | |
| ) | |
| # Process the sentiment data | |
| if "feed" in apple_news: | |
| for article in apple_news["feed"]: | |
| title = article.get("title", "No title") | |
| sentiment = article.get("overall_sentiment_score", "N/A") | |
| print(f"Article: {title} | Sentiment: {sentiment}") | |
| ``` | |
| """ | |
| params = { | |
| "function": "NEWS_SENTIMENT", | |
| } | |
| # Add optional parameters | |
| if tickers: | |
| params["tickers"] = tickers | |
| if topics: | |
| params["topics"] = topics | |
| if time_from: | |
| params["time_from"] = time_from | |
| if time_to: | |
| params["time_to"] = time_to | |
| if sort: | |
| params["sort"] = sort | |
| if limit: | |
| params["limit"] = limit | |
| return _client.make_request("NEWS_SENTIMENT", "", **params) | |
| """Example functions to be used in the tools and called by the agent""" | |
| class FinancialCalculatorTool(Tool): | |
| """ | |
| Performs various financial calculations, given structured data from a table. | |
| Useful for calculating growth rates, financial ratios, and other key metrics. | |
| The tool can directly perform calculations on the data for numerical answers. | |
| """ | |
| name = "financial_calculator" | |
| description = """ | |
| Performs various financial calculations, given structured data from a table. | |
| Useful for calculating growth rates, financial ratios, and other key metrics. | |
| The tool can directly perform calculations on the data for numerical answers. | |
| Input: | |
| - `data` (str): A string representing table data (e.g., CSV, markdown table). | |
| - `calculation_type` (str): The type of calculation to perform, such as 'growth_rate', 'profit_margin', 'debt_to_equity'. | |
| - `year1`, `year2`, `metric` (str): Parameters for "growth", e.g., "2020", "2021", "Revenue". | |
| - `year`, `revenue`, `netIncome`(str): Parameters for 'Profit_Margin', e.g. "2023", "10000", "1000". | |
| - `year`, `totalDebt`, `totalEquity` (str): Parameters for 'Debt_To_Equity', e.g. "2023", "5000", "10000". | |
| - `startYear`, `endYear`, `metric"(str): Parametes for "CAGR", e.g. "2020", "2025", "Revenue" | |
| Output: | |
| - `calculation_result` (str): The result of the financial calculation as a string, to two decimals points. | |
| This ensures the agent can understand and utilize the output effectively. | |
| """ | |
| inputs = { | |
| "data": { | |
| "type": "string", | |
| "description": "A string representing table data. Must be in CSV format with a header row.", | |
| }, | |
| "calculation_type": { | |
| "type": "string", | |
| "description": "The type of calculation to perform. Must be one of the following exactly: 'growth_rate', 'profit_margin', 'debt_to_equity', 'CAGR'.", | |
| }, | |
| "year1": { | |
| "type": "string", | |
| "description": "Year 1 for growth rate calculation, as a string.", | |
| "nullable": True, | |
| }, | |
| "metric": { | |
| "type": "string", | |
| "description": "Valid CSV Header to compare, for growth. MUST correspond to the appropriate header in dataset.", | |
| "nullable": True, | |
| }, | |
| "year2": { | |
| "type": "string", | |
| "description": "Year 2 for growth rate calculation, as a string. Make sure that is a valid CSV Header.", | |
| "nullable": True, | |
| }, | |
| "revenue": { | |
| "type": "string", | |
| "description": "Revenue for the fiscal year profit calculation (as a string).", | |
| "nullable": True, | |
| }, | |
| "netIncome": { | |
| "type": "string", | |
| "description": "Must be Valid Valid Net income for the fiscal year profit margin calculation, in string format", | |
| "nullable": True, | |
| }, | |
| "endYear": { | |
| "type": "string", | |
| "description": "Year 2 string for the CAGR function", | |
| "nullable": True, | |
| }, | |
| "year": { | |
| "type": "string", | |
| "description": "Valid Year", | |
| "nullable": True, | |
| }, | |
| "startYear": { | |
| "type": "string", | |
| "description": "Year 1, string for the CAGR function", | |
| "nullable": True, | |
| }, | |
| "totalAssets": { | |
| "type": "string", | |
| "description": "The Total assets data in string format", | |
| "nullable": True, | |
| }, | |
| "totalDebt": { | |
| "type": "string", | |
| "description": "The total debt data in string.", | |
| "nullable": True, | |
| }, | |
| "totalEquity": { | |
| "type": "string", | |
| "description": "The Total Shareholders Equity in string format", | |
| "nullable": True, | |
| }, | |
| } | |
| output_type = "string" | |
| def forward( | |
| self, | |
| data: str, # A string representing the data. Must be a valid CSV | |
| calculation_type: str, # type of calculation you'd like to do with the data | |
| year1: Optional[str] = None, # Year1, all string types | |
| metric: Optional[str] = None, # metric, all string types | |
| year2: Optional[str] = None, # Year2, all string types | |
| revenue: Optional[str] = None, # Revenue, all string types | |
| netIncome: Optional[str] = None, # Net income, all string types | |
| endYear: Optional[str] = None, # Year 2 string for the CAGR function | |
| year: Optional[str] = None, # Valid Year | |
| startYear: Optional[str] = None, # Year 1, string for the CAGR function | |
| totalAssets: Optional[str] = None, # The Total assets data in string format | |
| totalDebt: Optional[str] = None, # The total debt data in string. | |
| totalEquity: Optional[ | |
| str | |
| ] = None, # The Total Shareholders Equity in string format | |
| ) -> str: | |
| """ | |
| Performs the specified financial calculation. | |
| Args: | |
| data: A string representing the dat. Must be a valid CSV | |
| calculation_type: type of calculation you'd like to do with the data | |
| year1: Year1, all string types | |
| year2: Year2, all string types | |
| metric: metric, all string types | |
| Returns: | |
| A string representing the result of the calculation. If an error occurs, the string will start with "Error: " | |
| """ | |
| try: | |
| df = pd.read_csv(io.StringIO(data)) | |
| except Exception as e: | |
| return f"Error reading data: {e}. Ensure that the input provided is a valid csv, AND has headers (no comments or empty rows)." | |
| try: | |
| if calculation_type == "growth_rate": | |
| if not (year1 and year2 and metric): | |
| return "Error: Missing year1, year2, or metric for growth_rate calculation." | |
| value1 = df.loc[df["Year"] == year1][metric].values[0] | |
| value2 = df.loc[df["Year"] == year2][metric].values[0] | |
| growth_rate = ((value2 - value1) / value1) * 100 | |
| return f"{growth_rate:.2f}%" | |
| elif calculation_type == "profit_margin": | |
| if not year or not revenue or not netIncome: | |
| return "Error: Missing year for profit_margin calculation" | |
| # revenue = df.loc[df['Year'] == year]['Revenue'].values[0] # Replace with your actual data columns | |
| # net_income = df.loc[df['Year'] == year]['Net Income'].values[0] # This can also be EBIT or operating profit or whatever | |
| profit_margin = (float(netIncome) / float(revenue)) * 100 | |
| return f"{profit_margin:.2f}%" | |
| elif calculation_type == "debt_to_equity": | |
| if not year or not totalDebt or not totalEquity: | |
| return "Error: Missing year for debt_to_equity calculation" | |
| # total_debt = df.loc[df['Year'] == year]['Total Debt'].values[0] # Could be short term or long term | |
| # total_equity = df.loc[df['Year'] == year]['Total Equity'].values[0] # Could be share holders equity? | |
| debt_to_equity = float(totalDebt) / float(totalEquity) | |
| return f"{debt_to_equity:.2f}" | |
| elif calculation_type == "CAGR": | |
| if not (startYear and endYear and metric): | |
| return "Error: Missing startYear, endYear, or metric for CAGR calculation." | |
| try: # Make the CSV valid | |
| start_value = float( | |
| df[df["Year"] == startYear][metric].values[0] | |
| ) # float(start_value) #df[df.columns[1]] #["Start Value"].values[0] | |
| end_value = float( | |
| df[df["Year"] == endYear][metric].values[0] | |
| ) # float(end_value) # float(raw[0]) #df[df.columns[1]] #["End Value"].values[0]# CSV | |
| except Exception as exception: | |
| return f"start value {df[df['Year'] == startYear][metric].values[0]} endvalue {df[df['Year'] == endYear][metric].values[0]}. start and end values are not valid headers! Ensure CSV Headers are there, and they're valid. OriginalException{exception}" | |
| try: # check to confirm the calculations work by converting them to float | |
| n = int(endYear) - int(startYear) | |
| cagr = (end_value / start_value) ** (1 / n) - 1 | |
| return f"{cagr:.2f}" # f"EndValue {endYear2:.2f} Startvalue {startYear2:.2f}" | |
| except Exception: | |
| return f"start year {startYear} end year {endYear} Startvalue {start_value} end value {end_value}. Year calcs invalid! Invalid CSV" | |
| else: | |
| return f"Error: Unsupported Calculation Type: {calculation_type}. Consider growth_rate, profit_margin, debt_to_equity, CAGR." | |
| except Exception as e: | |
| return f"Error performing calculation: {e}" | |
| class DataVisualizationTool(Tool): | |
| """ | |
| Generates visualizations (charts, graphs) from structured data to help identify trends. | |
| Be thoughtful about the data AND type of graph: they must match. | |
| You CANNOT import things other than csv, so make sure to follow the instructions. | |
| """ | |
| name = "data_visualization" | |
| description = """ | |
| Generates visualizations (charts, graphs) from structured data to help identify trends. Be thoughtful about the data AND type of graph: they must match. You CANNOT import things other than csv, so make sure to follow the instructions. | |
| Input: | |
| - `data` (str): A valid CSV string, that represents values to graph: MUST start with a HEADER row, then be followed by valid csv syntax | |
| - `chart_type` (str): The type of chart/graph to generate, MUST be one of: 'line', 'bar', 'scatter'. | |
| - `x_axis_label` (str): Label for the x axis. If unsure, set as "years" | |
| - `y_axis_label` (str): Label for the y axis. If unsure, set as "net income" | |
| Output: | |
| - `plot_string` (str): A verbal description of the plot, especially its overall trend. A short trend is sufficient. | |
| """ | |
| inputs = { | |
| "data": { | |
| "type": "string", | |
| "description": "CSV data representing a time series: Start this with headers followed by values!!", | |
| }, | |
| "chart_type": { | |
| "type": "string", | |
| "description": "Type of chart to generate (e.g., MUST be one of 'line', 'bar', 'scatter').", | |
| }, | |
| "x_axis_label": { | |
| "type": "string", | |
| "description": "Label of x-axis, such as 'years' or 'quarters'", | |
| }, | |
| "y_axis_label": { | |
| "type": "string", | |
| "description": "Label of y-axis, such as 'net income' or 'revenue'", | |
| }, | |
| } | |
| output_type = "string" | |
| def forward( | |
| self, data: str, chart_type: str, x_axis_label: str, y_axis_label: str | |
| ) -> str: | |
| """ | |
| Perform chart visuals | |
| Args: | |
| data (str): string CSV in the correct format | |
| chart_type (str): one of scatter, line, bar | |
| x_axis_label (str): label | |
| y_axis_label (str): label | |
| Returns: | |
| str: A verbal description of the plot, especially its overall trend. | |
| """ | |
| if not data: | |
| return "Error: No data provided." | |
| if not chart_type: | |
| return "Error: No chart." | |
| if not x_axis_label: | |
| return "Error: No x-axis label provided." | |
| if not y_axis_label: | |
| return "Error: No y-axis label provided." | |
| try: | |
| df = pd.read_csv(io.StringIO(data)) | |
| except Exception as e: | |
| return f"Problem building data {data}: {e}" | |
| if len(df.columns) < 2: | |
| return "Error: Data must have at least two columns." | |
| try: | |
| plt.figure(figsize=(10, 6)) # Adjust the figure size for better readability | |
| if chart_type == "line": | |
| plt.xlabel(x_axis_label) | |
| plt.ylabel(y_axis_label) | |
| plt.plot( | |
| df[df.columns[0]], df[df.columns[1]] | |
| ) # [df.columns[0]], df[df.columns[1]] | |
| elif chart_type == "bar": | |
| plt.ylabel(y_axis_label) | |
| plt.xlabel(x_axis_label) | |
| plt.bar(df[df.columns[0]], df[df.columns[1]]) # .values[0] | |
| elif chart_type == "scatter": | |
| plt.ylabel(y_axis_label) | |
| plt.xlabel(x_axis_label) | |
| plt.scatter(df[df.columns[0]], df[df.columns[1]]) # .values[0] | |
| else: | |
| raise ValueError(f"Unsupported chart type: {chart_type}") | |
| chart_summary = f"Chart generated, which shows the {chart_type} of {df.columns[1]} with respect to {df.columns[0]}. " | |
| plt.title(y_axis_label + " vs. " + x_axis_label) # What we're graphing | |
| # plt.text(80000000000, 80000000000, chart_summary) # Show the chart summary | |
| plt.show() # actually show the chart to the user, as above shows matplotlib backend | |
| return chart_summary | |
| except Exception as e: | |
| return f"Problem with chart plotting: {e}" # chart_type = None | |
| class TrendAnalysisTool(Tool): | |
| """ | |
| You can retrieve year over year increase percentages for a specific category by setting the category. | |
| Please provide a valid CSV. MAKE SURE headers = columns, and that is in the correct format. | |
| """ | |
| name = "trend_analysis" | |
| description = """ | |
| You can retrieve year over year increase percentages for a specific category by setting the category. Please provide a valid CSV. MAKE SURE headers = columns, and that is in the correct format. | |
| """ | |
| inputs = { | |
| "data": { | |
| "type": "string", | |
| "description": "A string representing the data (e.g., CSV format) - MUST HAVE HEADERS. MUST specify all colums", | |
| }, | |
| "category": { | |
| "type": "string", | |
| "description": "The category we want to compare, such as revenue. Check to know WHAT the name is!!", | |
| }, | |
| } | |
| output_type = "string" | |
| def forward(self, data: str, category: str) -> str: | |
| """Make year over year increases for a given csv | |
| Args: | |
| data: all the data | |
| category: the category we want to compare, such as revenue | |
| """ | |
| try: | |
| df = pd.read_csv(io.StringIO(data)) | |
| except Exception as e: | |
| return f"Error reading data: {e}. Ensure valid CSV, and headers are present: {e}!!" | |
| try: | |
| df["YoY Change"] = df[category].pct_change() * 100 | |
| df["YoY Change"] = df["YoY Change"].map("{:.2f}%".format) | |
| change_description = df.to_string() # | |
| return change_description | |
| except Exception as e: | |
| return f"Error with trend analysis: {e}. Check the name or data!!" | |
| # ########################### | |
| # # Example loading the tools: | |
| # ########################### | |
| # # def load_finance_tools(): | |
| # # finance_tools = [ | |
| # # get_stock_quote_data, | |
| # # get_company_overview_data, | |
| # # get_earnings_data, | |
| # # get_income_statement_data, | |
| # # get_balance_sheet_data, | |
| # # get_cash_flow_data, | |
| # # get_time_series_daily, | |
| # # search_symbols, | |
| # # DataVisualizationTool(), | |
| # # FinancialCalculatorTool(), | |
| # # TrendAnalysisTool() | |
| # # ] | |
| # # return finance_tools | |
| def load_finance_tools(): | |
| """Initialize and return finance tools for data retrieval and analysis. | |
| You MUST put all the correct tools in here, or it will not run. | |
| """ | |
| finance_tools = [] | |
| # finance_tools_names = [] # was getting errors on loading | |
| def safe_tool_load(tool_func, tool_name): | |
| """Helper to safely load and append a finance tool.""" | |
| try: | |
| finance_tools.append(tool_func) | |
| # finance_tools_names.append(tool_func.__name__) # was getting errors on loading | |
| logging.info(f"Loaded {tool_name} tool successfully") | |
| except Exception as e: | |
| logging.error(f"Failed to load tool {tool_name}: {e}") | |
| logging.error(traceback.format_exc()) # Print the stack trace | |
| # Financial calculation tools first | |
| safe_tool_load(DataVisualizationTool(), "DataVisualizationTool") | |
| safe_tool_load(FinancialCalculatorTool(), "FinancialCalculatorTool") | |
| safe_tool_load(TrendAnalysisTool(), "TrendAnalysisTool") | |
| # Raw data retrieval tools last | |
| safe_tool_load(get_stock_quote_data, "get_stock_quote_data") | |
| safe_tool_load(get_company_overview_data, "get_company_overview_data") | |
| safe_tool_load(get_earnings_data, "get_earnings_data") | |
| safe_tool_load(get_income_statement_data, "get_income_statement_data") | |
| safe_tool_load(get_balance_sheet_data, "get_balance_sheet_data") | |
| safe_tool_load(get_cash_flow_data, "get_cash_flow_data") | |
| safe_tool_load(get_time_series_daily, "get_time_series_daily") | |
| safe_tool_load(search_symbols, "search_symbols") | |
| safe_tool_load(get_market_news_sentiment, "get_market_news_sentiment") | |
| return finance_tools | |
| __all__ = [ | |
| "get_stock_quote_data", | |
| "get_company_overview_data", | |
| "get_earnings_data", | |
| "get_income_statement_data", | |
| "get_balance_sheet_data", | |
| "get_cash_flow_data", | |
| "get_time_series_daily", | |
| "search_symbols", | |
| "get_market_news_sentiment", | |
| "DataVisualizationTool", | |
| "FinancialCalculatorTool", | |
| "TrendAnalysisTool", | |
| ] | |