Open SaudAltamimi opened 2 months ago
Useful code snippet:
import yfinance as yf
from typing import Tuple, Dict
class FinancialData:
"""
A class to represent financial data for a stock.
Attributes:
ticker (str): The stock ticker symbol.
balance_sheet (pd.DataFrame): Balance sheet data.
income_statement (pd.DataFrame): Income statement data.
cash_flow (pd.DataFrame): Cash flow statement data.
"""
def __init__(self, ticker: str):
"""
Initialize FinancialData with a stock ticker.
Args:
ticker (str): The stock ticker symbol.
"""
self.ticker = ticker
self.balance_sheet, self.income_statement, self.cash_flow = self._get_financial_data()
def _get_financial_data(self) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
"""
Fetch financial data from Yahoo Finance.
Returns:
Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]: Balance sheet, income statement, and cash flow data.
"""
stock = yf.Ticker(self.ticker)
return stock.balance_sheet, stock.financials, stock.cashflow
class ValuationMetrics:
"""
A class to calculate various valuation metrics for a stock.
Attributes:
financial_data (FinancialData): Financial data for the stock.
"""
def __init__(self, financial_data: FinancialData):
"""
Initialize ValuationMetrics with financial data.
Args:
financial_data (FinancialData): Financial data for the stock.
"""
self.financial_data = financial_data
def calculate_ncav(self) -> float:
"""
Calculate Net Current Asset Value (NCAV).
Returns:
float: The calculated NCAV.
"""
current_assets = self.financial_data.balance_sheet.loc['Total Current Assets'].iloc[0]
total_liabilities = self.financial_data.balance_sheet.loc['Total Liabilities'].iloc[0]
return current_assets - total_liabilities
def calculate_epv(self, wacc: float = 0.10) -> float:
"""
Calculate Earnings Power Value (EPV).
Args:
wacc (float): Weighted Average Cost of Capital. Defaults to 0.10.
Returns:
float: The calculated EPV.
"""
income_statement = self.financial_data.income_statement
cash_flow = self.financial_data.cash_flow
# Calculate average EBIT margin
ebit = income_statement.loc['EBIT']
revenue = income_statement.loc['Total Revenue']
ebit_margins = ebit / revenue
avg_ebit_margin = ebit_margins.mean()
# Normalize EBIT
current_revenue = revenue.iloc[0]
normalized_ebit = current_revenue * avg_ebit_margin
# Calculate after-tax normalized EBIT
tax_rate = income_statement.loc['Income Tax Expense'].iloc[0] / income_statement.loc['Income Before Tax'].iloc[0]
after_tax_normalized_ebit = normalized_ebit * (1 - tax_rate)
# Adjust for depreciation
avg_depreciation = cash_flow.loc['Depreciation'].mean()
adjusted_depreciation = 0.5 * tax_rate * avg_depreciation
# Calculate maintenance capex
capex = cash_flow.loc['Capital Expenditures'].abs()
income_growth_rate = income_statement.loc['Net Income'].pct_change().mean()
maintenance_capex = capex.mean() * (1 - income_growth_rate)
# Calculate adjusted earnings
adjusted_earnings = after_tax_normalized_ebit + adjusted_depreciation - maintenance_capex
return adjusted_earnings / wacc
@staticmethod
def calculate_margin_of_safety(intrinsic_value: float, current_price: float) -> float:
"""
Calculate Margin of Safety.
Args:
intrinsic_value (float): The estimated intrinsic value of the stock.
current_price (float): The current market price of the stock.
Returns:
float: The calculated Margin of Safety.
"""
return 1 - (current_price / intrinsic_value)
class StockAnalyzer:
"""
A class to analyze a stock using various valuation metrics.
Attributes:
ticker (str): The stock ticker symbol.
financial_data (FinancialData): Financial data for the stock.
valuation_metrics (ValuationMetrics): Valuation metrics calculator for the stock.
"""
def __init__(self, ticker: str):
"""
Initialize StockAnalyzer with a stock ticker.
Args:
ticker (str): The stock ticker symbol.
"""
self.ticker = ticker
self.financial_data = FinancialData(ticker)
self.valuation_metrics = ValuationMetrics(self.financial_data)
def analyze(self) -> Dict[str, float]:
"""
Perform a comprehensive analysis of the stock.
Returns:
Dict[str, float]: A dictionary containing various analysis results.
"""
stock = yf.Ticker(self.ticker)
current_price = stock.info['currentPrice']
shares_outstanding = stock.info['sharesOutstanding']
ncav = self.valuation_metrics.calculate_ncav()
epv = self.valuation_metrics.calculate_epv()
ncav_per_share = ncav / shares_outstanding
epv_per_share = epv / shares_outstanding
mos_ncav = self.valuation_metrics.calculate_margin_of_safety(ncav_per_share, current_price)
mos_epv = self.valuation_metrics.calculate_margin_of_safety(epv_per_share, current_price)
return {
'current_price': current_price,
'ncav_per_share': ncav_per_share,
'epv_per_share': epv_per_share,
'mos_ncav': mos_ncav,
'mos_epv': mos_epv
}
def print_analysis(self):
"""
Print the stock analysis results.
"""
results = self.analyze()
print(f"Analysis for {self.ticker}:")
print(f"Current Price: ${results['current_price']:.2f}")
print(f"NCAV per share: ${results['ncav_per_share']:.2f}")
print(f"EPV per share: ${results['epv_per_share']:.2f}")
print(f"Margin of Safety (NCAV): {results['mos_ncav']:.2%}")
print(f"Margin of Safety (EPV): {results['mos_epv']:.2%}")
# Example usage
if __name__ == "__main__":
analyzer = StockAnalyzer("AAPL")
analyzer.print_analysis()