1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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,
}
|