ellements 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ellements/__init__.py +57 -0
- ellements/agents/__init__.py +45 -0
- ellements/agents/backend.py +100 -0
- ellements/agents/builder.py +303 -0
- ellements/agents/claude_backend.py +200 -0
- ellements/agents/controller.py +237 -0
- ellements/agents/openai_backend.py +187 -0
- ellements/agents/py.typed +0 -0
- ellements/agents/runner.py +358 -0
- ellements/agents/tools.py +30 -0
- ellements/benchmarking/__init__.py +52 -0
- ellements/benchmarking/harness.py +342 -0
- ellements/benchmarking/py.typed +0 -0
- ellements/benchmarking/results.py +173 -0
- ellements/cli/__init__.py +80 -0
- ellements/cli/adapters.py +73 -0
- ellements/cli/agent_tui.py +1178 -0
- ellements/cli/components.py +411 -0
- ellements/cli/printer.py +229 -0
- ellements/cli/py.typed +0 -0
- ellements/core/__init__.py +112 -0
- ellements/core/async_utils.py +42 -0
- ellements/core/budgeting/__init__.py +43 -0
- ellements/core/budgeting/client.py +276 -0
- ellements/core/budgeting/protocol.py +51 -0
- ellements/core/budgeting/trackers.py +177 -0
- ellements/core/caching/__init__.py +51 -0
- ellements/core/caching/cache.py +73 -0
- ellements/core/caching/client.py +300 -0
- ellements/core/caching/disk.py +128 -0
- ellements/core/caching/keys.py +97 -0
- ellements/core/caching/memory.py +104 -0
- ellements/core/chunking.py +262 -0
- ellements/core/config.py +180 -0
- ellements/core/exceptions.py +145 -0
- ellements/core/llm/__init__.py +46 -0
- ellements/core/llm/client.py +1124 -0
- ellements/core/llm/images.py +226 -0
- ellements/core/llm/messages.py +202 -0
- ellements/core/llm/model_params.py +66 -0
- ellements/core/llm/protocol.py +146 -0
- ellements/core/llm/requests.py +100 -0
- ellements/core/llm/structured.py +91 -0
- ellements/core/llm/wrapper.py +79 -0
- ellements/core/observability/__init__.py +39 -0
- ellements/core/observability/events.py +169 -0
- ellements/core/observability/jsonl_logger.py +244 -0
- ellements/core/observability/markdown_formatter.py +197 -0
- ellements/core/observability/observer.py +56 -0
- ellements/core/prompting/__init__.py +14 -0
- ellements/core/prompting/context.py +185 -0
- ellements/core/prompting/guideline.py +133 -0
- ellements/core/prompting/persona.py +267 -0
- ellements/core/prompting/sources.py +92 -0
- ellements/core/py.typed +0 -0
- ellements/core/rate_limit/__init__.py +44 -0
- ellements/core/rate_limit/bucket.py +85 -0
- ellements/core/rate_limit/client.py +216 -0
- ellements/core/rate_limit/protocol.py +27 -0
- ellements/core/templating.py +126 -0
- ellements/core/tools/__init__.py +51 -0
- ellements/core/tools/dialects.py +136 -0
- ellements/core/tools/executor.py +48 -0
- ellements/core/tools/protocol.py +36 -0
- ellements/core/tools/records.py +28 -0
- ellements/core/tools/registry.py +205 -0
- ellements/core/tools/schemas.py +80 -0
- ellements/core/tools/simple.py +119 -0
- ellements/core/tools/spec.py +33 -0
- ellements/domain_specific/__init__.py +7 -0
- ellements/domain_specific/finance/__init__.py +188 -0
- ellements/domain_specific/finance/calculations.py +837 -0
- ellements/domain_specific/finance/charts.py +426 -0
- ellements/domain_specific/finance/portfolio.py +129 -0
- ellements/domain_specific/finance/quant_analysis.py +279 -0
- ellements/domain_specific/finance/risk.py +362 -0
- ellements/domain_specific/finance/technical_indicators.py +241 -0
- ellements/domain_specific/finance/tools.py +483 -0
- ellements/domain_specific/finance/valuation.py +312 -0
- ellements/domain_specific/finance/yahoo_finance.py +1523 -0
- ellements/domain_specific/finance/yahoo_finance_models.py +321 -0
- ellements/domain_specific/py.typed +0 -0
- ellements/execution/__init__.py +56 -0
- ellements/execution/callbacks.py +149 -0
- ellements/execution/catalog.py +70 -0
- ellements/execution/collaborative.py +191 -0
- ellements/execution/config.py +135 -0
- ellements/execution/py.typed +0 -0
- ellements/execution/reflection.py +156 -0
- ellements/execution/self_consistency.py +189 -0
- ellements/execution/single_call.py +48 -0
- ellements/execution/strategies.py +237 -0
- ellements/execution/tree_of_thought.py +541 -0
- ellements/fslm/__init__.py +108 -0
- ellements/fslm/builtins.py +103 -0
- ellements/fslm/cli.py +199 -0
- ellements/fslm/context.py +50 -0
- ellements/fslm/definition.py +163 -0
- ellements/fslm/det.py +173 -0
- ellements/fslm/dsl.py +458 -0
- ellements/fslm/errors.py +38 -0
- ellements/fslm/evaluators.py +141 -0
- ellements/fslm/kernel.py +603 -0
- ellements/fslm/loading.py +123 -0
- ellements/fslm/models.py +623 -0
- ellements/fslm/nl.py +87 -0
- ellements/fslm/observers.py +107 -0
- ellements/fslm/persistence.py +72 -0
- ellements/fslm/py.typed +0 -0
- ellements/fslm/rendering.py +551 -0
- ellements/fslm/visualization.py +25 -0
- ellements/reporting/__init__.py +12 -0
- ellements/reporting/charts.py +364 -0
- ellements/reporting/html_generation.py +132 -0
- ellements/reporting/py.typed +0 -0
- ellements/reporting/visualization.py +73 -0
- ellements/standard_tools/__init__.py +22 -0
- ellements/standard_tools/py.typed +0 -0
- ellements/standard_tools/terminal.py +205 -0
- ellements/standard_tools/web/__init__.py +37 -0
- ellements/standard_tools/web/browser_viewer.py +214 -0
- ellements/standard_tools/web/crawler.py +454 -0
- ellements/standard_tools/web/search.py +399 -0
- ellements/standard_tools/web/youtube.py +1297 -0
- ellements-0.2.0.dist-info/METADATA +368 -0
- ellements-0.2.0.dist-info/RECORD +130 -0
- ellements-0.2.0.dist-info/WHEEL +5 -0
- ellements-0.2.0.dist-info/entry_points.txt +2 -0
- ellements-0.2.0.dist-info/licenses/LICENSE +42 -0
- ellements-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"""Valuation and corporate finance module.
|
|
2
|
+
|
|
3
|
+
Provides:
|
|
4
|
+
- DCF valuation (projected cash flows + terminal value → enterprise value)
|
|
5
|
+
- WACC (weighted average cost of capital)
|
|
6
|
+
- CAPM (cost of equity)
|
|
7
|
+
- Gordon Growth Model (terminal value / intrinsic value)
|
|
8
|
+
- Free Cash Flow (FCFF, FCFE)
|
|
9
|
+
- Enterprise → equity value bridge
|
|
10
|
+
|
|
11
|
+
All functions are pure, stateless, and return Pydantic models where
|
|
12
|
+
the result is non-trivial.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from collections.abc import Sequence
|
|
18
|
+
|
|
19
|
+
from pydantic import BaseModel, Field
|
|
20
|
+
|
|
21
|
+
# ── Result models ────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
class WACCResult(BaseModel):
|
|
24
|
+
"""Weighted average cost of capital breakdown."""
|
|
25
|
+
wacc: float = Field(description="WACC as a decimal (e.g. 0.08 = 8%)")
|
|
26
|
+
equity_weight: float = Field(description="E / (E + D)")
|
|
27
|
+
debt_weight: float = Field(description="D / (E + D)")
|
|
28
|
+
cost_of_equity: float
|
|
29
|
+
cost_of_debt: float
|
|
30
|
+
tax_rate: float
|
|
31
|
+
after_tax_cost_of_debt: float = Field(description="Rd × (1 − Tc)")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class DCFResult(BaseModel):
|
|
35
|
+
"""Discounted cash flow valuation result."""
|
|
36
|
+
pv_cash_flows: float = Field(description="Present value of projected cash flows")
|
|
37
|
+
pv_terminal_value: float = Field(description="Present value of terminal value (0 if none)")
|
|
38
|
+
enterprise_value: float = Field(description="Total DCF enterprise value")
|
|
39
|
+
discount_rate: float
|
|
40
|
+
num_periods: int
|
|
41
|
+
terminal_value_undiscounted: float | None = None
|
|
42
|
+
cash_flows: list[float]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TerminalValueResult(BaseModel):
|
|
46
|
+
"""Terminal value calculation result."""
|
|
47
|
+
terminal_value: float
|
|
48
|
+
method: str # "gordon_growth" or "exit_multiple"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class FCFResult(BaseModel):
|
|
52
|
+
"""Free cash flow calculation result."""
|
|
53
|
+
fcf: float
|
|
54
|
+
method: str # "fcff" or "fcfe"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class EquityValueResult(BaseModel):
|
|
58
|
+
"""Enterprise value to equity value bridge."""
|
|
59
|
+
enterprise_value: float
|
|
60
|
+
total_debt: float
|
|
61
|
+
cash_and_equivalents: float
|
|
62
|
+
equity_value: float
|
|
63
|
+
shares_outstanding: float | None = None
|
|
64
|
+
equity_value_per_share: float | None = None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# ── WACC & Cost of Capital ───────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
def wacc(
|
|
70
|
+
equity_value: float,
|
|
71
|
+
debt_value: float,
|
|
72
|
+
cost_of_equity: float,
|
|
73
|
+
cost_of_debt: float,
|
|
74
|
+
tax_rate: float,
|
|
75
|
+
) -> WACCResult:
|
|
76
|
+
"""Calculate Weighted Average Cost of Capital.
|
|
77
|
+
|
|
78
|
+
WACC = (E/V × Re) + (D/V × Rd × (1 − Tc))
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
equity_value: Market value of equity (E)
|
|
82
|
+
debt_value: Market value of debt (D)
|
|
83
|
+
cost_of_equity: Required return on equity (Re), e.g. 0.10 for 10%
|
|
84
|
+
cost_of_debt: Cost of debt before tax (Rd), e.g. 0.05 for 5%
|
|
85
|
+
tax_rate: Corporate tax rate (Tc), e.g. 0.21 for 21%
|
|
86
|
+
"""
|
|
87
|
+
total = equity_value + debt_value
|
|
88
|
+
if total <= 0:
|
|
89
|
+
raise ValueError("Total capital (E + D) must be positive.")
|
|
90
|
+
|
|
91
|
+
e_weight = equity_value / total
|
|
92
|
+
d_weight = debt_value / total
|
|
93
|
+
after_tax_rd = cost_of_debt * (1 - tax_rate)
|
|
94
|
+
result = (e_weight * cost_of_equity) + (d_weight * after_tax_rd)
|
|
95
|
+
|
|
96
|
+
return WACCResult(
|
|
97
|
+
wacc=result,
|
|
98
|
+
equity_weight=e_weight,
|
|
99
|
+
debt_weight=d_weight,
|
|
100
|
+
cost_of_equity=cost_of_equity,
|
|
101
|
+
cost_of_debt=cost_of_debt,
|
|
102
|
+
tax_rate=tax_rate,
|
|
103
|
+
after_tax_cost_of_debt=after_tax_rd,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def capm(
|
|
108
|
+
risk_free_rate: float,
|
|
109
|
+
beta: float,
|
|
110
|
+
market_return: float,
|
|
111
|
+
) -> float:
|
|
112
|
+
"""Calculate cost of equity via the Capital Asset Pricing Model.
|
|
113
|
+
|
|
114
|
+
Re = Rf + β × (Rm − Rf)
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
risk_free_rate: Risk-free rate (Rf), e.g. 0.04 for 4%
|
|
118
|
+
beta: Asset's systematic risk (β)
|
|
119
|
+
market_return: Expected market return (Rm), e.g. 0.10 for 10%
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Cost of equity as a decimal.
|
|
123
|
+
"""
|
|
124
|
+
return risk_free_rate + beta * (market_return - risk_free_rate)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# ── Terminal Value ───────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
def terminal_value_gordon(
|
|
130
|
+
final_cash_flow: float,
|
|
131
|
+
growth_rate: float,
|
|
132
|
+
discount_rate: float,
|
|
133
|
+
) -> TerminalValueResult:
|
|
134
|
+
"""Terminal value via Gordon Growth Model (perpetuity growth).
|
|
135
|
+
|
|
136
|
+
TV = FCF × (1 + g) / (r − g)
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
final_cash_flow: Last projected cash flow
|
|
140
|
+
growth_rate: Perpetual growth rate (g), e.g. 0.02 for 2%
|
|
141
|
+
discount_rate: Discount rate (r), must be > growth_rate
|
|
142
|
+
"""
|
|
143
|
+
if discount_rate <= growth_rate:
|
|
144
|
+
raise ValueError(
|
|
145
|
+
f"Discount rate ({discount_rate}) must exceed growth rate ({growth_rate})."
|
|
146
|
+
)
|
|
147
|
+
tv = final_cash_flow * (1 + growth_rate) / (discount_rate - growth_rate)
|
|
148
|
+
return TerminalValueResult(terminal_value=tv, method="gordon_growth")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def terminal_value_exit_multiple(
|
|
152
|
+
final_metric: float,
|
|
153
|
+
multiple: float,
|
|
154
|
+
) -> TerminalValueResult:
|
|
155
|
+
"""Terminal value via exit multiple method.
|
|
156
|
+
|
|
157
|
+
TV = Metric × Multiple (e.g., EBITDA × EV/EBITDA)
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
final_metric: Final-year metric (e.g., EBITDA)
|
|
161
|
+
multiple: Valuation multiple (e.g., 10x EV/EBITDA)
|
|
162
|
+
"""
|
|
163
|
+
return TerminalValueResult(
|
|
164
|
+
terminal_value=final_metric * multiple,
|
|
165
|
+
method="exit_multiple",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# ── Gordon Growth Model (intrinsic value) ────────────────────────
|
|
170
|
+
|
|
171
|
+
def gordon_growth_model(
|
|
172
|
+
dividend_or_fcf: float,
|
|
173
|
+
growth_rate: float,
|
|
174
|
+
discount_rate: float,
|
|
175
|
+
) -> float:
|
|
176
|
+
"""Intrinsic value via Gordon Growth / Dividend Discount Model.
|
|
177
|
+
|
|
178
|
+
P = D₁ / (r − g) = D₀ × (1 + g) / (r − g)
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
dividend_or_fcf: Current period dividend or cash flow (D₀)
|
|
182
|
+
growth_rate: Constant growth rate (g)
|
|
183
|
+
discount_rate: Required rate of return (r), must be > g
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
Intrinsic value per share/unit.
|
|
187
|
+
"""
|
|
188
|
+
if discount_rate <= growth_rate:
|
|
189
|
+
raise ValueError(
|
|
190
|
+
f"Discount rate ({discount_rate}) must exceed growth rate ({growth_rate})."
|
|
191
|
+
)
|
|
192
|
+
return dividend_or_fcf * (1 + growth_rate) / (discount_rate - growth_rate)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# ── DCF Valuation ────────────────────────────────────────────────
|
|
196
|
+
|
|
197
|
+
def dcf(
|
|
198
|
+
projected_cash_flows: Sequence[float],
|
|
199
|
+
discount_rate: float,
|
|
200
|
+
terminal_value: float | None = None,
|
|
201
|
+
) -> DCFResult:
|
|
202
|
+
"""Full Discounted Cash Flow valuation.
|
|
203
|
+
|
|
204
|
+
PV = Σ (CFₜ / (1+r)^t) + TV / (1+r)^n
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
projected_cash_flows: Cash flows for periods 1…n (NOT period 0)
|
|
208
|
+
discount_rate: WACC or required return, e.g. 0.10 for 10%
|
|
209
|
+
terminal_value: Undiscounted terminal value at end of last period (optional)
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
DCFResult with enterprise value breakdown.
|
|
213
|
+
"""
|
|
214
|
+
cfs = list(projected_cash_flows)
|
|
215
|
+
n = len(cfs)
|
|
216
|
+
if n == 0:
|
|
217
|
+
raise ValueError("At least one projected cash flow is required.")
|
|
218
|
+
|
|
219
|
+
# PV of each cash flow
|
|
220
|
+
pv_cfs = sum(cf / (1 + discount_rate) ** t for t, cf in enumerate(cfs, start=1))
|
|
221
|
+
|
|
222
|
+
# PV of terminal value
|
|
223
|
+
pv_tv = 0.0
|
|
224
|
+
if terminal_value is not None and terminal_value != 0:
|
|
225
|
+
pv_tv = terminal_value / (1 + discount_rate) ** n
|
|
226
|
+
|
|
227
|
+
return DCFResult(
|
|
228
|
+
pv_cash_flows=pv_cfs,
|
|
229
|
+
pv_terminal_value=pv_tv,
|
|
230
|
+
enterprise_value=pv_cfs + pv_tv,
|
|
231
|
+
discount_rate=discount_rate,
|
|
232
|
+
num_periods=n,
|
|
233
|
+
terminal_value_undiscounted=terminal_value,
|
|
234
|
+
cash_flows=cfs,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
# ── Free Cash Flow ───────────────────────────────────────────────
|
|
239
|
+
|
|
240
|
+
def fcff(
|
|
241
|
+
ebit: float,
|
|
242
|
+
tax_rate: float,
|
|
243
|
+
depreciation: float,
|
|
244
|
+
capex: float,
|
|
245
|
+
change_in_working_capital: float,
|
|
246
|
+
) -> FCFResult:
|
|
247
|
+
"""Free Cash Flow to the Firm.
|
|
248
|
+
|
|
249
|
+
FCFF = EBIT × (1 − T) + D&A − CapEx − ΔWC
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
ebit: Earnings before interest and taxes
|
|
253
|
+
tax_rate: Corporate tax rate
|
|
254
|
+
depreciation: Depreciation & amortization
|
|
255
|
+
capex: Capital expenditures (positive number)
|
|
256
|
+
change_in_working_capital: Increase in net working capital (positive = cash outflow)
|
|
257
|
+
"""
|
|
258
|
+
result = ebit * (1 - tax_rate) + depreciation - capex - change_in_working_capital
|
|
259
|
+
return FCFResult(fcf=result, method="fcff")
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def fcfe(
|
|
263
|
+
net_income: float,
|
|
264
|
+
depreciation: float,
|
|
265
|
+
capex: float,
|
|
266
|
+
change_in_working_capital: float,
|
|
267
|
+
net_borrowing: float,
|
|
268
|
+
) -> FCFResult:
|
|
269
|
+
"""Free Cash Flow to Equity.
|
|
270
|
+
|
|
271
|
+
FCFE = Net Income + D&A − CapEx − ΔWC + Net Borrowing
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
net_income: Net income after tax
|
|
275
|
+
depreciation: Depreciation & amortization
|
|
276
|
+
capex: Capital expenditures (positive number)
|
|
277
|
+
change_in_working_capital: Increase in net working capital (positive = outflow)
|
|
278
|
+
net_borrowing: Net new debt issued (positive = inflow)
|
|
279
|
+
"""
|
|
280
|
+
result = net_income + depreciation - capex - change_in_working_capital + net_borrowing
|
|
281
|
+
return FCFResult(fcf=result, method="fcfe")
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
# ── Enterprise → Equity Bridge ───────────────────────────────────
|
|
285
|
+
|
|
286
|
+
def ev_to_equity(
|
|
287
|
+
enterprise_value: float,
|
|
288
|
+
total_debt: float,
|
|
289
|
+
cash_and_equivalents: float,
|
|
290
|
+
shares_outstanding: float | None = None,
|
|
291
|
+
) -> EquityValueResult:
|
|
292
|
+
"""Convert enterprise value to equity value.
|
|
293
|
+
|
|
294
|
+
Equity Value = EV − Debt + Cash
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
enterprise_value: Enterprise value (e.g., from DCF)
|
|
298
|
+
total_debt: Total interest-bearing debt
|
|
299
|
+
cash_and_equivalents: Cash and cash equivalents
|
|
300
|
+
shares_outstanding: Optional — if provided, calculates per-share value
|
|
301
|
+
"""
|
|
302
|
+
equity = enterprise_value - total_debt + cash_and_equivalents
|
|
303
|
+
per_share = equity / shares_outstanding if shares_outstanding and shares_outstanding > 0 else None
|
|
304
|
+
|
|
305
|
+
return EquityValueResult(
|
|
306
|
+
enterprise_value=enterprise_value,
|
|
307
|
+
total_debt=total_debt,
|
|
308
|
+
cash_and_equivalents=cash_and_equivalents,
|
|
309
|
+
equity_value=equity,
|
|
310
|
+
shares_outstanding=shares_outstanding,
|
|
311
|
+
equity_value_per_share=per_share,
|
|
312
|
+
)
|