Spaces:
Running
Running
| import logging | |
| import yfinance as yf | |
| class FundamentalAnalysis: | |
| def __init__( | |
| self, | |
| ticker: str, | |
| debug: bool=False): | |
| """ | |
| Initialize FundamentalAnalysis object. | |
| Args: | |
| ticker : str | |
| Stock ticker to analyze. | |
| debug : bool, optional, default: False | |
| Whether to run in debug mode, so that logging is produced at debug level. | |
| """ | |
| # set up logging | |
| if debug: | |
| self.logger_level = logging.DEBUG | |
| else: | |
| self.logger_level = logging.INFO | |
| self.logger = logging.getLogger(__name__) | |
| logging.basicConfig(level=self.logger_level) # filename='FundamentalAnalysis.log', | |
| # input args | |
| self.ticker = ticker | |
| # done initializing | |
| self.logger.info(f'Initialized TechnicalAnalysis object for ticker: {ticker}') | |
| def run( | |
| self | |
| ) -> dict: | |
| """ | |
| Runs the fundamental analysis for the given ticker. | |
| Returns: | |
| dict: A dictionary with fundamental metrics for the given ticker. | |
| """ | |
| self.info = self.fetch_stock_info() | |
| if len(self.info) > 0: | |
| result = self.get_stock_fundamentals() | |
| else: | |
| result = {} | |
| return result | |
| def fetch_stock_info( | |
| self | |
| ) -> dict: | |
| """ | |
| Fetches all available information for a given stock ticker using yfinance. | |
| Returns: | |
| dict: A dictionary of key-value pairs with available information for the given ticker. | |
| """ | |
| try: | |
| stock = yf.Ticker(self.ticker) | |
| info = stock.info # Fetch all available info | |
| except Exception as e: | |
| self.logger.error(f"Error fetching stock info for {self.ticker}: {str(e)}") | |
| info = {} | |
| if len(info) == 1: | |
| info = {} | |
| else: | |
| self.logger.info(f"Fetched stock info for {self.ticker}") | |
| return info | |
| def get_stock_fundamentals( | |
| self | |
| ) -> dict: | |
| """ | |
| Attempts to fetches key fundamental metrics for a given stock ticker using yfinance. | |
| Returns: | |
| dict: Dictionary of fundamental metrics with human-readable keys | |
| """ | |
| # Define a safe fetch method to avoid entire function failure | |
| def safe_get(key, transform=None): | |
| value = self.info.get(key, "Metric not available") | |
| if value != "Metric not available" and transform: | |
| try: | |
| return transform(value) | |
| except Exception: | |
| return "metric not available" | |
| return value | |
| # Extract key financial metrics | |
| fundamentals = { | |
| "Company Name": safe_get("longName"), | |
| "Sector": safe_get("sector"), | |
| "Industry": safe_get("industry"), | |
| "Market Capitalization": safe_get("marketCap"), | |
| # Valuation Metrics | |
| "P/E Ratio (Trailing)": safe_get("trailingPE"), | |
| "P/E Ratio (Forward)": safe_get("forwardPE"), | |
| "P/B Ratio (Price to Book)": safe_get("priceToBook"), | |
| "P/S Ratio (Price to Sales)": safe_get("priceToSalesTrailing12Months"), | |
| "Dividend Yield (%)": safe_get("dividendYield", lambda x: round(x * 100, 2)), | |
| # Profitability Metrics | |
| "Earnings Per Share (EPS)": safe_get("trailingEps"), | |
| "Return on Equity (ROE)": safe_get("returnOnEquity"), | |
| "Return on Assets (ROA)": safe_get("returnOnAssets"), | |
| "Gross Margin (%)": safe_get("grossMargins", lambda x: round(x * 100, 2)), | |
| "Operating Margin (%)": safe_get("operatingMargins", lambda x: round(x * 100, 2)), | |
| # Financial Health Metrics | |
| "Debt-to-Equity Ratio": safe_get("debtToEquity"), | |
| "Current Ratio": safe_get("currentRatio"), | |
| "Quick Ratio": safe_get("quickRatio"), | |
| "Interest Coverage Ratio": safe_get( | |
| "ebitda", | |
| lambda ebitda: round(ebitda / self.info["totalDebt"], 2) if self.info.get("totalDebt") else "Metric not available" | |
| ), | |
| # Growth Metrics | |
| "Revenue Growth (%)": safe_get("revenueGrowth", lambda x: round(x * 100, 2)), | |
| "EPS Growth (%)": safe_get("earningsGrowth", lambda x: round(x * 100, 2)), | |
| # Market & Ownership | |
| "Institutional Ownership (%)": safe_get("heldPercentInstitutions", lambda x: round(x * 100, 2)), | |
| "Insider Ownership (%)": safe_get("heldPercentInsiders", lambda x: round(x * 100, 2)), | |
| } | |
| return fundamentals | |
| if __name__ == '__main__': | |
| dict_fundamentals = FundamentalAnalysis(ticker="GOOG").run() | |
| if len(dict_fundamentals) > 0: | |
| for key, value in dict_fundamentals.items(): | |
| print(f"{key}: {value}") | |
| else: | |
| print("No fundamental data available.") | |