from __future__ import annotations from typing import Final from app.services import data_service DEFAULT_RISK_FREE_RATE: Final = 0.044 DEFAULT_BETA: Final = 1.0 DEFAULT_EQUITY_RISK_PREMIUM: Final = 0.055 DEFAULT_COST_OF_DEBT: Final = 0.05 DEFAULT_TAX_RATE: Final = 0.21 def _unavailable(sym: str) -> dict[str, str | bool | float | None]: info = data_service.get_company_info(sym) fast_info = data_service.get_fast_info(sym) currency_metadata = data_service._currency_metadata(info, fast_info, prefer_reporting=True) return { "symbol": sym, "available": False, "wacc": None, "cost_of_equity": None, "after_tax_cost_of_debt": None, "risk_free_rate": DEFAULT_RISK_FREE_RATE, "beta": DEFAULT_BETA, "equity_risk_premium": DEFAULT_EQUITY_RISK_PREMIUM, "cost_of_debt": DEFAULT_COST_OF_DEBT, "tax_rate": DEFAULT_TAX_RATE, "market_cap": None, "total_debt": None, "cash": None, "net_debt": None, "equity_weight": None, "debt_weight": None, **currency_metadata, } def compute_wacc_value(symbol: str) -> dict[str, str | bool | float | None]: sym = data_service.normalize_symbol(symbol) info = data_service.get_company_info(sym) fast_info = data_service.get_fast_info(sym) balance = data_service.get_balance_sheet(sym, quarterly=True) income = data_service.get_income_statement(sym, quarterly=True) market_cap = data_service._safe_float(info.get("marketCap")) or data_service._safe_float( fast_info.get("marketCap") ) if market_cap is None or market_cap <= 0: return _unavailable(sym) beta = data_service._safe_float(info.get("beta")) if beta is None: beta = DEFAULT_BETA total_debt = data_service._balance_value( balance, "Total Debt", "Long Term Debt And Capital Lease Obligation", ) if total_debt is None: total_debt = data_service._safe_float(info.get("totalDebt")) or 0.0 cash = data_service._balance_value( balance, "Cash And Cash Equivalents", "Cash Cash Equivalents And Short Term Investments", ) if cash is None: cash = data_service._safe_float(info.get("totalCash")) or 0.0 interest_expense = data_service._statement_ttm(income, "Interest Expense") cost_of_debt = DEFAULT_COST_OF_DEBT if interest_expense is not None and total_debt > 0: computed_cost_of_debt = abs(interest_expense) / total_debt if 0 < computed_cost_of_debt < 1: cost_of_debt = computed_cost_of_debt tax_rate = DEFAULT_TAX_RATE tax_provision = data_service._statement_ttm(income, "Tax Provision") pretax_income = data_service._statement_ttm(income, "Pretax Income") if tax_provision is not None and pretax_income is not None and pretax_income > 0: computed_tax_rate = tax_provision / pretax_income if 0 <= computed_tax_rate <= 1: tax_rate = computed_tax_rate risk_free_rate = DEFAULT_RISK_FREE_RATE equity_risk_premium = DEFAULT_EQUITY_RISK_PREMIUM cost_of_equity = risk_free_rate + (beta * equity_risk_premium) after_tax_cost_of_debt = cost_of_debt * (1 - tax_rate) net_debt = max(total_debt - cash, 0.0) total_capital = market_cap + net_debt if total_capital <= 0: return _unavailable(sym) equity_weight = market_cap / total_capital debt_weight = net_debt / total_capital wacc = (cost_of_equity * equity_weight) + (after_tax_cost_of_debt * debt_weight) currency_metadata = data_service._currency_metadata(info, fast_info, prefer_reporting=True) return { "symbol": sym, "available": True, "wacc": wacc, "cost_of_equity": cost_of_equity, "after_tax_cost_of_debt": after_tax_cost_of_debt, "risk_free_rate": risk_free_rate, "beta": beta, "equity_risk_premium": equity_risk_premium, "cost_of_debt": cost_of_debt, "tax_rate": tax_rate, "market_cap": market_cap, "total_debt": total_debt, "cash": cash, "net_debt": net_debt, "equity_weight": equity_weight, "debt_weight": debt_weight, **currency_metadata, }