StockAnalysisAgent / src /fundamental_analysis.py
OnurKerimoglu's picture
fundamental_analysis: log message for successful fetching
8ce1623
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.")