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,241 @@
1
+ """Technical analysis indicators with pandas-first APIs backed by TA-Lib."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+ from typing import Any
7
+
8
+ import numpy as np
9
+ import pandas as pd
10
+ from pydantic import BaseModel
11
+
12
+
13
+ def talib_available() -> bool:
14
+ """Return True when TA-Lib can be imported."""
15
+ try:
16
+ import talib # noqa: F401
17
+ except ImportError:
18
+ return False
19
+ return True
20
+
21
+
22
+ def _load_talib() -> Any:
23
+ try:
24
+ import talib
25
+ except ImportError as exc:
26
+ raise RuntimeError(
27
+ "TA-Lib is required for technical indicators. "
28
+ "Install with: pip install TA-Lib"
29
+ ) from exc
30
+ return talib
31
+
32
+
33
+ class TechnicalIndicatorSnapshot(BaseModel):
34
+ """Latest values for the core technical indicator set."""
35
+
36
+ sample_size: int = 0
37
+ rsi: float | None = None
38
+ macd: float | None = None
39
+ macd_signal: float | None = None
40
+ macd_histogram: float | None = None
41
+ sma: float | None = None
42
+ ema: float | None = None
43
+ bollinger_upper: float | None = None
44
+ bollinger_middle: float | None = None
45
+ bollinger_lower: float | None = None
46
+ stochastic_k: float | None = None
47
+ stochastic_d: float | None = None
48
+ atr: float | None = None
49
+ adx: float | None = None
50
+
51
+
52
+ def _as_float_series(series: pd.Series) -> pd.Series:
53
+ return pd.to_numeric(series, errors="coerce").astype("float64")
54
+
55
+
56
+ def _validate_positive_int(name: str, value: int) -> None:
57
+ if value <= 0:
58
+ raise ValueError(f"{name} must be > 0.")
59
+
60
+
61
+ def _normalize_price_input(
62
+ data: pd.Series | pd.DataFrame | Sequence[float],
63
+ ) -> pd.DataFrame:
64
+ if isinstance(data, pd.Series):
65
+ frame = pd.DataFrame({"close": _as_float_series(data)})
66
+ frame.index = data.index
67
+ return frame.sort_index()
68
+
69
+ if isinstance(data, pd.DataFrame):
70
+ frame = data.copy()
71
+ if frame.empty:
72
+ raise ValueError("Input DataFrame is empty.")
73
+
74
+ normalized_columns: dict[object, str] = {}
75
+ for original in frame.columns:
76
+ raw = str(original).strip().lower().replace(" ", "_")
77
+ if raw in {"open", "high", "low", "close", "volume"}:
78
+ normalized_columns[original] = raw
79
+ elif raw in {"adj_close", "adjusted_close", "adjclose"}:
80
+ normalized_columns[original] = "adj_close"
81
+
82
+ if not normalized_columns:
83
+ raise ValueError(
84
+ "Input DataFrame must include close prices (close/adj_close)."
85
+ )
86
+
87
+ working = frame.rename(columns=normalized_columns)
88
+ selected_columns = [
89
+ col
90
+ for col in ["open", "high", "low", "close", "adj_close", "volume"]
91
+ if col in working.columns
92
+ ]
93
+ working = working[selected_columns].copy()
94
+
95
+ if "close" not in working.columns:
96
+ if "adj_close" not in working.columns:
97
+ raise ValueError(
98
+ "Input DataFrame must include close prices (close/adj_close)."
99
+ )
100
+ working["close"] = working["adj_close"]
101
+ elif "adj_close" in working.columns:
102
+ working["close"] = working["close"].fillna(working["adj_close"])
103
+
104
+ for column in working.columns:
105
+ working[column] = _as_float_series(working[column])
106
+
107
+ return working.sort_index()
108
+
109
+ if not isinstance(data, Sequence):
110
+ raise ValueError("Unsupported input type for technical indicators.")
111
+
112
+ series = pd.Series(list(data), dtype="float64")
113
+ return pd.DataFrame({"close": _as_float_series(series)})
114
+
115
+
116
+ def _last_finite(series: pd.Series) -> float | None:
117
+ clean = series.replace([np.inf, -np.inf], np.nan).dropna()
118
+ if clean.empty:
119
+ return None
120
+ return float(clean.iloc[-1])
121
+
122
+
123
+ def latest_indicator_snapshot(indicators: pd.DataFrame) -> TechnicalIndicatorSnapshot:
124
+ """Extract latest finite values for each indicator column."""
125
+ return TechnicalIndicatorSnapshot(
126
+ sample_size=int(len(indicators)),
127
+ rsi=_last_finite(indicators["rsi"]),
128
+ macd=_last_finite(indicators["macd"]),
129
+ macd_signal=_last_finite(indicators["macd_signal"]),
130
+ macd_histogram=_last_finite(indicators["macd_histogram"]),
131
+ sma=_last_finite(indicators["sma"]),
132
+ ema=_last_finite(indicators["ema"]),
133
+ bollinger_upper=_last_finite(indicators["bollinger_upper"]),
134
+ bollinger_middle=_last_finite(indicators["bollinger_middle"]),
135
+ bollinger_lower=_last_finite(indicators["bollinger_lower"]),
136
+ stochastic_k=_last_finite(indicators["stochastic_k"]),
137
+ stochastic_d=_last_finite(indicators["stochastic_d"]),
138
+ atr=_last_finite(indicators["atr"]),
139
+ adx=_last_finite(indicators["adx"]),
140
+ )
141
+
142
+
143
+ def compute_technical_indicators(
144
+ data: pd.Series | pd.DataFrame | Sequence[float],
145
+ *,
146
+ rsi_period: int = 14,
147
+ macd_fast: int = 12,
148
+ macd_slow: int = 26,
149
+ macd_signal: int = 9,
150
+ sma_period: int = 20,
151
+ ema_period: int = 20,
152
+ bollinger_window: int = 20,
153
+ bollinger_dev: float = 2.0,
154
+ stochastic_window: int = 14,
155
+ stochastic_smooth_window: int = 3,
156
+ atr_window: int = 14,
157
+ adx_window: int = 14,
158
+ ) -> tuple[pd.DataFrame, TechnicalIndicatorSnapshot]:
159
+ """Compute the technical indicator set on Series/DataFrame inputs.
160
+
161
+ Returns:
162
+ tuple[pd.DataFrame, TechnicalIndicatorSnapshot]:
163
+ - DataFrame with one column per indicator and aligned index.
164
+ - Snapshot with latest finite values.
165
+ """
166
+ _validate_positive_int("rsi_period", rsi_period)
167
+ _validate_positive_int("macd_fast", macd_fast)
168
+ _validate_positive_int("macd_slow", macd_slow)
169
+ _validate_positive_int("macd_signal", macd_signal)
170
+ _validate_positive_int("sma_period", sma_period)
171
+ _validate_positive_int("ema_period", ema_period)
172
+ _validate_positive_int("bollinger_window", bollinger_window)
173
+ _validate_positive_int("stochastic_window", stochastic_window)
174
+ _validate_positive_int("stochastic_smooth_window", stochastic_smooth_window)
175
+ _validate_positive_int("atr_window", atr_window)
176
+ _validate_positive_int("adx_window", adx_window)
177
+ if bollinger_dev <= 0:
178
+ raise ValueError("bollinger_dev must be > 0.")
179
+
180
+ talib = _load_talib()
181
+ frame = _normalize_price_input(data)
182
+ if frame.empty:
183
+ raise ValueError("No price data available to compute indicators.")
184
+
185
+ close = frame["close"].to_numpy(dtype="float64")
186
+ rsi = talib.RSI(close, timeperiod=rsi_period)
187
+ macd, macd_signal_line, macd_hist = talib.MACD(
188
+ close,
189
+ fastperiod=macd_fast,
190
+ slowperiod=macd_slow,
191
+ signalperiod=macd_signal,
192
+ )
193
+ sma = talib.SMA(close, timeperiod=sma_period)
194
+ ema = talib.EMA(close, timeperiod=ema_period)
195
+ bb_upper, bb_middle, bb_lower = talib.BBANDS(
196
+ close,
197
+ timeperiod=bollinger_window,
198
+ nbdevup=bollinger_dev,
199
+ nbdevdn=bollinger_dev,
200
+ )
201
+
202
+ nan_line = np.full(len(frame), np.nan, dtype="float64")
203
+ stochastic_k = nan_line.copy()
204
+ stochastic_d = nan_line.copy()
205
+ atr = nan_line.copy()
206
+ adx = nan_line.copy()
207
+
208
+ if {"high", "low"}.issubset(frame.columns):
209
+ high = frame["high"].to_numpy(dtype="float64")
210
+ low = frame["low"].to_numpy(dtype="float64")
211
+ stochastic_k, stochastic_d = talib.STOCH(
212
+ high,
213
+ low,
214
+ close,
215
+ fastk_period=stochastic_window,
216
+ slowk_period=stochastic_smooth_window,
217
+ slowd_period=stochastic_smooth_window,
218
+ )
219
+ atr = talib.ATR(high, low, close, timeperiod=atr_window)
220
+ adx = talib.ADX(high, low, close, timeperiod=adx_window)
221
+
222
+ indicators = pd.DataFrame(
223
+ {
224
+ "rsi": rsi,
225
+ "macd": macd,
226
+ "macd_signal": macd_signal_line,
227
+ "macd_histogram": macd_hist,
228
+ "sma": sma,
229
+ "ema": ema,
230
+ "bollinger_upper": bb_upper,
231
+ "bollinger_middle": bb_middle,
232
+ "bollinger_lower": bb_lower,
233
+ "stochastic_k": stochastic_k,
234
+ "stochastic_d": stochastic_d,
235
+ "atr": atr,
236
+ "adx": adx,
237
+ },
238
+ index=frame.index,
239
+ dtype="float64",
240
+ )
241
+ return indicators, latest_indicator_snapshot(indicators)