david-data 0.1.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.
@@ -0,0 +1,129 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, List, Optional
4
+
5
+ from .base import Resource
6
+
7
+ DateLike = Any
8
+
9
+
10
+ class News(Resource):
11
+ """Synthetic / real news articles."""
12
+
13
+ def list(
14
+ self,
15
+ *,
16
+ scenario_id: Optional[str] = None,
17
+ ticker: Optional[str] = None,
18
+ as_of: Optional[DateLike] = None,
19
+ start_date: Optional[DateLike] = None,
20
+ end_date: Optional[DateLike] = None,
21
+ limit: int = 50,
22
+ offset: int = 0,
23
+ ) -> List[dict]:
24
+ return self._get(
25
+ "/news",
26
+ params={
27
+ "scenario_id": self._scenario(scenario_id),
28
+ "ticker": ticker,
29
+ "as_of": as_of,
30
+ "start_date": start_date,
31
+ "end_date": end_date,
32
+ "limit": limit,
33
+ "offset": offset,
34
+ },
35
+ unwrap="news",
36
+ )
37
+
38
+ def get(self, artifact_id: str, *, scenario_id: Optional[str] = None) -> dict:
39
+ """Fetch the full body of a single news article."""
40
+ return self._get(
41
+ f"/news/{artifact_id}",
42
+ params={"scenario_id": self._scenario(scenario_id)},
43
+ unwrap="news_article",
44
+ )
45
+
46
+
47
+ class Filings(Resource):
48
+ """SEC-style filings: index, full-text item search, and facet lookups."""
49
+
50
+ def list(
51
+ self,
52
+ *,
53
+ scenario_id: Optional[str] = None,
54
+ ticker: Optional[str] = None,
55
+ filing_type: Optional[str] = None,
56
+ start_date: Optional[DateLike] = None,
57
+ end_date: Optional[DateLike] = None,
58
+ limit: int = 50,
59
+ offset: int = 0,
60
+ ) -> List[dict]:
61
+ return self._get(
62
+ "/filings",
63
+ params={
64
+ "scenario_id": self._scenario(scenario_id),
65
+ "ticker": ticker,
66
+ "filing_type": filing_type,
67
+ "start_date": start_date,
68
+ "end_date": end_date,
69
+ "limit": limit,
70
+ "offset": offset,
71
+ },
72
+ unwrap="filings",
73
+ )
74
+
75
+ def items(
76
+ self,
77
+ *,
78
+ scenario_id: Optional[str] = None,
79
+ ticker: Optional[str] = None,
80
+ filing_type: Optional[str] = None,
81
+ item: Optional[str] = None,
82
+ year: Optional[int] = None,
83
+ quarter: Optional[int] = None,
84
+ start_date: Optional[DateLike] = None,
85
+ end_date: Optional[DateLike] = None,
86
+ limit: int = 50,
87
+ offset: int = 0,
88
+ ) -> List[dict]:
89
+ """Filing items with their extracted text (e.g. 10-K Item 1A, 8-K items)."""
90
+ return self._get(
91
+ "/filings/items",
92
+ params={
93
+ "scenario_id": self._scenario(scenario_id),
94
+ "ticker": ticker,
95
+ "filing_type": filing_type,
96
+ "item": item,
97
+ "year": year,
98
+ "quarter": quarter,
99
+ "start_date": start_date,
100
+ "end_date": end_date,
101
+ "limit": limit,
102
+ "offset": offset,
103
+ },
104
+ unwrap="filing_items",
105
+ )
106
+
107
+ def types(self, *, scenario_id: Optional[str] = None) -> Any:
108
+ return self._get(
109
+ "/filings/types",
110
+ params={"scenario_id": self._scenario(scenario_id)},
111
+ unwrap="filing_types",
112
+ )
113
+
114
+ def item_types(self, *, scenario_id: Optional[str] = None) -> Any:
115
+ return self._get(
116
+ "/filings/items/types",
117
+ params={"scenario_id": self._scenario(scenario_id)},
118
+ unwrap="item_types",
119
+ )
120
+
121
+ def tickers(self, *, scenario_id: Optional[str] = None) -> List[str]:
122
+ return self._get(
123
+ "/filings/tickers", params={"scenario_id": self._scenario(scenario_id)}, unwrap="tickers"
124
+ )
125
+
126
+ def ciks(self, *, scenario_id: Optional[str] = None) -> Any:
127
+ return self._get(
128
+ "/filings/ciks", params={"scenario_id": self._scenario(scenario_id)}, unwrap="ciks"
129
+ )
@@ -0,0 +1,132 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, List, Optional
4
+
5
+ from .base import Resource
6
+
7
+ DateLike = Any
8
+
9
+
10
+ class Earnings(Resource):
11
+ """Reported earnings and the forward earnings calendar."""
12
+
13
+ def list(
14
+ self,
15
+ ticker: Optional[str] = None,
16
+ *,
17
+ scenario_id: Optional[str] = None,
18
+ limit: int = 8,
19
+ offset: int = 0,
20
+ ) -> List[dict]:
21
+ return self._get(
22
+ "/earnings",
23
+ params={
24
+ "scenario_id": self._scenario(scenario_id),
25
+ "ticker": ticker,
26
+ "limit": limit,
27
+ "offset": offset,
28
+ },
29
+ unwrap="earnings",
30
+ )
31
+
32
+ def calendar(
33
+ self, ticker: str, *, scenario_id: Optional[str] = None, limit: int = 8, offset: int = 0
34
+ ) -> List[dict]:
35
+ return self._get(
36
+ "/earnings/calendar",
37
+ params={
38
+ "scenario_id": self._scenario(scenario_id),
39
+ "ticker": ticker,
40
+ "limit": limit,
41
+ "offset": offset,
42
+ },
43
+ unwrap="earnings",
44
+ )
45
+
46
+ def tickers(self, *, scenario_id: Optional[str] = None) -> List[str]:
47
+ return self._get(
48
+ "/earnings/tickers",
49
+ params={"scenario_id": self._scenario(scenario_id)},
50
+ unwrap="tickers",
51
+ )
52
+
53
+
54
+ class Analyst(Resource):
55
+ """Sell-side analyst estimates and analyst notes."""
56
+
57
+ def estimates(
58
+ self,
59
+ ticker: str,
60
+ *,
61
+ scenario_id: Optional[str] = None,
62
+ as_of: Optional[DateLike] = None,
63
+ limit: int = 8,
64
+ offset: int = 0,
65
+ ) -> List[dict]:
66
+ return self._get(
67
+ "/analyst-estimates",
68
+ params={
69
+ "scenario_id": self._scenario(scenario_id),
70
+ "ticker": ticker,
71
+ "as_of": as_of,
72
+ "limit": limit,
73
+ "offset": offset,
74
+ },
75
+ unwrap="analyst_estimates",
76
+ )
77
+
78
+ def notes(
79
+ self,
80
+ *,
81
+ scenario_id: Optional[str] = None,
82
+ ticker: Optional[str] = None,
83
+ as_of: Optional[DateLike] = None,
84
+ start_date: Optional[DateLike] = None,
85
+ end_date: Optional[DateLike] = None,
86
+ limit: int = 50,
87
+ offset: int = 0,
88
+ ) -> List[dict]:
89
+ return self._get(
90
+ "/analyst-notes",
91
+ params={
92
+ "scenario_id": self._scenario(scenario_id),
93
+ "ticker": ticker,
94
+ "as_of": as_of,
95
+ "start_date": start_date,
96
+ "end_date": end_date,
97
+ "limit": limit,
98
+ "offset": offset,
99
+ },
100
+ unwrap="analyst_notes",
101
+ )
102
+
103
+
104
+ class Events(Resource):
105
+ """The per-scenario event timeline (catalysts, regime shifts, corporate events)."""
106
+
107
+ def timeline(
108
+ self,
109
+ *,
110
+ scenario_id: Optional[str] = None,
111
+ ticker: Optional[str] = None,
112
+ as_of: Optional[DateLike] = None,
113
+ event_type: Optional[str] = None,
114
+ start_date: Optional[DateLike] = None,
115
+ end_date: Optional[DateLike] = None,
116
+ limit: int = 100,
117
+ offset: int = 0,
118
+ ) -> List[dict]:
119
+ return self._get(
120
+ "/events/timeline",
121
+ params={
122
+ "scenario_id": self._scenario(scenario_id),
123
+ "ticker": ticker,
124
+ "as_of": as_of,
125
+ "event_type": event_type,
126
+ "start_date": start_date,
127
+ "end_date": end_date,
128
+ "limit": limit,
129
+ "offset": offset,
130
+ },
131
+ unwrap="events",
132
+ )
@@ -0,0 +1,248 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, List, Optional
4
+
5
+ from .base import Resource
6
+
7
+ DateLike = Any
8
+
9
+
10
+ class Financials(Resource):
11
+ """Financial statements, derived metrics, segments, KPIs, and the screener.
12
+
13
+ ``period`` is one of ``"annual"``, ``"quarterly"`` or ``"ttm"`` where the
14
+ endpoint supports it.
15
+ """
16
+
17
+ # -- income statements ------------------------------------------------
18
+ def income_statements(
19
+ self,
20
+ ticker: str,
21
+ *,
22
+ scenario_id: Optional[str] = None,
23
+ period: str = "annual",
24
+ report_period_gte: Optional[DateLike] = None,
25
+ report_period_lte: Optional[DateLike] = None,
26
+ limit: int = 4,
27
+ offset: int = 0,
28
+ ) -> List[dict]:
29
+ return self._get(
30
+ "/financials/income-statements",
31
+ params=self._period_params(
32
+ ticker, scenario_id, period, limit, offset, report_period_gte, report_period_lte
33
+ ),
34
+ unwrap="income_statements",
35
+ )
36
+
37
+ def balance_sheets(
38
+ self,
39
+ ticker: str,
40
+ *,
41
+ scenario_id: Optional[str] = None,
42
+ period: str = "annual",
43
+ report_period_gte: Optional[DateLike] = None,
44
+ report_period_lte: Optional[DateLike] = None,
45
+ limit: int = 4,
46
+ offset: int = 0,
47
+ ) -> List[dict]:
48
+ return self._get(
49
+ "/financials/balance-sheets",
50
+ params=self._period_params(
51
+ ticker, scenario_id, period, limit, offset, report_period_gte, report_period_lte
52
+ ),
53
+ unwrap="balance_sheets",
54
+ )
55
+
56
+ def cash_flow_statements(
57
+ self,
58
+ ticker: str,
59
+ *,
60
+ scenario_id: Optional[str] = None,
61
+ period: str = "annual",
62
+ report_period_gte: Optional[DateLike] = None,
63
+ report_period_lte: Optional[DateLike] = None,
64
+ limit: int = 4,
65
+ offset: int = 0,
66
+ ) -> List[dict]:
67
+ return self._get(
68
+ "/financials/cash-flow-statements",
69
+ params=self._period_params(
70
+ ticker, scenario_id, period, limit, offset, report_period_gte, report_period_lte
71
+ ),
72
+ unwrap="cash_flow_statements",
73
+ )
74
+
75
+ def all_statements(
76
+ self,
77
+ ticker: str,
78
+ *,
79
+ scenario_id: Optional[str] = None,
80
+ period: str = "annual",
81
+ report_period_gte: Optional[DateLike] = None,
82
+ report_period_lte: Optional[DateLike] = None,
83
+ limit: int = 4,
84
+ offset: int = 0,
85
+ ) -> dict:
86
+ """All three statements together (the ``/financials`` combined endpoint)."""
87
+ return self._get(
88
+ "/financials",
89
+ params=self._period_params(
90
+ ticker, scenario_id, period, limit, offset, report_period_gte, report_period_lte
91
+ ),
92
+ unwrap="financials",
93
+ )
94
+
95
+ # -- as-reported & segments ------------------------------------------
96
+ def as_reported(
97
+ self,
98
+ ticker: str,
99
+ *,
100
+ statement: Optional[str] = None,
101
+ scenario_id: Optional[str] = None,
102
+ period: str = "annual",
103
+ limit: int = 4,
104
+ offset: int = 0,
105
+ ) -> Any:
106
+ """As-reported line items.
107
+
108
+ ``statement`` selects one of ``"income"``, ``"balance"``, ``"cash-flow"``;
109
+ omit it for the combined ``/financials/as-reported`` view.
110
+ """
111
+ path = {
112
+ None: "/financials/as-reported",
113
+ "income": "/financials/income-statements/as-reported",
114
+ "balance": "/financials/balance-sheets/as-reported",
115
+ "cash-flow": "/financials/cash-flow-statements/as-reported",
116
+ }[statement]
117
+ return self._get(
118
+ path, params=self._period_params(ticker, scenario_id, period, limit, offset)
119
+ )
120
+
121
+ def segments(
122
+ self,
123
+ ticker: str,
124
+ *,
125
+ statement: Optional[str] = None,
126
+ scenario_id: Optional[str] = None,
127
+ period: str = "annual",
128
+ limit: int = 4,
129
+ offset: int = 0,
130
+ ) -> Any:
131
+ """Segmented financials. ``statement`` as in :meth:`as_reported`."""
132
+ path = {
133
+ None: "/financials/segments",
134
+ "income": "/financials/income-statements/segments",
135
+ "balance": "/financials/balance-sheets/segments",
136
+ "cash-flow": "/financials/cash-flow-statements/segments",
137
+ }[statement]
138
+ return self._get(
139
+ path, params=self._period_params(ticker, scenario_id, period, limit, offset)
140
+ )
141
+
142
+ # -- metrics ----------------------------------------------------------
143
+ def metrics(
144
+ self,
145
+ ticker: str,
146
+ *,
147
+ scenario_id: Optional[str] = None,
148
+ period: str = "ttm",
149
+ limit: int = 4,
150
+ offset: int = 0,
151
+ ) -> List[dict]:
152
+ """Derived ratios and per-share metrics over time."""
153
+ return self._get(
154
+ "/financial-metrics",
155
+ params=self._period_params(ticker, scenario_id, period, limit, offset),
156
+ unwrap="financial_metrics",
157
+ )
158
+
159
+ def metrics_snapshot(
160
+ self,
161
+ ticker: Optional[str] = None,
162
+ *,
163
+ scenario_id: Optional[str] = None,
164
+ as_of: Optional[DateLike] = None,
165
+ limit: int = 100,
166
+ offset: int = 0,
167
+ ) -> Any:
168
+ """Latest metric values; omit ``ticker`` for a market-wide snapshot."""
169
+ return self._get(
170
+ "/financial-metrics/snapshot",
171
+ params={
172
+ "scenario_id": self._scenario(scenario_id),
173
+ "ticker": ticker,
174
+ "as_of": as_of,
175
+ "limit": limit,
176
+ "offset": offset,
177
+ },
178
+ )
179
+
180
+ # -- KPIs -------------------------------------------------------------
181
+ def kpi_metrics(self, ticker: str, *, scenario_id: Optional[str] = None, period: str = "quarterly", limit: int = 8, offset: int = 0) -> Any:
182
+ return self._get(
183
+ "/kpi/metrics",
184
+ params=self._period_params(ticker, scenario_id, period, limit, offset),
185
+ unwrap="kpi_metrics",
186
+ )
187
+
188
+ def kpi_guidance(self, ticker: str, *, scenario_id: Optional[str] = None, period: str = "quarterly", limit: int = 8, offset: int = 0) -> Any:
189
+ return self._get(
190
+ "/kpi/guidance",
191
+ params=self._period_params(ticker, scenario_id, period, limit, offset),
192
+ unwrap="kpi_guidance",
193
+ )
194
+
195
+ def kpi_non_gaap(self, ticker: str, *, scenario_id: Optional[str] = None, period: str = "quarterly", limit: int = 8, offset: int = 0) -> Any:
196
+ return self._get(
197
+ "/kpi/non-gaap",
198
+ params=self._period_params(ticker, scenario_id, period, limit, offset),
199
+ unwrap="non_gaap",
200
+ )
201
+
202
+ # -- screener / line-item search -------------------------------------
203
+ def screener(self, filters: List[dict], *, scenario_id: Optional[str] = None, **body: Any) -> Any:
204
+ """Run the fundamentals screener.
205
+
206
+ ``filters`` is a list of ``{"field": ..., "operator": ..., "value": ...}``
207
+ clauses. See :meth:`screener_filters` for the supported fields.
208
+ """
209
+ payload = {"scenario_id": self._scenario(scenario_id), "filters": filters, **body}
210
+ return self._post("/financials/search/screener", json=payload, unwrap="results")
211
+
212
+ def line_items(self, line_items: List[str], tickers: List[str], *, scenario_id: Optional[str] = None, **body: Any) -> Any:
213
+ """Fetch specific named line items across one or more tickers."""
214
+ payload = {
215
+ "scenario_id": self._scenario(scenario_id),
216
+ "line_items": line_items,
217
+ "tickers": tickers,
218
+ **body,
219
+ }
220
+ return self._post("/financials/search/line-items", json=payload, unwrap="results")
221
+
222
+ def screener_filters(self) -> Any:
223
+ """List the fields the screener accepts."""
224
+ return self._get("/financials/search/screener/filters")
225
+
226
+ # -- helpers ----------------------------------------------------------
227
+ def _period_params(
228
+ self,
229
+ ticker: str,
230
+ scenario_id: Optional[str],
231
+ period: str,
232
+ limit: int,
233
+ offset: int,
234
+ report_period_gte: Optional[DateLike] = None,
235
+ report_period_lte: Optional[DateLike] = None,
236
+ ) -> dict:
237
+ params = {
238
+ "scenario_id": self._scenario(scenario_id),
239
+ "ticker": ticker,
240
+ "period": period,
241
+ "limit": limit,
242
+ "offset": offset,
243
+ }
244
+ if report_period_gte is not None:
245
+ params["report_period_gte"] = report_period_gte
246
+ if report_period_lte is not None:
247
+ params["report_period_lte"] = report_period_lte
248
+ return params
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, List, Optional
4
+
5
+ from .base import Resource
6
+
7
+ DateLike = Any
8
+
9
+
10
+ class Macro(Resource):
11
+ """Macro series and central-bank interest rates."""
12
+
13
+ def series(
14
+ self,
15
+ *,
16
+ scenario_id: Optional[str] = None,
17
+ start_date: Optional[DateLike] = None,
18
+ end_date: Optional[DateLike] = None,
19
+ limit: int = 1000,
20
+ offset: int = 0,
21
+ ) -> List[dict]:
22
+ """The macro panel (rates, inflation, spreads, VIX, …) over time."""
23
+ return self._get(
24
+ "/macro",
25
+ params={
26
+ "scenario_id": self._scenario(scenario_id),
27
+ "start_date": start_date,
28
+ "end_date": end_date,
29
+ "limit": limit,
30
+ "offset": offset,
31
+ },
32
+ unwrap="macro_data",
33
+ )
34
+
35
+ def interest_rates(
36
+ self,
37
+ bank: str,
38
+ *,
39
+ scenario_id: Optional[str] = None,
40
+ start_date: Optional[DateLike] = None,
41
+ end_date: Optional[DateLike] = None,
42
+ ) -> List[dict]:
43
+ """Policy-rate history for a central ``bank`` (see :meth:`banks`)."""
44
+ return self._get(
45
+ "/macro/interest-rates",
46
+ params={
47
+ "scenario_id": self._scenario(scenario_id),
48
+ "bank": bank,
49
+ "start_date": start_date,
50
+ "end_date": end_date,
51
+ },
52
+ unwrap="interest_rates",
53
+ )
54
+
55
+ def interest_rate_snapshot(
56
+ self, bank: str, *, scenario_id: Optional[str] = None, as_of: Optional[DateLike] = None
57
+ ) -> Any:
58
+ return self._get(
59
+ "/macro/interest-rates/snapshot",
60
+ params={"scenario_id": self._scenario(scenario_id), "bank": bank, "as_of": as_of},
61
+ unwrap="interest_rates",
62
+ )
63
+
64
+ def banks(self) -> List[str]:
65
+ """List the central banks with rate coverage."""
66
+ return self._get("/macro/interest-rates/banks", unwrap="banks")
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, List, Optional
4
+
5
+ from .base import Resource
6
+
7
+
8
+ class Metadata(Resource):
9
+ """API-level metadata: coverage, presets, themes, sectors, and audits."""
10
+
11
+ def sectors(self, *, scenario_id: Optional[str] = None) -> List[str]:
12
+ return self._get(
13
+ "/metadata/sectors",
14
+ params={"scenario_id": self._scenario(scenario_id)},
15
+ unwrap="sectors",
16
+ )
17
+
18
+ def scenario_themes(self) -> Any:
19
+ return self._get("/metadata/scenario-themes")
20
+
21
+ def scale_presets(self) -> Any:
22
+ return self._get("/metadata/scale-presets")
23
+
24
+ def financial_datasets_coverage(self) -> Any:
25
+ return self._get("/metadata/financial-datasets-coverage")
26
+
27
+ def institutional_readiness(self) -> Any:
28
+ return self._get("/metadata/institutional-readiness")
29
+
30
+ def synthetic_data_audit(self) -> Any:
31
+ return self._get("/metadata/synthetic-data-audit")
32
+
33
+ def empirical_calibration(self, *, panel_path: Optional[str] = None) -> Any:
34
+ return self._get(
35
+ "/metadata/empirical-calibration",
36
+ params={"panel_path": panel_path} if panel_path else None,
37
+ )