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.
Files changed (130) hide show
  1. ellements/__init__.py +57 -0
  2. ellements/agents/__init__.py +45 -0
  3. ellements/agents/backend.py +100 -0
  4. ellements/agents/builder.py +303 -0
  5. ellements/agents/claude_backend.py +200 -0
  6. ellements/agents/controller.py +237 -0
  7. ellements/agents/openai_backend.py +187 -0
  8. ellements/agents/py.typed +0 -0
  9. ellements/agents/runner.py +358 -0
  10. ellements/agents/tools.py +30 -0
  11. ellements/benchmarking/__init__.py +52 -0
  12. ellements/benchmarking/harness.py +342 -0
  13. ellements/benchmarking/py.typed +0 -0
  14. ellements/benchmarking/results.py +173 -0
  15. ellements/cli/__init__.py +80 -0
  16. ellements/cli/adapters.py +73 -0
  17. ellements/cli/agent_tui.py +1178 -0
  18. ellements/cli/components.py +411 -0
  19. ellements/cli/printer.py +229 -0
  20. ellements/cli/py.typed +0 -0
  21. ellements/core/__init__.py +112 -0
  22. ellements/core/async_utils.py +42 -0
  23. ellements/core/budgeting/__init__.py +43 -0
  24. ellements/core/budgeting/client.py +276 -0
  25. ellements/core/budgeting/protocol.py +51 -0
  26. ellements/core/budgeting/trackers.py +177 -0
  27. ellements/core/caching/__init__.py +51 -0
  28. ellements/core/caching/cache.py +73 -0
  29. ellements/core/caching/client.py +300 -0
  30. ellements/core/caching/disk.py +128 -0
  31. ellements/core/caching/keys.py +97 -0
  32. ellements/core/caching/memory.py +104 -0
  33. ellements/core/chunking.py +262 -0
  34. ellements/core/config.py +180 -0
  35. ellements/core/exceptions.py +145 -0
  36. ellements/core/llm/__init__.py +46 -0
  37. ellements/core/llm/client.py +1124 -0
  38. ellements/core/llm/images.py +226 -0
  39. ellements/core/llm/messages.py +202 -0
  40. ellements/core/llm/model_params.py +66 -0
  41. ellements/core/llm/protocol.py +146 -0
  42. ellements/core/llm/requests.py +100 -0
  43. ellements/core/llm/structured.py +91 -0
  44. ellements/core/llm/wrapper.py +79 -0
  45. ellements/core/observability/__init__.py +39 -0
  46. ellements/core/observability/events.py +169 -0
  47. ellements/core/observability/jsonl_logger.py +244 -0
  48. ellements/core/observability/markdown_formatter.py +197 -0
  49. ellements/core/observability/observer.py +56 -0
  50. ellements/core/prompting/__init__.py +14 -0
  51. ellements/core/prompting/context.py +185 -0
  52. ellements/core/prompting/guideline.py +133 -0
  53. ellements/core/prompting/persona.py +267 -0
  54. ellements/core/prompting/sources.py +92 -0
  55. ellements/core/py.typed +0 -0
  56. ellements/core/rate_limit/__init__.py +44 -0
  57. ellements/core/rate_limit/bucket.py +85 -0
  58. ellements/core/rate_limit/client.py +216 -0
  59. ellements/core/rate_limit/protocol.py +27 -0
  60. ellements/core/templating.py +126 -0
  61. ellements/core/tools/__init__.py +51 -0
  62. ellements/core/tools/dialects.py +136 -0
  63. ellements/core/tools/executor.py +48 -0
  64. ellements/core/tools/protocol.py +36 -0
  65. ellements/core/tools/records.py +28 -0
  66. ellements/core/tools/registry.py +205 -0
  67. ellements/core/tools/schemas.py +80 -0
  68. ellements/core/tools/simple.py +119 -0
  69. ellements/core/tools/spec.py +33 -0
  70. ellements/domain_specific/__init__.py +7 -0
  71. ellements/domain_specific/finance/__init__.py +188 -0
  72. ellements/domain_specific/finance/calculations.py +837 -0
  73. ellements/domain_specific/finance/charts.py +426 -0
  74. ellements/domain_specific/finance/portfolio.py +129 -0
  75. ellements/domain_specific/finance/quant_analysis.py +279 -0
  76. ellements/domain_specific/finance/risk.py +362 -0
  77. ellements/domain_specific/finance/technical_indicators.py +241 -0
  78. ellements/domain_specific/finance/tools.py +483 -0
  79. ellements/domain_specific/finance/valuation.py +312 -0
  80. ellements/domain_specific/finance/yahoo_finance.py +1523 -0
  81. ellements/domain_specific/finance/yahoo_finance_models.py +321 -0
  82. ellements/domain_specific/py.typed +0 -0
  83. ellements/execution/__init__.py +56 -0
  84. ellements/execution/callbacks.py +149 -0
  85. ellements/execution/catalog.py +70 -0
  86. ellements/execution/collaborative.py +191 -0
  87. ellements/execution/config.py +135 -0
  88. ellements/execution/py.typed +0 -0
  89. ellements/execution/reflection.py +156 -0
  90. ellements/execution/self_consistency.py +189 -0
  91. ellements/execution/single_call.py +48 -0
  92. ellements/execution/strategies.py +237 -0
  93. ellements/execution/tree_of_thought.py +541 -0
  94. ellements/fslm/__init__.py +108 -0
  95. ellements/fslm/builtins.py +103 -0
  96. ellements/fslm/cli.py +199 -0
  97. ellements/fslm/context.py +50 -0
  98. ellements/fslm/definition.py +163 -0
  99. ellements/fslm/det.py +173 -0
  100. ellements/fslm/dsl.py +458 -0
  101. ellements/fslm/errors.py +38 -0
  102. ellements/fslm/evaluators.py +141 -0
  103. ellements/fslm/kernel.py +603 -0
  104. ellements/fslm/loading.py +123 -0
  105. ellements/fslm/models.py +623 -0
  106. ellements/fslm/nl.py +87 -0
  107. ellements/fslm/observers.py +107 -0
  108. ellements/fslm/persistence.py +72 -0
  109. ellements/fslm/py.typed +0 -0
  110. ellements/fslm/rendering.py +551 -0
  111. ellements/fslm/visualization.py +25 -0
  112. ellements/reporting/__init__.py +12 -0
  113. ellements/reporting/charts.py +364 -0
  114. ellements/reporting/html_generation.py +132 -0
  115. ellements/reporting/py.typed +0 -0
  116. ellements/reporting/visualization.py +73 -0
  117. ellements/standard_tools/__init__.py +22 -0
  118. ellements/standard_tools/py.typed +0 -0
  119. ellements/standard_tools/terminal.py +205 -0
  120. ellements/standard_tools/web/__init__.py +37 -0
  121. ellements/standard_tools/web/browser_viewer.py +214 -0
  122. ellements/standard_tools/web/crawler.py +454 -0
  123. ellements/standard_tools/web/search.py +399 -0
  124. ellements/standard_tools/web/youtube.py +1297 -0
  125. ellements-0.2.0.dist-info/METADATA +368 -0
  126. ellements-0.2.0.dist-info/RECORD +130 -0
  127. ellements-0.2.0.dist-info/WHEEL +5 -0
  128. ellements-0.2.0.dist-info/entry_points.txt +2 -0
  129. ellements-0.2.0.dist-info/licenses/LICENSE +42 -0
  130. 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
+ )