alphai-sdk 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.
Files changed (39) hide show
  1. alphai_sdk-0.1.0/.gitignore +26 -0
  2. alphai_sdk-0.1.0/CHANGELOG.md +21 -0
  3. alphai_sdk-0.1.0/LICENSE +21 -0
  4. alphai_sdk-0.1.0/PKG-INFO +222 -0
  5. alphai_sdk-0.1.0/README.md +186 -0
  6. alphai_sdk-0.1.0/pyproject.toml +85 -0
  7. alphai_sdk-0.1.0/src/alphai/__init__.py +110 -0
  8. alphai_sdk-0.1.0/src/alphai/_config.py +58 -0
  9. alphai_sdk-0.1.0/src/alphai/_core.py +179 -0
  10. alphai_sdk-0.1.0/src/alphai/_requests.py +155 -0
  11. alphai_sdk-0.1.0/src/alphai/_version.py +1 -0
  12. alphai_sdk-0.1.0/src/alphai/async_client.py +278 -0
  13. alphai_sdk-0.1.0/src/alphai/client.py +286 -0
  14. alphai_sdk-0.1.0/src/alphai/errors.py +124 -0
  15. alphai_sdk-0.1.0/src/alphai/models/__init__.py +69 -0
  16. alphai_sdk-0.1.0/src/alphai/models/enums.py +78 -0
  17. alphai_sdk-0.1.0/src/alphai/models/news.py +172 -0
  18. alphai_sdk-0.1.0/src/alphai/models/symbols.py +78 -0
  19. alphai_sdk-0.1.0/src/alphai/pagination.py +73 -0
  20. alphai_sdk-0.1.0/src/alphai/py.typed +0 -0
  21. alphai_sdk-0.1.0/tests/__init__.py +0 -0
  22. alphai_sdk-0.1.0/tests/conftest.py +42 -0
  23. alphai_sdk-0.1.0/tests/fixtures/article.json +71 -0
  24. alphai_sdk-0.1.0/tests/fixtures/insider_article.json +64 -0
  25. alphai_sdk-0.1.0/tests/fixtures/insider_summary.json +14 -0
  26. alphai_sdk-0.1.0/tests/fixtures/sentiment_summary.json +13 -0
  27. alphai_sdk-0.1.0/tests/fixtures/symbol.json +10 -0
  28. alphai_sdk-0.1.0/tests/fixtures/symbols_list.json +5 -0
  29. alphai_sdk-0.1.0/tests/test_async.py +82 -0
  30. alphai_sdk-0.1.0/tests/test_config.py +64 -0
  31. alphai_sdk-0.1.0/tests/test_errors.py +123 -0
  32. alphai_sdk-0.1.0/tests/test_hardening.py +186 -0
  33. alphai_sdk-0.1.0/tests/test_integration.py +50 -0
  34. alphai_sdk-0.1.0/tests/test_models.py +88 -0
  35. alphai_sdk-0.1.0/tests/test_news.py +80 -0
  36. alphai_sdk-0.1.0/tests/test_pagination.py +68 -0
  37. alphai_sdk-0.1.0/tests/test_params.py +67 -0
  38. alphai_sdk-0.1.0/tests/test_retry.py +110 -0
  39. alphai_sdk-0.1.0/tests/test_symbols.py +68 -0
@@ -0,0 +1,26 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ .python-version.local
11
+
12
+ # Tooling caches
13
+ .pytest_cache/
14
+ .mypy_cache/
15
+ .ruff_cache/
16
+ .coverage
17
+ htmlcov/
18
+
19
+ # Env / secrets
20
+ .env
21
+ *.local
22
+
23
+ # OS / editor
24
+ .DS_Store
25
+ .idea/
26
+ .vscode/
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ All notable changes to `alphai-sdk` are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres
5
+ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-06-14
10
+
11
+ ### Added
12
+ - Initial SDK: typed sync `Client` and async `AsyncClient` over the AlphaAI
13
+ public REST API (`api.alphai.io`, OpenAPI 1.5.0).
14
+ - `news` resource: `list`, `iter`, `trending`, `insider`, `insider_iter`,
15
+ `get`, `related`.
16
+ - `symbols` resource: `list`, `get`, `sentiment_summary`, `insider_summary`.
17
+ - Pydantic v2 response models, cursor auto-pagination, typed error hierarchy
18
+ (including `InvalidResponseError`), rate-limit header inspection, and automatic
19
+ retry on 429/5xx/connection errors with a bounded `Retry-After` (`max_retry_after`).
20
+ - Client-side validation of `uid` / `ticker` path segments; a custom `http_client`
21
+ still gets the SDK's auth header and base URL applied on every request.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AlphaAI
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,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: alphai-sdk
3
+ Version: 0.1.0
4
+ Summary: Python SDK for the AlphaAI financial-news REST API (api.alphai.io).
5
+ Project-URL: Homepage, https://alphai.io
6
+ Project-URL: Documentation, https://alphai.io/developers
7
+ Project-URL: API Reference, https://api.alphai.io/api/schema/
8
+ Project-URL: Changelog, https://alphai.io/changelog
9
+ Author-email: AlphaAI <support@alphai.io>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: alphai,api,financial-news,insider,sdk,sec,stocks,trading
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Financial and Insurance Industry
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: Implementation :: CPython
24
+ Classifier: Topic :: Office/Business :: Financial :: Investment
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: httpx>=0.27
28
+ Requires-Dist: pydantic>=2.7
29
+ Provides-Extra: dev
30
+ Requires-Dist: mypy>=1.10; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
32
+ Requires-Dist: pytest>=8; extra == 'dev'
33
+ Requires-Dist: respx>=0.21; extra == 'dev'
34
+ Requires-Dist: ruff>=0.6; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # alphai-sdk
38
+
39
+ Typed Python client for the [AlphaAI](https://alphai.io) financial-news REST API
40
+ — relevance-scored, ticker-linked news and SEC Form 4 insider data, built for AI
41
+ agents and trading bots.
42
+
43
+ - **Sync and async** clients (`Client` / `AsyncClient`) over `httpx`
44
+ - **Pydantic v2** response models — autocomplete, validation, `Decimal` money
45
+ - **Cursor auto-pagination**, automatic retry on 429/5xx, rate-limit inspection
46
+ - **Typed errors** and full coverage of the 9 public endpoints
47
+
48
+ API reference: <https://api.alphai.io/api/schema/> · Developer guide:
49
+ <https://alphai.io/developers>
50
+
51
+ ## Install
52
+
53
+ ```bash
54
+ pip install alphai-sdk
55
+ ```
56
+
57
+ Requires Python 3.10+. The import name is `alphai`.
58
+
59
+ ## Authentication
60
+
61
+ Create an API key at <https://alphai.io/account/api-keys>, then pass it
62
+ explicitly or via the `ALPHAI_API_KEY` environment variable.
63
+
64
+ ```python
65
+ from alphai import Client
66
+
67
+ # reads $ALPHAI_API_KEY when api_key is omitted
68
+ with Client(api_key="ak_live_…") as client:
69
+ page = client.news.list(symbol="NVDA")
70
+ for article in page.results:
71
+ print(article.title, "→", article.relevance_score)
72
+ ```
73
+
74
+ Rate limits are per account, per hour: **Free 100 · Basic 1,000 · Pro 10,000**.
75
+
76
+ ## Quickstart
77
+
78
+ ### List & filter the feed
79
+
80
+ ```python
81
+ from alphai import Client, NewsCategory
82
+
83
+ with Client() as client:
84
+ page = client.news.list(
85
+ symbol="NVDA",
86
+ category=[NewsCategory.EARNINGS, "insider"], # enum or str; OR-matched
87
+ min_relevance=7,
88
+ collapse_stories=True, # dedupe syndicated reprints
89
+ )
90
+ print(page.next_cursor) # opaque cursor for the next (older) page
91
+ print(page.has_more)
92
+ ```
93
+
94
+ ### Auto-paginate
95
+
96
+ `iter()` follows the cursor for you and flattens articles across pages:
97
+
98
+ ```python
99
+ with Client() as client:
100
+ for article in client.news.iter(category="earnings", max_items=100):
101
+ print(article.uid, article.title)
102
+ ```
103
+
104
+ ### Single article, trending, related, insider
105
+
106
+ ```python
107
+ with Client() as client:
108
+ client.news.trending() # top ≤10 from the last 48h
109
+ art = client.news.get("788e477c66f3849b")
110
+ client.news.related(art.uid) # up to 6 related articles
111
+ client.news.insider(symbol="NVDA") # SEC Form 4 feed (or .insider_iter())
112
+ ```
113
+
114
+ ### Symbols & rollups
115
+
116
+ ```python
117
+ from decimal import Decimal
118
+
119
+ with Client() as client:
120
+ client.symbols.list(limit=100) # active tickers (bare list)
121
+ nvda = client.symbols.get("NVDA") # detail (404 if unknown)
122
+ sent = client.symbols.sentiment_summary("NVDA") # 7-day AI sentiment
123
+ ins = client.symbols.insider_summary("NVDA") # 30-day Form 4 rollup
124
+ assert isinstance(ins.buy_value_usd, Decimal | None) # money is Decimal
125
+ ```
126
+
127
+ ### Async
128
+
129
+ Every method mirrors the sync client with `await`; `iter()` is an async generator:
130
+
131
+ ```python
132
+ import asyncio
133
+ from alphai import AsyncClient
134
+
135
+ async def main() -> None:
136
+ async with AsyncClient() as client:
137
+ async for article in client.news.iter(symbol="NVDA", max_items=20):
138
+ print(article.title)
139
+
140
+ asyncio.run(main())
141
+ ```
142
+
143
+ ## Errors
144
+
145
+ All errors derive from `AlphaAIError`:
146
+
147
+ ```python
148
+ from alphai import Client, RateLimitError, NotFoundError, AuthenticationError
149
+
150
+ with Client() as client:
151
+ try:
152
+ client.symbols.get("ZZZZ")
153
+ except NotFoundError:
154
+ ...
155
+ except RateLimitError as e:
156
+ print("retry after", e.retry_after, "seconds; limit", e.limit)
157
+ except AuthenticationError:
158
+ ...
159
+ ```
160
+
161
+ | Status | Exception |
162
+ |--------|-----------|
163
+ | 400 | `BadRequestError` (`.fields` for validation errors) |
164
+ | 401 | `AuthenticationError` |
165
+ | 403 | `PermissionDeniedError` |
166
+ | 404 | `NotFoundError` |
167
+ | 429 | `RateLimitError` (`.retry_after`, `.limit`, `.remaining`, `.reset`) |
168
+ | 5xx | `ServerError` |
169
+ | network/timeout | `APIConnectionError` |
170
+ | 2xx, unparseable body | `InvalidResponseError` |
171
+
172
+ GET requests are automatically retried on 429 / 5xx / connection errors
173
+ (`max_retries`, default 2) with jittered backoff that honors `Retry-After` (capped
174
+ at `max_retry_after`, default 60s, so a bad value can't freeze your process). A
175
+ 2xx with a non-JSON / empty body raises `InvalidResponseError`.
176
+
177
+ ## Rate-limit budget
178
+
179
+ Every keyed response carries the `X-RateLimit-*` trio. The last one seen is on
180
+ the client:
181
+
182
+ ```python
183
+ with Client() as client:
184
+ client.news.list()
185
+ rl = client.last_rate_limit
186
+ if rl:
187
+ print(f"{rl.remaining}/{rl.limit} left, resets at {rl.reset}")
188
+ ```
189
+
190
+ ## Configuration
191
+
192
+ ```python
193
+ Client(
194
+ api_key=None, # else $ALPHAI_API_KEY
195
+ base_url="https://api.alphai.io", # API host
196
+ timeout=30.0,
197
+ max_retries=2, # clamped to >= 0
198
+ backoff_factor=0.5,
199
+ max_retry_after=60.0, # cap on honored Retry-After (seconds)
200
+ user_agent="alphai-sdk-python/<version>",
201
+ http_client=None, # bring your own httpx.Client (advanced)
202
+ )
203
+ ```
204
+
205
+ The same keyword arguments apply to `AsyncClient`. When you pass a custom
206
+ `http_client`, the SDK **still applies its `Authorization` header and base URL on
207
+ every request** — your client just supplies the transport (proxies, custom
208
+ timeout, mounts). You own its lifecycle (the SDK won't close a client you passed in).
209
+
210
+ ## Development
211
+
212
+ ```bash
213
+ uv venv && uv pip install -e ".[dev]"
214
+ ruff check . && ruff format --check .
215
+ mypy src/alphai
216
+ pytest # offline suite
217
+ pytest -m integration # live tests (needs ALPHAI_API_KEY)
218
+ ```
219
+
220
+ ## License
221
+
222
+ MIT — see [LICENSE](LICENSE). API access still requires a valid key.
@@ -0,0 +1,186 @@
1
+ # alphai-sdk
2
+
3
+ Typed Python client for the [AlphaAI](https://alphai.io) financial-news REST API
4
+ — relevance-scored, ticker-linked news and SEC Form 4 insider data, built for AI
5
+ agents and trading bots.
6
+
7
+ - **Sync and async** clients (`Client` / `AsyncClient`) over `httpx`
8
+ - **Pydantic v2** response models — autocomplete, validation, `Decimal` money
9
+ - **Cursor auto-pagination**, automatic retry on 429/5xx, rate-limit inspection
10
+ - **Typed errors** and full coverage of the 9 public endpoints
11
+
12
+ API reference: <https://api.alphai.io/api/schema/> · Developer guide:
13
+ <https://alphai.io/developers>
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ pip install alphai-sdk
19
+ ```
20
+
21
+ Requires Python 3.10+. The import name is `alphai`.
22
+
23
+ ## Authentication
24
+
25
+ Create an API key at <https://alphai.io/account/api-keys>, then pass it
26
+ explicitly or via the `ALPHAI_API_KEY` environment variable.
27
+
28
+ ```python
29
+ from alphai import Client
30
+
31
+ # reads $ALPHAI_API_KEY when api_key is omitted
32
+ with Client(api_key="ak_live_…") as client:
33
+ page = client.news.list(symbol="NVDA")
34
+ for article in page.results:
35
+ print(article.title, "→", article.relevance_score)
36
+ ```
37
+
38
+ Rate limits are per account, per hour: **Free 100 · Basic 1,000 · Pro 10,000**.
39
+
40
+ ## Quickstart
41
+
42
+ ### List & filter the feed
43
+
44
+ ```python
45
+ from alphai import Client, NewsCategory
46
+
47
+ with Client() as client:
48
+ page = client.news.list(
49
+ symbol="NVDA",
50
+ category=[NewsCategory.EARNINGS, "insider"], # enum or str; OR-matched
51
+ min_relevance=7,
52
+ collapse_stories=True, # dedupe syndicated reprints
53
+ )
54
+ print(page.next_cursor) # opaque cursor for the next (older) page
55
+ print(page.has_more)
56
+ ```
57
+
58
+ ### Auto-paginate
59
+
60
+ `iter()` follows the cursor for you and flattens articles across pages:
61
+
62
+ ```python
63
+ with Client() as client:
64
+ for article in client.news.iter(category="earnings", max_items=100):
65
+ print(article.uid, article.title)
66
+ ```
67
+
68
+ ### Single article, trending, related, insider
69
+
70
+ ```python
71
+ with Client() as client:
72
+ client.news.trending() # top ≤10 from the last 48h
73
+ art = client.news.get("788e477c66f3849b")
74
+ client.news.related(art.uid) # up to 6 related articles
75
+ client.news.insider(symbol="NVDA") # SEC Form 4 feed (or .insider_iter())
76
+ ```
77
+
78
+ ### Symbols & rollups
79
+
80
+ ```python
81
+ from decimal import Decimal
82
+
83
+ with Client() as client:
84
+ client.symbols.list(limit=100) # active tickers (bare list)
85
+ nvda = client.symbols.get("NVDA") # detail (404 if unknown)
86
+ sent = client.symbols.sentiment_summary("NVDA") # 7-day AI sentiment
87
+ ins = client.symbols.insider_summary("NVDA") # 30-day Form 4 rollup
88
+ assert isinstance(ins.buy_value_usd, Decimal | None) # money is Decimal
89
+ ```
90
+
91
+ ### Async
92
+
93
+ Every method mirrors the sync client with `await`; `iter()` is an async generator:
94
+
95
+ ```python
96
+ import asyncio
97
+ from alphai import AsyncClient
98
+
99
+ async def main() -> None:
100
+ async with AsyncClient() as client:
101
+ async for article in client.news.iter(symbol="NVDA", max_items=20):
102
+ print(article.title)
103
+
104
+ asyncio.run(main())
105
+ ```
106
+
107
+ ## Errors
108
+
109
+ All errors derive from `AlphaAIError`:
110
+
111
+ ```python
112
+ from alphai import Client, RateLimitError, NotFoundError, AuthenticationError
113
+
114
+ with Client() as client:
115
+ try:
116
+ client.symbols.get("ZZZZ")
117
+ except NotFoundError:
118
+ ...
119
+ except RateLimitError as e:
120
+ print("retry after", e.retry_after, "seconds; limit", e.limit)
121
+ except AuthenticationError:
122
+ ...
123
+ ```
124
+
125
+ | Status | Exception |
126
+ |--------|-----------|
127
+ | 400 | `BadRequestError` (`.fields` for validation errors) |
128
+ | 401 | `AuthenticationError` |
129
+ | 403 | `PermissionDeniedError` |
130
+ | 404 | `NotFoundError` |
131
+ | 429 | `RateLimitError` (`.retry_after`, `.limit`, `.remaining`, `.reset`) |
132
+ | 5xx | `ServerError` |
133
+ | network/timeout | `APIConnectionError` |
134
+ | 2xx, unparseable body | `InvalidResponseError` |
135
+
136
+ GET requests are automatically retried on 429 / 5xx / connection errors
137
+ (`max_retries`, default 2) with jittered backoff that honors `Retry-After` (capped
138
+ at `max_retry_after`, default 60s, so a bad value can't freeze your process). A
139
+ 2xx with a non-JSON / empty body raises `InvalidResponseError`.
140
+
141
+ ## Rate-limit budget
142
+
143
+ Every keyed response carries the `X-RateLimit-*` trio. The last one seen is on
144
+ the client:
145
+
146
+ ```python
147
+ with Client() as client:
148
+ client.news.list()
149
+ rl = client.last_rate_limit
150
+ if rl:
151
+ print(f"{rl.remaining}/{rl.limit} left, resets at {rl.reset}")
152
+ ```
153
+
154
+ ## Configuration
155
+
156
+ ```python
157
+ Client(
158
+ api_key=None, # else $ALPHAI_API_KEY
159
+ base_url="https://api.alphai.io", # API host
160
+ timeout=30.0,
161
+ max_retries=2, # clamped to >= 0
162
+ backoff_factor=0.5,
163
+ max_retry_after=60.0, # cap on honored Retry-After (seconds)
164
+ user_agent="alphai-sdk-python/<version>",
165
+ http_client=None, # bring your own httpx.Client (advanced)
166
+ )
167
+ ```
168
+
169
+ The same keyword arguments apply to `AsyncClient`. When you pass a custom
170
+ `http_client`, the SDK **still applies its `Authorization` header and base URL on
171
+ every request** — your client just supplies the transport (proxies, custom
172
+ timeout, mounts). You own its lifecycle (the SDK won't close a client you passed in).
173
+
174
+ ## Development
175
+
176
+ ```bash
177
+ uv venv && uv pip install -e ".[dev]"
178
+ ruff check . && ruff format --check .
179
+ mypy src/alphai
180
+ pytest # offline suite
181
+ pytest -m integration # live tests (needs ALPHAI_API_KEY)
182
+ ```
183
+
184
+ ## License
185
+
186
+ MIT — see [LICENSE](LICENSE). API access still requires a valid key.
@@ -0,0 +1,85 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "alphai-sdk"
7
+ dynamic = ["version"]
8
+ description = "Python SDK for the AlphaAI financial-news REST API (api.alphai.io)."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ authors = [{ name = "AlphaAI", email = "support@alphai.io" }]
14
+ keywords = ["alphai", "financial-news", "stocks", "sec", "insider", "trading", "api", "sdk"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "Intended Audience :: Financial and Insurance Industry",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Programming Language :: Python :: Implementation :: CPython",
27
+ "Topic :: Office/Business :: Financial :: Investment",
28
+ "Typing :: Typed",
29
+ ]
30
+ dependencies = [
31
+ "httpx>=0.27",
32
+ "pydantic>=2.7",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://alphai.io"
37
+ Documentation = "https://alphai.io/developers"
38
+ "API Reference" = "https://api.alphai.io/api/schema/"
39
+ Changelog = "https://alphai.io/changelog"
40
+
41
+ [project.optional-dependencies]
42
+ dev = [
43
+ "pytest>=8",
44
+ "pytest-asyncio>=0.23",
45
+ "respx>=0.21",
46
+ "ruff>=0.6",
47
+ "mypy>=1.10",
48
+ ]
49
+
50
+ [tool.hatch.version]
51
+ path = "src/alphai/_version.py"
52
+
53
+ [tool.hatch.build.targets.wheel]
54
+ packages = ["src/alphai"]
55
+
56
+ [tool.hatch.build.targets.sdist]
57
+ include = ["/src", "/tests", "/README.md", "/LICENSE", "/CHANGELOG.md"]
58
+
59
+ [tool.ruff]
60
+ line-length = 100
61
+ target-version = "py310"
62
+ src = ["src", "tests"]
63
+
64
+ [tool.ruff.lint]
65
+ select = ["E", "F", "I", "UP", "B", "SIM", "C4", "PIE", "RUF"]
66
+ ignore = ["B008"]
67
+
68
+ [tool.ruff.lint.per-file-ignores]
69
+ "tests/**" = ["S101"]
70
+ # Grouped, commented __all__ in package __init__ files reads better than a flat sort.
71
+ "**/__init__.py" = ["RUF022"]
72
+
73
+ [tool.mypy]
74
+ python_version = "3.10"
75
+ strict = true
76
+ files = ["src/alphai"]
77
+ plugins = ["pydantic.mypy"]
78
+
79
+ [tool.pytest.ini_options]
80
+ testpaths = ["tests"]
81
+ asyncio_mode = "auto"
82
+ markers = [
83
+ "integration: hits the live api.alphai.io (needs ALPHAI_API_KEY); skipped by default",
84
+ ]
85
+ addopts = "-m 'not integration'"
@@ -0,0 +1,110 @@
1
+ """alphai — Python SDK for the AlphaAI financial-news REST API.
2
+
3
+ Quickstart::
4
+
5
+ from alphai import Client
6
+
7
+ with Client(api_key="ak_live_…") as client: # or $ALPHAI_API_KEY
8
+ for article in client.news.iter(symbol="NVDA", max_items=20):
9
+ print(article.title, article.relevance_score)
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from ._config import API_KEY_ENV_VAR, DEFAULT_BASE_URL, ClientConfig
15
+ from ._core import RateLimit
16
+ from ._version import __version__
17
+ from .async_client import AsyncClient, AsyncNewsResource, AsyncSymbolsResource
18
+ from .client import Client, NewsResource, SymbolsResource
19
+ from .errors import (
20
+ AlphaAIError,
21
+ APIConnectionError,
22
+ APIStatusError,
23
+ AuthenticationError,
24
+ BadRequestError,
25
+ InvalidResponseError,
26
+ MissingAPIKeyError,
27
+ NotFoundError,
28
+ PermissionDeniedError,
29
+ RateLimitError,
30
+ ServerError,
31
+ )
32
+ from .models import (
33
+ Actionability,
34
+ AITradingInsights,
35
+ AlternativePerspectives,
36
+ Confidence,
37
+ DailySentimentBucket,
38
+ EnrichedArticle,
39
+ ImpactAnalysis,
40
+ IndirectMarketEffects,
41
+ KeyEntity,
42
+ NewsCategory,
43
+ NewsContextEnhancement,
44
+ NewsPage,
45
+ NewsPagination,
46
+ NewsTradingValue,
47
+ OriginalArticle,
48
+ RichNewsArticle,
49
+ Sentiment,
50
+ Symbol,
51
+ TickerAnalysis,
52
+ TickerInsiderSummary,
53
+ TickerSentimentSummary,
54
+ Topic,
55
+ TopInsider,
56
+ )
57
+
58
+ __all__ = [
59
+ "__version__",
60
+ # clients
61
+ "Client",
62
+ "AsyncClient",
63
+ "NewsResource",
64
+ "SymbolsResource",
65
+ "AsyncNewsResource",
66
+ "AsyncSymbolsResource",
67
+ # config / misc
68
+ "ClientConfig",
69
+ "RateLimit",
70
+ "DEFAULT_BASE_URL",
71
+ "API_KEY_ENV_VAR",
72
+ # errors
73
+ "AlphaAIError",
74
+ "MissingAPIKeyError",
75
+ "InvalidResponseError",
76
+ "APIConnectionError",
77
+ "APIStatusError",
78
+ "BadRequestError",
79
+ "AuthenticationError",
80
+ "PermissionDeniedError",
81
+ "NotFoundError",
82
+ "RateLimitError",
83
+ "ServerError",
84
+ # enums
85
+ "NewsCategory",
86
+ "Sentiment",
87
+ "Confidence",
88
+ "Actionability",
89
+ # news models
90
+ "Topic",
91
+ "ImpactAnalysis",
92
+ "TickerAnalysis",
93
+ "NewsTradingValue",
94
+ "IndirectMarketEffects",
95
+ "AlternativePerspectives",
96
+ "KeyEntity",
97
+ "AITradingInsights",
98
+ "NewsContextEnhancement",
99
+ "OriginalArticle",
100
+ "EnrichedArticle",
101
+ "RichNewsArticle",
102
+ "NewsPagination",
103
+ "NewsPage",
104
+ # symbol models
105
+ "Symbol",
106
+ "DailySentimentBucket",
107
+ "TickerSentimentSummary",
108
+ "TopInsider",
109
+ "TickerInsiderSummary",
110
+ ]