dataquery-sdk 0.1.3__tar.gz → 0.1.5__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.
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/CHANGELOG.md +5 -1
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/CONTRIBUTING.md +3 -6
- dataquery_sdk-0.1.5/PKG-INFO +502 -0
- dataquery_sdk-0.1.5/README.md +437 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/__init__.py +12 -114
- dataquery_sdk-0.1.5/dataquery/_download_utils.py +110 -0
- dataquery_sdk-0.1.5/dataquery/_mixins.py +656 -0
- dataquery_sdk-0.1.5/dataquery/_parallel_download.py +300 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/auth.py +27 -9
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/cli.py +80 -25
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/client.py +118 -827
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/config.py +7 -4
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/connection_pool.py +46 -99
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/dataquery.py +108 -464
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/exceptions.py +15 -2
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/models.py +27 -3
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/rate_limiter.py +3 -27
- dataquery_sdk-0.1.5/dataquery/sse_client.py +280 -0
- dataquery_sdk-0.1.5/dataquery/sse_subscriber.py +437 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/utils.py +4 -4
- dataquery_sdk-0.1.5/dataquery_sdk.egg-info/PKG-INFO +502 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/SOURCES.txt +5 -1
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/pyproject.toml +1 -1
- dataquery_sdk-0.1.3/PKG-INFO +0 -503
- dataquery_sdk-0.1.3/README.md +0 -438
- dataquery_sdk-0.1.3/dataquery/auto_download.py +0 -443
- dataquery_sdk-0.1.3/dataquery_sdk.egg-info/PKG-INFO +0 -503
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/LICENSE +0 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/MANIFEST.in +0 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/logging_config.py +0 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/py.typed +0 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery/retry.py +0 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/dependency_links.txt +0 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/entry_points.txt +0 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/requires.txt +0 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/top_level.txt +0 -0
- {dataquery_sdk-0.1.3 → dataquery_sdk-0.1.5}/setup.cfg +0 -0
|
@@ -22,4 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
22
22
|
## [0.1.2] - 2026-02-18
|
|
23
23
|
- File already exists status added
|
|
24
24
|
## [0.1.3] - 2026-02-21
|
|
25
|
-
- Historical file download added
|
|
25
|
+
- Historical file download added
|
|
26
|
+
## [0.1.4] - 2026-03-23
|
|
27
|
+
- Introduced circuit breaker environment variable (`DATAQUERY_CIRCUIT_BREAKER_THRESHOLD`)
|
|
28
|
+
## [0.1.5] - 2026-04-16
|
|
29
|
+
- Introduced file-group-id to the group downloads
|
|
@@ -54,9 +54,8 @@ Thank you for your interest in contributing to the DataQuery SDK! This document
|
|
|
54
54
|
|
|
55
55
|
5. Run linting and formatting:
|
|
56
56
|
```bash
|
|
57
|
-
uv run
|
|
58
|
-
uv run
|
|
59
|
-
uv run flake8 dataquery/ tests/
|
|
57
|
+
uv run ruff check dataquery/ tests/ examples/
|
|
58
|
+
uv run ruff format dataquery/ tests/ examples/
|
|
60
59
|
uv run mypy dataquery/
|
|
61
60
|
```
|
|
62
61
|
|
|
@@ -71,9 +70,7 @@ Thank you for your interest in contributing to the DataQuery SDK! This document
|
|
|
71
70
|
### Coding Standards
|
|
72
71
|
|
|
73
72
|
- **Python Style**: Follow PEP 8
|
|
74
|
-
- **Formatting**: Use
|
|
75
|
-
- **Import Sorting**: Use isort for import organization
|
|
76
|
-
- **Linting**: Use flake8 for code quality checks
|
|
73
|
+
- **Linting & Formatting**: Use [Ruff](https://github.com/astral-sh/ruff) for linting, formatting, and import sorting
|
|
77
74
|
- **Type Hints**: Use mypy for type checking
|
|
78
75
|
- **Docstrings**: Follow Google docstring format
|
|
79
76
|
|
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dataquery-sdk
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: Python SDK for DATAQUERY Data API - Query, download, and check availability of economic data files
|
|
5
|
+
Author-email: DATAQUERY SDK Team <dataquery_support@jpmorgan.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/dataquery/dataquery-sdk
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/dataquery/dataquery-sdk/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/dataquery/dataquery-sdk/wiki
|
|
9
|
+
Project-URL: Source Code, https://github.com/dataquery/dataquery-sdk
|
|
10
|
+
Keywords: dataquery,data,api,economic,financial,download,async,oauth,rate-limiting,sdk
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
25
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: aiohttp<4.0.0,>=3.8.0
|
|
30
|
+
Requires-Dist: pydantic<3.0.0,>=2.0.0
|
|
31
|
+
Requires-Dist: structlog>=23.0.0
|
|
32
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
37
|
+
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy>=1.5.0; extra == "dev"
|
|
39
|
+
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pip-audit>=2.7.0; extra == "dev"
|
|
41
|
+
Requires-Dist: build>=1.3.0; extra == "dev"
|
|
42
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
43
|
+
Provides-Extra: docs
|
|
44
|
+
Requires-Dist: mkdocs>=1.5.0; extra == "docs"
|
|
45
|
+
Requires-Dist: mkdocs-material>=9.0.0; extra == "docs"
|
|
46
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "docs"
|
|
47
|
+
Requires-Dist: mike>=1.1.0; extra == "docs"
|
|
48
|
+
Provides-Extra: pandas
|
|
49
|
+
Requires-Dist: pandas>=2.0.0; extra == "pandas"
|
|
50
|
+
Provides-Extra: all
|
|
51
|
+
Requires-Dist: pytest>=7.0.0; extra == "all"
|
|
52
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
|
|
53
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "all"
|
|
54
|
+
Requires-Dist: ruff>=0.4.0; extra == "all"
|
|
55
|
+
Requires-Dist: mypy>=1.5.0; extra == "all"
|
|
56
|
+
Requires-Dist: pre-commit>=3.0.0; extra == "all"
|
|
57
|
+
Requires-Dist: mkdocs>=1.5.0; extra == "all"
|
|
58
|
+
Requires-Dist: mkdocs-material>=9.0.0; extra == "all"
|
|
59
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "all"
|
|
60
|
+
Requires-Dist: mike>=1.1.0; extra == "all"
|
|
61
|
+
Requires-Dist: pandas>=2.0.0; extra == "all"
|
|
62
|
+
Requires-Dist: pip-audit>=2.7.0; extra == "all"
|
|
63
|
+
Requires-Dist: build>=1.3.0; extra == "all"
|
|
64
|
+
Dynamic: license-file
|
|
65
|
+
|
|
66
|
+
# DataQuery SDK
|
|
67
|
+
|
|
68
|
+
Python SDK for the J.P. Morgan DataQuery API — authenticated file downloads, time-series queries, and real-time notification-driven downloads with OAuth 2.0, rate limiting, and automatic retries built in.
|
|
69
|
+
|
|
70
|
+
[](https://www.python.org/downloads/)
|
|
71
|
+
[](https://opensource.org/licenses/MIT)
|
|
72
|
+
[](https://github.com/astral-sh/ruff)
|
|
73
|
+
|
|
74
|
+
## Features
|
|
75
|
+
|
|
76
|
+
- **Parallel file downloads** — when `num_parts > 1`, HTTP range requests split the file into parallel chunks with bounded concurrency; `num_parts=1` (default) uses a simple streaming GET
|
|
77
|
+
- **Historical and date-range downloads** — fetch every file in a group (optionally filtered to one or many `file-group-id`s) between two dates
|
|
78
|
+
- **Notification-driven downloads (SSE)** — subscribe to the `/notification` stream and auto-download files as soon as they are published
|
|
79
|
+
- **Time-series queries** — by expression, by instrument, or by group with attribute / filter projections
|
|
80
|
+
- **OAuth 2.0 with token caching and refresh** — or supply a bearer token directly
|
|
81
|
+
- **Token-bucket rate limiter** — 300 rpm / 5 tps defaults (configurable up to API limits)
|
|
82
|
+
- **Retry + circuit breaker** — exponential backoff, configurable failure threshold
|
|
83
|
+
- **Sync and async APIs** — every operation has `_async` and sync variants
|
|
84
|
+
- **Optional pandas integration** — `to_dataframe(...)` on any response
|
|
85
|
+
- **CLI** — `dataquery groups | files | availability | download | download-group | auth | config`
|
|
86
|
+
|
|
87
|
+
## Installation
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Core install
|
|
91
|
+
pip install dataquery-sdk
|
|
92
|
+
|
|
93
|
+
# With pandas DataFrame conversion
|
|
94
|
+
pip install "dataquery-sdk[pandas]"
|
|
95
|
+
|
|
96
|
+
# With dev tooling (ruff, mypy, pytest)
|
|
97
|
+
pip install "dataquery-sdk[dev]"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Python 3.10+ is required.
|
|
101
|
+
|
|
102
|
+
## Configure credentials
|
|
103
|
+
|
|
104
|
+
Set OAuth client credentials via environment variables:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
export DATAQUERY_CLIENT_ID="your_client_id"
|
|
108
|
+
export DATAQUERY_CLIENT_SECRET="your_client_secret"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Or create a `.env` file in the working directory:
|
|
112
|
+
|
|
113
|
+
```env
|
|
114
|
+
DATAQUERY_CLIENT_ID=your_client_id
|
|
115
|
+
DATAQUERY_CLIENT_SECRET=your_client_secret
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Or pass them directly to the constructor:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from dataquery import DataQuery
|
|
122
|
+
|
|
123
|
+
dq = DataQuery(client_id="...", client_secret="...")
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
A starter `.env` can be generated with `dataquery config template --output .env`.
|
|
127
|
+
|
|
128
|
+
## Quick start
|
|
129
|
+
|
|
130
|
+
### Download files for a date range
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from dataquery import DataQuery
|
|
134
|
+
|
|
135
|
+
# async
|
|
136
|
+
async with DataQuery() as dq:
|
|
137
|
+
result = await dq.run_group_download_async(
|
|
138
|
+
group_id="JPMAQS_GENERIC_RETURNS",
|
|
139
|
+
start_date="20250101",
|
|
140
|
+
end_date="20250131",
|
|
141
|
+
destination_dir="./data",
|
|
142
|
+
)
|
|
143
|
+
print(f"{result['successful_downloads']}/{result['total_files']} files downloaded")
|
|
144
|
+
|
|
145
|
+
# sync
|
|
146
|
+
with DataQuery() as dq:
|
|
147
|
+
result = dq.run_group_download(
|
|
148
|
+
group_id="JPMAQS_GENERIC_RETURNS",
|
|
149
|
+
start_date="20250101",
|
|
150
|
+
end_date="20250131",
|
|
151
|
+
destination_dir="./data",
|
|
152
|
+
)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Restrict a date-range download to specific file-group-ids
|
|
156
|
+
|
|
157
|
+
`file_group_id` accepts a single id or a list. When a list is supplied, availability
|
|
158
|
+
queries run in parallel per id and the union of dates is downloaded.
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
async with DataQuery() as dq:
|
|
162
|
+
result = await dq.run_group_download_async(
|
|
163
|
+
group_id="JPMAQS_GENERIC_RETURNS",
|
|
164
|
+
start_date="20250101",
|
|
165
|
+
end_date="20250131",
|
|
166
|
+
destination_dir="./data",
|
|
167
|
+
file_group_id=["FG_ABC", "FG_DEF", "FG_XYZ"],
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Download a single file
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from pathlib import Path
|
|
175
|
+
from dataquery import DataQuery
|
|
176
|
+
|
|
177
|
+
async with DataQuery() as dq:
|
|
178
|
+
result = await dq.download_file_async(
|
|
179
|
+
file_group_id="JPMAQS_GENERIC_RETURNS",
|
|
180
|
+
file_datetime="20250115",
|
|
181
|
+
destination_path=Path("./downloads"),
|
|
182
|
+
num_parts=5, # parallel chunks
|
|
183
|
+
)
|
|
184
|
+
print(f"Downloaded: {result.local_path} ({result.file_size} bytes)")
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Time-series queries
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
async with DataQuery() as dq:
|
|
191
|
+
# By expression
|
|
192
|
+
ts = await dq.get_expressions_time_series_async(
|
|
193
|
+
expressions=["DB(MTE,IRISH EUR 1.100 15-May-2029 LON,,IE00BH3SQ895,MIDPRC)"],
|
|
194
|
+
start_date="20240101",
|
|
195
|
+
end_date="20240131",
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# By group with attributes + filter
|
|
199
|
+
ts = await dq.get_group_time_series_async(
|
|
200
|
+
group_id="FI_GO_BO_EA",
|
|
201
|
+
attributes=["MIDPRC", "REPO_1M"],
|
|
202
|
+
filter="country(IRL)",
|
|
203
|
+
start_date="20240101",
|
|
204
|
+
end_date="20240131",
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
df = dq.to_dataframe(ts) # requires pandas extra
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Discover available data
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
async with DataQuery() as dq:
|
|
214
|
+
groups = await dq.list_groups_async(limit=100)
|
|
215
|
+
files = await dq.list_files_async(group_id="JPMAQS_GENERIC_RETURNS")
|
|
216
|
+
available = await dq.list_available_files_async(
|
|
217
|
+
group_id="JPMAQS_GENERIC_RETURNS",
|
|
218
|
+
start_date="20250101",
|
|
219
|
+
end_date="20250131",
|
|
220
|
+
)
|
|
221
|
+
instruments = await dq.search_instruments_async(
|
|
222
|
+
group_id="FI_GO_BO_EA", keywords="irish"
|
|
223
|
+
)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Auto-download (coming soon)
|
|
227
|
+
|
|
228
|
+
Real-time notification-driven downloads via the DataQuery SSE stream are under
|
|
229
|
+
active development and will be available in a future release. Once released,
|
|
230
|
+
`auto_download_async` will subscribe to the `/notification` endpoint and
|
|
231
|
+
download files automatically as they are published — no polling required.
|
|
232
|
+
|
|
233
|
+
## CLI
|
|
234
|
+
|
|
235
|
+
The installer registers a `dataquery` script:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# List / search groups
|
|
239
|
+
dataquery groups --limit 100
|
|
240
|
+
dataquery groups --search "fixed income" --json
|
|
241
|
+
|
|
242
|
+
# List files in a group
|
|
243
|
+
dataquery files --group-id JPMAQS_GENERIC_RETURNS --json
|
|
244
|
+
|
|
245
|
+
# Check availability for a single file
|
|
246
|
+
dataquery availability --file-group-id JPMAQS_GENERIC_RETURNS --file-datetime 20250115
|
|
247
|
+
|
|
248
|
+
# Download a single file
|
|
249
|
+
dataquery download --file-group-id JPMAQS_GENERIC_RETURNS \
|
|
250
|
+
--file-datetime 20250115 \
|
|
251
|
+
--destination ./downloads \
|
|
252
|
+
--num-parts 5
|
|
253
|
+
|
|
254
|
+
# Watch a group and download as new files arrive
|
|
255
|
+
dataquery download --watch --group-id JPMAQS_GENERIC_RETURNS --destination ./downloads
|
|
256
|
+
|
|
257
|
+
# Download everything in a date range
|
|
258
|
+
dataquery download-group --group-id JPMAQS_GENERIC_RETURNS \
|
|
259
|
+
--start-date 20250101 --end-date 20250131 \
|
|
260
|
+
--destination ./data \
|
|
261
|
+
--max-concurrent 5 --num-parts 4
|
|
262
|
+
|
|
263
|
+
# Restrict to one or more file-group-ids
|
|
264
|
+
dataquery download-group --group-id JPMAQS_GENERIC_RETURNS \
|
|
265
|
+
--file-group-id FG_ABC FG_DEF \
|
|
266
|
+
--start-date 20250101 --end-date 20250131
|
|
267
|
+
|
|
268
|
+
# Config utilities
|
|
269
|
+
dataquery config show
|
|
270
|
+
dataquery config validate
|
|
271
|
+
dataquery config template --output .env
|
|
272
|
+
|
|
273
|
+
# Verify auth
|
|
274
|
+
dataquery auth test
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Every subcommand accepts `--env-file PATH` (to point at a non-default `.env`) and
|
|
278
|
+
most accept `--json` for machine-readable output.
|
|
279
|
+
|
|
280
|
+
## Configuration
|
|
281
|
+
|
|
282
|
+
### Environment variables
|
|
283
|
+
|
|
284
|
+
All environment variables use the `DATAQUERY_` prefix.
|
|
285
|
+
|
|
286
|
+
**Credentials**
|
|
287
|
+
|
|
288
|
+
| Variable | Default | Notes |
|
|
289
|
+
|---|---|---|
|
|
290
|
+
| `DATAQUERY_CLIENT_ID` | _(none)_ | Required for OAuth |
|
|
291
|
+
| `DATAQUERY_CLIENT_SECRET` | _(none)_ | Required for OAuth |
|
|
292
|
+
| `DATAQUERY_BEARER_TOKEN` | _(none)_ | Alternative to OAuth |
|
|
293
|
+
| `DATAQUERY_OAUTH_ENABLED` | `true` | Set `false` to use bearer-token mode |
|
|
294
|
+
| `DATAQUERY_OAUTH_TOKEN_URL` | `https://authe.jpmorgan.com/as/token.oauth2` | |
|
|
295
|
+
| `DATAQUERY_OAUTH_AUD` | `JPMC:URI:RS-06785-DataQueryExternalApi-PROD` | |
|
|
296
|
+
|
|
297
|
+
**API endpoints**
|
|
298
|
+
|
|
299
|
+
| Variable | Default |
|
|
300
|
+
|---|---|
|
|
301
|
+
| `DATAQUERY_BASE_URL` | `https://api-developer.jpmorgan.com` |
|
|
302
|
+
| `DATAQUERY_FILES_BASE_URL` | `https://api-dataquery.jpmchase.com` |
|
|
303
|
+
| `DATAQUERY_CONTEXT_PATH` | `/research/dataquery-authe/api/v2` |
|
|
304
|
+
|
|
305
|
+
**HTTP / retry / rate limit**
|
|
306
|
+
|
|
307
|
+
| Variable | Default |
|
|
308
|
+
|---|---|
|
|
309
|
+
| `DATAQUERY_TIMEOUT` | `600.0` |
|
|
310
|
+
| `DATAQUERY_MAX_RETRIES` | `3` |
|
|
311
|
+
| `DATAQUERY_RETRY_DELAY` | `1.0` |
|
|
312
|
+
| `DATAQUERY_CIRCUIT_BREAKER_THRESHOLD` | `5` |
|
|
313
|
+
| `DATAQUERY_REQUESTS_PER_MINUTE` | `300` |
|
|
314
|
+
| `DATAQUERY_BURST_CAPACITY` | `5` |
|
|
315
|
+
| `DATAQUERY_POOL_CONNECTIONS` | `10` |
|
|
316
|
+
| `DATAQUERY_POOL_MAXSIZE` | `20` |
|
|
317
|
+
|
|
318
|
+
**Proxy** (optional)
|
|
319
|
+
|
|
320
|
+
`DATAQUERY_PROXY_ENABLED`, `DATAQUERY_PROXY_URL`, `DATAQUERY_PROXY_USERNAME`,
|
|
321
|
+
`DATAQUERY_PROXY_PASSWORD`, `DATAQUERY_PROXY_VERIFY_SSL`.
|
|
322
|
+
|
|
323
|
+
### Programmatic configuration
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
from dataquery import ClientConfig, DataQuery
|
|
327
|
+
|
|
328
|
+
config = ClientConfig(
|
|
329
|
+
client_id="...",
|
|
330
|
+
client_secret="...",
|
|
331
|
+
base_url="https://api-developer.jpmorgan.com",
|
|
332
|
+
timeout=60.0,
|
|
333
|
+
max_retries=3,
|
|
334
|
+
requests_per_minute=300,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
async with DataQuery(config) as dq:
|
|
338
|
+
...
|
|
339
|
+
|
|
340
|
+
# Or pass overrides as kwargs on top of env/.env resolution:
|
|
341
|
+
async with DataQuery(client_id="...", client_secret="...", timeout=60.0) as dq:
|
|
342
|
+
...
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Error handling
|
|
346
|
+
|
|
347
|
+
All errors inherit from `DataQueryError`:
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
from dataquery import DataQuery
|
|
351
|
+
from dataquery.exceptions import (
|
|
352
|
+
DataQueryError,
|
|
353
|
+
AuthenticationError,
|
|
354
|
+
NotFoundError,
|
|
355
|
+
RateLimitError,
|
|
356
|
+
NetworkError,
|
|
357
|
+
DownloadError,
|
|
358
|
+
ConfigurationError,
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
async with DataQuery() as dq:
|
|
362
|
+
try:
|
|
363
|
+
ts = await dq.get_expressions_time_series_async(
|
|
364
|
+
expressions=["DB(...)"], start_date="20240101", end_date="20240131"
|
|
365
|
+
)
|
|
366
|
+
except AuthenticationError:
|
|
367
|
+
... # check credentials
|
|
368
|
+
except RateLimitError:
|
|
369
|
+
... # back off — SDK already retried
|
|
370
|
+
except NotFoundError:
|
|
371
|
+
... # group / file / instrument not found
|
|
372
|
+
except NetworkError:
|
|
373
|
+
... # transient; SDK already retried
|
|
374
|
+
except DataQueryError:
|
|
375
|
+
... # any other SDK-level failure
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Date formats
|
|
379
|
+
|
|
380
|
+
```python
|
|
381
|
+
start_date="20240101" # absolute, YYYYMMDD
|
|
382
|
+
start_date="TODAY"
|
|
383
|
+
start_date="TODAY-1D" # yesterday
|
|
384
|
+
start_date="TODAY-1W"
|
|
385
|
+
start_date="TODAY-1M"
|
|
386
|
+
start_date="TODAY-1Y"
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Performance tuning
|
|
390
|
+
|
|
391
|
+
`run_group_download_async` uses a flattened concurrency model — total concurrent
|
|
392
|
+
HTTP requests = `max_concurrent × num_parts`.
|
|
393
|
+
|
|
394
|
+
With `num_parts=1` (the default) each file downloads as a single streaming GET.
|
|
395
|
+
Set `num_parts > 1` to enable parallel HTTP range requests per file — the SDK
|
|
396
|
+
probes the file size first, then downloads byte ranges concurrently. Files under
|
|
397
|
+
10 MB always use a single stream regardless of `num_parts`.
|
|
398
|
+
|
|
399
|
+
```python
|
|
400
|
+
await dq.run_group_download_async(
|
|
401
|
+
group_id="JPMAQS_GENERIC_RETURNS",
|
|
402
|
+
start_date="20250101",
|
|
403
|
+
end_date="20250131",
|
|
404
|
+
destination_dir="./data",
|
|
405
|
+
max_concurrent=5, # parallel files
|
|
406
|
+
num_parts=4, # parallel chunks per file (1 = single stream)
|
|
407
|
+
max_retries=3,
|
|
408
|
+
)
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Typical settings: `max_concurrent` 3–5, `num_parts` 2–8. The SDK automatically
|
|
412
|
+
inserts delays between file starts so the configured `requests_per_minute` is not
|
|
413
|
+
exceeded.
|
|
414
|
+
|
|
415
|
+
## API reference (most-used methods)
|
|
416
|
+
|
|
417
|
+
| Area | Method | Notes |
|
|
418
|
+
|---|---|---|
|
|
419
|
+
| Discovery | `list_groups_async(limit)` | |
|
|
420
|
+
| | `search_groups_async(keywords, limit, offset)` | |
|
|
421
|
+
| | `list_files_async(group_id, file_group_id=None)` | |
|
|
422
|
+
| | `list_available_files_async(group_id, file_group_id, start_date, end_date)` | |
|
|
423
|
+
| | `list_instruments_async(group_id, instrument_id=None, page=None)` | |
|
|
424
|
+
| | `search_instruments_async(group_id, keywords, page=None)` | |
|
|
425
|
+
| | `get_group_attributes_async(group_id, ...)` | |
|
|
426
|
+
| | `get_group_filters_async(group_id, page=None)` | |
|
|
427
|
+
| Downloads | `download_file_async(file_group_id, file_datetime, ...)` | single file |
|
|
428
|
+
| | `run_group_download_async(group_id, start_date, end_date, file_group_id=None, ...)` | date range, single or list of ids |
|
|
429
|
+
| | `download_historical_async(...)` | chunked historical backfill |
|
|
430
|
+
| | `auto_download_async(group_id, ...)` | SSE notifications (the only watch path) |
|
|
431
|
+
| Time series | `get_expressions_time_series_async(expressions, start_date, end_date)` | |
|
|
432
|
+
| | `get_instrument_time_series_async(instruments, attributes, start_date, end_date)` | |
|
|
433
|
+
| | `get_group_time_series_async(group_id, attributes, filter, start_date, end_date)` | |
|
|
434
|
+
| Grid data | `get_grid_data_async(...)` | |
|
|
435
|
+
| Utilities | `check_availability_async(file_group_id, file_datetime)` | |
|
|
436
|
+
| | `health_check_async()` | |
|
|
437
|
+
| | `to_dataframe(response)` | requires `pandas` extra |
|
|
438
|
+
| | `get_stats()` / `get_pool_stats()` / `get_rate_limit_info()` | diagnostics |
|
|
439
|
+
|
|
440
|
+
Every async method above has a sync counterpart (without the `_async` suffix, or
|
|
441
|
+
with an explicit `_sync` suffix) that runs the coroutine via `asyncio.run`.
|
|
442
|
+
|
|
443
|
+
## Examples
|
|
444
|
+
|
|
445
|
+
The `examples/` directory is organised by feature:
|
|
446
|
+
|
|
447
|
+
- `examples/files/` — single-file and date-range downloads
|
|
448
|
+
- `examples/expressions/` — expression time series
|
|
449
|
+
- `examples/instruments/` — instrument discovery + time series
|
|
450
|
+
- `examples/groups/` and `examples/groups_advanced/` — group discovery and time series
|
|
451
|
+
- `examples/grid/` — grid data
|
|
452
|
+
- `examples/system/` — SSE notification subscriber, diagnostics
|
|
453
|
+
|
|
454
|
+
Run any example directly:
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
python examples/files/download_file.py
|
|
458
|
+
python examples/system/sse_local_server_example.py
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## Development
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
# Clone
|
|
465
|
+
git clone https://github.com/jpmorganchase/dataquery-sdk.git
|
|
466
|
+
cd dataquery-sdk
|
|
467
|
+
|
|
468
|
+
# Install with dev + all extras
|
|
469
|
+
uv sync --all-extras --dev # using uv
|
|
470
|
+
# or
|
|
471
|
+
pip install -e ".[dev,pandas]"
|
|
472
|
+
|
|
473
|
+
# Run tests
|
|
474
|
+
pytest tests/ -v
|
|
475
|
+
pytest tests/ --cov=dataquery --cov-report=term-missing
|
|
476
|
+
|
|
477
|
+
# Lint / format / type-check
|
|
478
|
+
ruff check dataquery/ tests/ examples/
|
|
479
|
+
ruff format dataquery/ tests/ examples/
|
|
480
|
+
mypy dataquery/
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
Pytest markers: `slow`, `integration`, `unit`, `asyncio`.
|
|
484
|
+
|
|
485
|
+
## Requirements
|
|
486
|
+
|
|
487
|
+
- Python 3.10+
|
|
488
|
+
- `aiohttp>=3.8,<4`, `pydantic>=2,<3`, `structlog>=23`, `python-dotenv>=1`
|
|
489
|
+
- Optional: `pandas>=2` (for `to_dataframe`)
|
|
490
|
+
|
|
491
|
+
## Support
|
|
492
|
+
|
|
493
|
+
- GitHub Issues: <https://github.com/jpmorganchase/dataquery-sdk/issues>
|
|
494
|
+
- Email: dataquery_support@jpmorgan.com
|
|
495
|
+
|
|
496
|
+
## License
|
|
497
|
+
|
|
498
|
+
MIT — see [LICENSE](LICENSE).
|
|
499
|
+
|
|
500
|
+
## Changelog
|
|
501
|
+
|
|
502
|
+
See [docs/changelog.md](docs/changelog.md).
|