diff options
Diffstat (limited to 'backend/app/services/wacc_service.py')
| -rw-r--r-- | backend/app/services/wacc_service.py | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/backend/app/services/wacc_service.py b/backend/app/services/wacc_service.py new file mode 100644 index 0000000..2b4ee3e --- /dev/null +++ b/backend/app/services/wacc_service.py @@ -0,0 +1,120 @@ +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, + } |
