profitelligence 0.1.0__tar.gz
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.
- profitelligence-0.1.0/.gitignore +7 -0
- profitelligence-0.1.0/CHANGELOG.md +20 -0
- profitelligence-0.1.0/LICENSE +21 -0
- profitelligence-0.1.0/PKG-INFO +236 -0
- profitelligence-0.1.0/README.md +185 -0
- profitelligence-0.1.0/codegen/generate.py +304 -0
- profitelligence-0.1.0/codegen/spec.json +6943 -0
- profitelligence-0.1.0/pyproject.toml +74 -0
- profitelligence-0.1.0/src/profitelligence/__init__.py +155 -0
- profitelligence-0.1.0/src/profitelligence/_base.py +34 -0
- profitelligence-0.1.0/src/profitelligence/_http.py +347 -0
- profitelligence-0.1.0/src/profitelligence/_version.py +3 -0
- profitelligence-0.1.0/src/profitelligence/client.py +123 -0
- profitelligence-0.1.0/src/profitelligence/errors.py +185 -0
- profitelligence-0.1.0/src/profitelligence/py.typed +0 -0
- profitelligence-0.1.0/src/profitelligence/resources/__init__.py +42 -0
- profitelligence-0.1.0/src/profitelligence/resources/analytics.py +315 -0
- profitelligence-0.1.0/src/profitelligence/resources/company.py +391 -0
- profitelligence-0.1.0/src/profitelligence/resources/discovery.py +155 -0
- profitelligence-0.1.0/src/profitelligence/resources/filings.py +160 -0
- profitelligence-0.1.0/src/profitelligence/resources/financials.py +296 -0
- profitelligence-0.1.0/src/profitelligence/resources/form4.py +1130 -0
- profitelligence-0.1.0/src/profitelligence/resources/fred.py +168 -0
- profitelligence-0.1.0/src/profitelligence/resources/graph.py +128 -0
- profitelligence-0.1.0/src/profitelligence/resources/institutional.py +582 -0
- profitelligence-0.1.0/src/profitelligence/table.py +407 -0
- profitelligence-0.1.0/tests/conftest.py +28 -0
- profitelligence-0.1.0/tests/test_client.py +104 -0
- profitelligence-0.1.0/tests/test_errors.py +139 -0
- profitelligence-0.1.0/tests/test_live.py +53 -0
- profitelligence-0.1.0/tests/test_table.py +109 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
The Python client versions independently of the web app. Releases go out from
|
|
4
|
+
the public mirror at github.com/profitelligence/profitelligence-py; the
|
|
5
|
+
package itself is developed and generated upstream.
|
|
6
|
+
|
|
7
|
+
## 0.1.0 — unreleased
|
|
8
|
+
|
|
9
|
+
First release.
|
|
10
|
+
|
|
11
|
+
- A typed client over the public Profitelligence API: 68 endpoints in nine
|
|
12
|
+
namespaces, generated from the API reference so the package cannot drift
|
|
13
|
+
from the documented contract.
|
|
14
|
+
- Pipe-delimited CSV responses parse into a `Table` of typed rows. Numbers are
|
|
15
|
+
numbers, dates are dates, and empty cells are `None`.
|
|
16
|
+
- `Table.to_pandas()` for a DataFrame, behind the `[pandas]` extra.
|
|
17
|
+
- API-key auth with the `ApiKey` scheme, or guest access with no key at all.
|
|
18
|
+
- Errors say what happened: `UpgradeRequired` carries the tier message,
|
|
19
|
+
`RateLimited` carries the retry window, and an in-band `error,...` body on a
|
|
20
|
+
200 becomes `BadRequest` or `NoData` instead of a silent empty result.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Profitelligence
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: profitelligence
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: SEC filings, insider trading and market signals in Python.
|
|
5
|
+
Project-URL: Homepage, https://profitelligence.com
|
|
6
|
+
Project-URL: Documentation, https://profitelligence.com/api-reference
|
|
7
|
+
Project-URL: Changelog, https://github.com/profitelligence/profitelligence-py/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Issues, https://github.com/profitelligence/profitelligence-py/issues
|
|
9
|
+
Project-URL: Source, https://github.com/profitelligence/profitelligence-py
|
|
10
|
+
Author-email: Profitelligence <support@profitelligence.com>
|
|
11
|
+
License: MIT License
|
|
12
|
+
|
|
13
|
+
Copyright (c) 2026 Profitelligence
|
|
14
|
+
|
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
17
|
+
in the Software without restriction, including without limitation the rights
|
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
20
|
+
furnished to do so, subject to the following conditions:
|
|
21
|
+
|
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
|
23
|
+
copies or substantial portions of the Software.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Keywords: 13f,api-client,edgar,finance,form4,fred,insider-trading,institutional-holdings,market-data,quant,sec
|
|
34
|
+
Classifier: Development Status :: 4 - Beta
|
|
35
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
36
|
+
Classifier: Intended Audience :: Science/Research
|
|
37
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
38
|
+
Classifier: Operating System :: OS Independent
|
|
39
|
+
Classifier: Programming Language :: Python :: 3
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
44
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
45
|
+
Classifier: Typing :: Typed
|
|
46
|
+
Requires-Python: >=3.10
|
|
47
|
+
Requires-Dist: httpx<1,>=0.27
|
|
48
|
+
Provides-Extra: pandas
|
|
49
|
+
Requires-Dist: pandas>=2.0; extra == 'pandas'
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
|
|
52
|
+
# profitelligence
|
|
53
|
+
|
|
54
|
+
SEC filings, insider trading and market signals in Python.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install profitelligence
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import profitelligence as prof
|
|
62
|
+
|
|
63
|
+
prof.api_key("pk_live_...") # or set PROFITELLIGENCE_API_KEY
|
|
64
|
+
prices = prof.company.ohlc("AAPL", days=90) # 90 rows, typed
|
|
65
|
+
prices[0].close # 305.69, a float
|
|
66
|
+
prices.df # a DataFrame, with [pandas]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
That is the whole idea. The Profitelligence API answers in pipe-delimited CSV.
|
|
70
|
+
This package parses it, types it, and hands you rows you can work with.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## What you get
|
|
75
|
+
|
|
76
|
+
Nine namespaces cover 68 endpoints. Every method is generated from the same API
|
|
77
|
+
reference the documentation site renders, so the package cannot describe an
|
|
78
|
+
endpoint the API does not have.
|
|
79
|
+
|
|
80
|
+
| Namespace | Data |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `prof.company` | Profiles, daily prices, technical signals, corporate actions |
|
|
83
|
+
| `prof.filings` | 8-K summaries and filing patterns |
|
|
84
|
+
| `prof.form4` | Insider transactions, clusters, insider profiles |
|
|
85
|
+
| `prof.institutional` | 13F holdings, managers, crowded trades |
|
|
86
|
+
| `prof.financials` | Income statement, balance sheet, cash flow |
|
|
87
|
+
| `prof.fred` | Economic series from the Federal Reserve |
|
|
88
|
+
| `prof.discovery` | Search, spotlights, interesting companies |
|
|
89
|
+
| `prof.graph` | The knowledge graph |
|
|
90
|
+
| `prof.analytics` | Correlations, opportunity scores, strategies |
|
|
91
|
+
|
|
92
|
+
Every method carries the endpoint's own documentation. In a notebook,
|
|
93
|
+
`prof.form4.clusters?` shows the arguments, the tier it needs, and the columns
|
|
94
|
+
it returns.
|
|
95
|
+
|
|
96
|
+
## Authentication
|
|
97
|
+
|
|
98
|
+
Get a key at [profitelligence.com/account/api-keys](https://profitelligence.com/account/api-keys).
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
prof.api_key("pk_live_...") # for a notebook
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
export PROFITELLIGENCE_API_KEY=pk_live_...
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
You can also call with no key at all. Guests reach the free endpoints on the
|
|
109
|
+
top 500 symbols, which is enough to try the package before you sign up.
|
|
110
|
+
|
|
111
|
+
In a service, build a client and hold it. One client is one connection pool.
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from profitelligence import Client
|
|
115
|
+
|
|
116
|
+
with Client(api_key="pk_live_...", timeout=60) as prof:
|
|
117
|
+
holdings = prof.institutional.manager_top_holdings("0001067983")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Tables
|
|
121
|
+
|
|
122
|
+
CSV endpoints return a `Table`: named columns, typed values, one row object per
|
|
123
|
+
record. It is a normal Python sequence, so index it, slice it, and iterate it.
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
prices = prof.company.ohlc("AAPL,MSFT", days=180)
|
|
127
|
+
|
|
128
|
+
prices.columns # ['symbol', 'time', 'open', 'high', 'low', 'close']
|
|
129
|
+
len(prices) # 360
|
|
130
|
+
prices[0].close # 305.69 a float
|
|
131
|
+
prices[0].time # date(2026, 8, 17) a date
|
|
132
|
+
prices.column("close") # the whole column
|
|
133
|
+
prices.to_dicts() # plain dictionaries
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Types come from the API reference where it declares them, and from the data
|
|
137
|
+
where it does not. A column is typed as a whole: if one value will not parse,
|
|
138
|
+
the column stays text rather than becoming a mix you cannot do arithmetic on.
|
|
139
|
+
An empty cell is `None`, never `0` and never `""`.
|
|
140
|
+
|
|
141
|
+
For pandas, install the extra:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pip install 'profitelligence[pandas]'
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
frame = prices.df # or prices.to_pandas()
|
|
149
|
+
frame.set_index("time").close.resample("W").last()
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Date columns arrive as `datetime64`, so resampling and plotting work with no
|
|
153
|
+
further conversion.
|
|
154
|
+
|
|
155
|
+
JSON endpoints — the page routes, FRED, search, and the knowledge graph —
|
|
156
|
+
return the decoded body as it stands.
|
|
157
|
+
|
|
158
|
+
## When a call does not work
|
|
159
|
+
|
|
160
|
+
Errors say what happened, in the API's own words.
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
try:
|
|
164
|
+
scores = prof.analytics.opportunities()
|
|
165
|
+
except prof.UpgradeRequired as error:
|
|
166
|
+
print(error.message) # the plan this endpoint needs
|
|
167
|
+
except prof.RateLimited as error:
|
|
168
|
+
print(error.retry_after) # seconds until the window resets
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
| Error | Means |
|
|
172
|
+
|---|---|
|
|
173
|
+
| `AuthenticationError` | The key is absent, wrong, or revoked |
|
|
174
|
+
| `UpgradeRequired` | Your plan does not include this endpoint or this symbol |
|
|
175
|
+
| `RateLimited` | The window is spent. `retry_after`, `limit`, `remaining`, `reset` |
|
|
176
|
+
| `BadRequest` | An argument is missing or out of range |
|
|
177
|
+
| `NoData` | The API looked and found nothing to return |
|
|
178
|
+
| `ServerError` | The API failed. The client already retried twice |
|
|
179
|
+
| `Timeout` | No answer inside the timeout |
|
|
180
|
+
|
|
181
|
+
All of them inherit `ProfitelligenceError`.
|
|
182
|
+
|
|
183
|
+
A rate limit is never retried behind your back. A notebook that sleeps for a
|
|
184
|
+
minute without telling you is worse than an error you can see. Server errors
|
|
185
|
+
and timeouts are retried twice, with backoff.
|
|
186
|
+
|
|
187
|
+
Two of these deserve a word. The API sometimes reports a problem in-band: HTTP
|
|
188
|
+
200, with a body of `error,<message>`. Read raw, that looks like success and
|
|
189
|
+
parses to nothing. This package raises instead — `BadRequest` when you caused
|
|
190
|
+
it, `NoData` when the API simply had nothing — so an empty result never passes
|
|
191
|
+
for a real one. A genuinely empty result, which the API returns as a header row
|
|
192
|
+
with no data rows, stays an empty `Table`.
|
|
193
|
+
|
|
194
|
+
## What this package does not do
|
|
195
|
+
|
|
196
|
+
It reads. There is nothing here that writes to your account, and nothing that
|
|
197
|
+
places a trade.
|
|
198
|
+
|
|
199
|
+
It reports what filings and prices show. It does not advise, predict, or
|
|
200
|
+
recommend. What you do with the data is your decision, and a licensed advisor
|
|
201
|
+
is the right person to help you make it.
|
|
202
|
+
|
|
203
|
+
## Rate limits and tiers
|
|
204
|
+
|
|
205
|
+
Each key has a request window and a symbol list that follow your plan. Guests
|
|
206
|
+
and Free see the top 500 symbols, Pro the top 6,000, Elite all of them. A
|
|
207
|
+
symbol outside your tier raises `UpgradeRequired` with the plan it needs.
|
|
208
|
+
|
|
209
|
+
## How this package is built
|
|
210
|
+
|
|
211
|
+
The client is **generated**. The nine modules under
|
|
212
|
+
`src/profitelligence/resources/` are produced by `codegen/generate.py` from
|
|
213
|
+
`codegen/spec.json`, which is exported from the same API reference that renders
|
|
214
|
+
at [profitelligence.com/api-reference](https://profitelligence.com/api-reference).
|
|
215
|
+
That reference is the contract: an endpoint reaches this package by being
|
|
216
|
+
documented, not by someone hand-writing a signature.
|
|
217
|
+
|
|
218
|
+
Editing a generated file therefore has no lasting effect — the next generation
|
|
219
|
+
replaces it. The hand-written part is the core: `client.py`, `_http.py`,
|
|
220
|
+
`table.py` and `errors.py`.
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
uv sync --group dev
|
|
224
|
+
pytest # offline, every response mocked
|
|
225
|
+
pytest -m live # hits the public API; no key needed for the free endpoints
|
|
226
|
+
ruff check . && ruff format --check .
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Development happens in a private repository and is pushed here in one
|
|
230
|
+
direction, so a pull request cannot be merged into this tree. Bug reports are
|
|
231
|
+
genuinely useful and are acted on — see
|
|
232
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for what helps most.
|
|
233
|
+
|
|
234
|
+
## License
|
|
235
|
+
|
|
236
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# profitelligence
|
|
2
|
+
|
|
3
|
+
SEC filings, insider trading and market signals in Python.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install profitelligence
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import profitelligence as prof
|
|
11
|
+
|
|
12
|
+
prof.api_key("pk_live_...") # or set PROFITELLIGENCE_API_KEY
|
|
13
|
+
prices = prof.company.ohlc("AAPL", days=90) # 90 rows, typed
|
|
14
|
+
prices[0].close # 305.69, a float
|
|
15
|
+
prices.df # a DataFrame, with [pandas]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
That is the whole idea. The Profitelligence API answers in pipe-delimited CSV.
|
|
19
|
+
This package parses it, types it, and hands you rows you can work with.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## What you get
|
|
24
|
+
|
|
25
|
+
Nine namespaces cover 68 endpoints. Every method is generated from the same API
|
|
26
|
+
reference the documentation site renders, so the package cannot describe an
|
|
27
|
+
endpoint the API does not have.
|
|
28
|
+
|
|
29
|
+
| Namespace | Data |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `prof.company` | Profiles, daily prices, technical signals, corporate actions |
|
|
32
|
+
| `prof.filings` | 8-K summaries and filing patterns |
|
|
33
|
+
| `prof.form4` | Insider transactions, clusters, insider profiles |
|
|
34
|
+
| `prof.institutional` | 13F holdings, managers, crowded trades |
|
|
35
|
+
| `prof.financials` | Income statement, balance sheet, cash flow |
|
|
36
|
+
| `prof.fred` | Economic series from the Federal Reserve |
|
|
37
|
+
| `prof.discovery` | Search, spotlights, interesting companies |
|
|
38
|
+
| `prof.graph` | The knowledge graph |
|
|
39
|
+
| `prof.analytics` | Correlations, opportunity scores, strategies |
|
|
40
|
+
|
|
41
|
+
Every method carries the endpoint's own documentation. In a notebook,
|
|
42
|
+
`prof.form4.clusters?` shows the arguments, the tier it needs, and the columns
|
|
43
|
+
it returns.
|
|
44
|
+
|
|
45
|
+
## Authentication
|
|
46
|
+
|
|
47
|
+
Get a key at [profitelligence.com/account/api-keys](https://profitelligence.com/account/api-keys).
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
prof.api_key("pk_live_...") # for a notebook
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export PROFITELLIGENCE_API_KEY=pk_live_...
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
You can also call with no key at all. Guests reach the free endpoints on the
|
|
58
|
+
top 500 symbols, which is enough to try the package before you sign up.
|
|
59
|
+
|
|
60
|
+
In a service, build a client and hold it. One client is one connection pool.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from profitelligence import Client
|
|
64
|
+
|
|
65
|
+
with Client(api_key="pk_live_...", timeout=60) as prof:
|
|
66
|
+
holdings = prof.institutional.manager_top_holdings("0001067983")
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Tables
|
|
70
|
+
|
|
71
|
+
CSV endpoints return a `Table`: named columns, typed values, one row object per
|
|
72
|
+
record. It is a normal Python sequence, so index it, slice it, and iterate it.
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
prices = prof.company.ohlc("AAPL,MSFT", days=180)
|
|
76
|
+
|
|
77
|
+
prices.columns # ['symbol', 'time', 'open', 'high', 'low', 'close']
|
|
78
|
+
len(prices) # 360
|
|
79
|
+
prices[0].close # 305.69 a float
|
|
80
|
+
prices[0].time # date(2026, 8, 17) a date
|
|
81
|
+
prices.column("close") # the whole column
|
|
82
|
+
prices.to_dicts() # plain dictionaries
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Types come from the API reference where it declares them, and from the data
|
|
86
|
+
where it does not. A column is typed as a whole: if one value will not parse,
|
|
87
|
+
the column stays text rather than becoming a mix you cannot do arithmetic on.
|
|
88
|
+
An empty cell is `None`, never `0` and never `""`.
|
|
89
|
+
|
|
90
|
+
For pandas, install the extra:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pip install 'profitelligence[pandas]'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
frame = prices.df # or prices.to_pandas()
|
|
98
|
+
frame.set_index("time").close.resample("W").last()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Date columns arrive as `datetime64`, so resampling and plotting work with no
|
|
102
|
+
further conversion.
|
|
103
|
+
|
|
104
|
+
JSON endpoints — the page routes, FRED, search, and the knowledge graph —
|
|
105
|
+
return the decoded body as it stands.
|
|
106
|
+
|
|
107
|
+
## When a call does not work
|
|
108
|
+
|
|
109
|
+
Errors say what happened, in the API's own words.
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
try:
|
|
113
|
+
scores = prof.analytics.opportunities()
|
|
114
|
+
except prof.UpgradeRequired as error:
|
|
115
|
+
print(error.message) # the plan this endpoint needs
|
|
116
|
+
except prof.RateLimited as error:
|
|
117
|
+
print(error.retry_after) # seconds until the window resets
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| Error | Means |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `AuthenticationError` | The key is absent, wrong, or revoked |
|
|
123
|
+
| `UpgradeRequired` | Your plan does not include this endpoint or this symbol |
|
|
124
|
+
| `RateLimited` | The window is spent. `retry_after`, `limit`, `remaining`, `reset` |
|
|
125
|
+
| `BadRequest` | An argument is missing or out of range |
|
|
126
|
+
| `NoData` | The API looked and found nothing to return |
|
|
127
|
+
| `ServerError` | The API failed. The client already retried twice |
|
|
128
|
+
| `Timeout` | No answer inside the timeout |
|
|
129
|
+
|
|
130
|
+
All of them inherit `ProfitelligenceError`.
|
|
131
|
+
|
|
132
|
+
A rate limit is never retried behind your back. A notebook that sleeps for a
|
|
133
|
+
minute without telling you is worse than an error you can see. Server errors
|
|
134
|
+
and timeouts are retried twice, with backoff.
|
|
135
|
+
|
|
136
|
+
Two of these deserve a word. The API sometimes reports a problem in-band: HTTP
|
|
137
|
+
200, with a body of `error,<message>`. Read raw, that looks like success and
|
|
138
|
+
parses to nothing. This package raises instead — `BadRequest` when you caused
|
|
139
|
+
it, `NoData` when the API simply had nothing — so an empty result never passes
|
|
140
|
+
for a real one. A genuinely empty result, which the API returns as a header row
|
|
141
|
+
with no data rows, stays an empty `Table`.
|
|
142
|
+
|
|
143
|
+
## What this package does not do
|
|
144
|
+
|
|
145
|
+
It reads. There is nothing here that writes to your account, and nothing that
|
|
146
|
+
places a trade.
|
|
147
|
+
|
|
148
|
+
It reports what filings and prices show. It does not advise, predict, or
|
|
149
|
+
recommend. What you do with the data is your decision, and a licensed advisor
|
|
150
|
+
is the right person to help you make it.
|
|
151
|
+
|
|
152
|
+
## Rate limits and tiers
|
|
153
|
+
|
|
154
|
+
Each key has a request window and a symbol list that follow your plan. Guests
|
|
155
|
+
and Free see the top 500 symbols, Pro the top 6,000, Elite all of them. A
|
|
156
|
+
symbol outside your tier raises `UpgradeRequired` with the plan it needs.
|
|
157
|
+
|
|
158
|
+
## How this package is built
|
|
159
|
+
|
|
160
|
+
The client is **generated**. The nine modules under
|
|
161
|
+
`src/profitelligence/resources/` are produced by `codegen/generate.py` from
|
|
162
|
+
`codegen/spec.json`, which is exported from the same API reference that renders
|
|
163
|
+
at [profitelligence.com/api-reference](https://profitelligence.com/api-reference).
|
|
164
|
+
That reference is the contract: an endpoint reaches this package by being
|
|
165
|
+
documented, not by someone hand-writing a signature.
|
|
166
|
+
|
|
167
|
+
Editing a generated file therefore has no lasting effect — the next generation
|
|
168
|
+
replaces it. The hand-written part is the core: `client.py`, `_http.py`,
|
|
169
|
+
`table.py` and `errors.py`.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
uv sync --group dev
|
|
173
|
+
pytest # offline, every response mocked
|
|
174
|
+
pytest -m live # hits the public API; no key needed for the free endpoints
|
|
175
|
+
ruff check . && ruff format --check .
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Development happens in a private repository and is pushed here in one
|
|
179
|
+
direction, so a pull request cannot be merged into this tree. Bug reports are
|
|
180
|
+
genuinely useful and are acted on — see
|
|
181
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for what helps most.
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
MIT. See [LICENSE](LICENSE).
|