summaryrefslogtreecommitdiff
path: root/backend/app/services
diff options
context:
space:
mode:
Diffstat (limited to 'backend/app/services')
-rw-r--r--backend/app/services/wacc_service.py120
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,
+ }