unique-quartr 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.
- unique_quartr-0.1.0/CHANGELOG.md +9 -0
- unique_quartr-0.1.0/LICENSE +1 -0
- unique_quartr-0.1.0/PKG-INFO +480 -0
- unique_quartr-0.1.0/README.md +454 -0
- unique_quartr-0.1.0/pyproject.toml +32 -0
- unique_quartr-0.1.0/unique_quartr/constants/document_types.py +75 -0
- unique_quartr-0.1.0/unique_quartr/constants/event_types.py +151 -0
- unique_quartr-0.1.0/unique_quartr/endpoints/api.py +62 -0
- unique_quartr-0.1.0/unique_quartr/endpoints/schemas.py +723 -0
- unique_quartr-0.1.0/unique_quartr/service.py +158 -0
- unique_quartr-0.1.0/unique_quartr/settings.py +46 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2025-08-18
|
|
9
|
+
- Initial release of `unique_quartr`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
`unique_toolkit` is covered by the [`Unique License v1`](https://github.com/Unique-AG/license/releases/tag/unique-license.v1), unless the/a header or a nested LICENSE specifies another license.
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: unique_quartr
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary:
|
|
5
|
+
License: Proprietary
|
|
6
|
+
Author: Rami Azouz
|
|
7
|
+
Author-email: rami.ext@unique.ch
|
|
8
|
+
Requires-Python: >=3.12,<4.0
|
|
9
|
+
Classifier: License :: Other/Proprietary License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Requires-Dist: pydantic (>=2.12.4,<3.0.0)
|
|
14
|
+
Requires-Dist: unique-toolkit (>=1.24.1,<2.0.0)
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# Unique Quartr Connector
|
|
18
|
+
|
|
19
|
+
A Python connector library for the [Quartr API](https://quartr.com), providing easy access to company events, documents, and financial data.
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- 🔍 Fetch company earnings calls and events
|
|
24
|
+
- 📄 Retrieve event documents (transcripts, reports, slides, etc.)
|
|
25
|
+
- 🎯 Type-safe API with Pydantic models
|
|
26
|
+
- 🔄 Automatic pagination handling
|
|
27
|
+
- 📊 Support for multiple document and event types
|
|
28
|
+
- 🔐 Secure API key authentication
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
poetry add unique_quartr
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or using pip:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install unique_quartr
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Configuration
|
|
43
|
+
|
|
44
|
+
### Environment Variables
|
|
45
|
+
|
|
46
|
+
Create a `.env` file in your project root with your Quartr API credentials:
|
|
47
|
+
|
|
48
|
+
```env
|
|
49
|
+
QUARTR_API_CREDS='{"api_key": "your_api_key_here", "valid_to": "2025-12-31"}'
|
|
50
|
+
QUARTR_API_ACTIVATED_COMPANIES='["company_id_1", "company_id_2"]'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Test Environment
|
|
54
|
+
|
|
55
|
+
For testing, create `tests/test.env`:
|
|
56
|
+
|
|
57
|
+
```env
|
|
58
|
+
QUARTR_API_CREDS='{"api_key": "test_api_key", "valid_to": "2025-12-31"}'
|
|
59
|
+
QUARTR_API_ACTIVATED_COMPANIES='["test_company"]'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
### Basic Usage
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from unique_quartr.service import QuartrService
|
|
68
|
+
from unique_quartr.constants.event_types import EventType
|
|
69
|
+
from unique_quartr.constants.document_types import DocumentType
|
|
70
|
+
from unique_toolkit._common.endpoint_requestor import RequestorType
|
|
71
|
+
|
|
72
|
+
# Initialize the service
|
|
73
|
+
service = QuartrService(
|
|
74
|
+
company_id="your_company_id",
|
|
75
|
+
requestor_type=RequestorType.REQUESTS,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Define the event types you want to fetch
|
|
79
|
+
event_types = [EventType.EARNINGS_CALL]
|
|
80
|
+
event_ids = service.get_event_subtype_ids_from_event_types(event_types)
|
|
81
|
+
|
|
82
|
+
# Fetch company events
|
|
83
|
+
events = service.fetch_company_events(
|
|
84
|
+
ticker="AAPL",
|
|
85
|
+
exchange="NasdaqGS",
|
|
86
|
+
country="US",
|
|
87
|
+
event_ids=event_ids,
|
|
88
|
+
start_date="2024-01-01",
|
|
89
|
+
end_date="2024-12-31",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
print(f"Found {len(events)} events")
|
|
93
|
+
for event in events:
|
|
94
|
+
print(f"Event: {event['title']} - {event['date']}")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Fetching Documents
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
# Get event IDs from the events you fetched
|
|
101
|
+
event_ids = [event["id"] for event in events]
|
|
102
|
+
|
|
103
|
+
# Define document types you want
|
|
104
|
+
document_types = [DocumentType.TRANSCRIPT, DocumentType.SLIDES]
|
|
105
|
+
document_ids = service.get_document_ids_from_document_types(document_types)
|
|
106
|
+
|
|
107
|
+
# Fetch documents for these events
|
|
108
|
+
documents = service.fetch_event_documents(
|
|
109
|
+
event_ids=event_ids,
|
|
110
|
+
document_ids=document_ids,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
print(f"Found {len(documents)} documents")
|
|
114
|
+
for doc in documents:
|
|
115
|
+
print(f"Document: {doc['type_id']} - {doc['file_url']}")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Event Types
|
|
119
|
+
|
|
120
|
+
The library supports the following event types:
|
|
121
|
+
|
|
122
|
+
- **Earnings Call**: Q1, Q2, Q3, Q4, H1, H2
|
|
123
|
+
- **Analyst Day**
|
|
124
|
+
- **Annual General Meeting**: AGM, Scheme Meeting
|
|
125
|
+
- **Business Combination**
|
|
126
|
+
- **C-level Sitdown**: C-level Sitdown, CEO Sitdown
|
|
127
|
+
- **Capital Markets Day**
|
|
128
|
+
- **Capital Raise**
|
|
129
|
+
- **Conference**
|
|
130
|
+
- **Extraordinary General Meeting**
|
|
131
|
+
- **FDA Announcement**
|
|
132
|
+
- **Fireside Chat**
|
|
133
|
+
- **Investor Day**
|
|
134
|
+
- **M&A Announcement**
|
|
135
|
+
- **Outlook / Guidance Update**
|
|
136
|
+
- **Partnerships / Collaborations**: Partnership, Collaboration
|
|
137
|
+
- **Product / Service Launch**: Product Launch, Service Launch
|
|
138
|
+
- **Slides**: Investor Presentation, Corporate Presentation, Company Presentation
|
|
139
|
+
- **Trading Update**
|
|
140
|
+
- **Update / Briefing**: Status Update, Investor Update, ESG Update, Study Update, Study Result, KOL Event
|
|
141
|
+
|
|
142
|
+
### Example: Getting Earnings Call Event IDs
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from unique_quartr.constants.event_types import EventType
|
|
146
|
+
|
|
147
|
+
event_types = [EventType.EARNINGS_CALL]
|
|
148
|
+
event_ids = QuartrService.get_event_subtype_ids_from_event_types(event_types)
|
|
149
|
+
# Returns: [26, 27, 28, 29, 35, 36] (Q1, Q2, Q3, Q4, H1, H2)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Document Types
|
|
153
|
+
|
|
154
|
+
The library supports various document types:
|
|
155
|
+
|
|
156
|
+
- **Slides** 📊
|
|
157
|
+
- **Report** 📄
|
|
158
|
+
- **Quarterly Report (10-Q)** 📑
|
|
159
|
+
- **Earnings Release (8-K)** 📢
|
|
160
|
+
- **Annual Report (10-K)** 📘
|
|
161
|
+
- **Annual Report (20-F)** 📙
|
|
162
|
+
- **Annual Report (40-F)** 📕
|
|
163
|
+
- **Earnings Release (6-K)** 📣
|
|
164
|
+
- **Transcript** 🗒️
|
|
165
|
+
- **Interim Report** 📜
|
|
166
|
+
- **Press Release** 🗞️
|
|
167
|
+
- **Earnings Release** 💰
|
|
168
|
+
- **In-house Transcript** 🎤
|
|
169
|
+
|
|
170
|
+
### Example: Getting Document Type Information
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from unique_quartr.constants.document_types import DocumentType
|
|
174
|
+
|
|
175
|
+
doc_type = DocumentType.QUARTERLY_REPORT_10Q
|
|
176
|
+
|
|
177
|
+
print(doc_type.name) # "Quarterly report"
|
|
178
|
+
print(doc_type.form) # "10-Q"
|
|
179
|
+
print(doc_type.emoji) # "📑"
|
|
180
|
+
print(doc_type.get_file_prefix()) # "Quarterly report (10-Q)"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Advanced Usage
|
|
184
|
+
|
|
185
|
+
### Custom Pagination
|
|
186
|
+
|
|
187
|
+
Control pagination parameters for large datasets:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
events = service.fetch_company_events(
|
|
191
|
+
ticker="AAPL",
|
|
192
|
+
exchange="NasdaqGS",
|
|
193
|
+
country="US",
|
|
194
|
+
event_ids=event_ids,
|
|
195
|
+
limit=100, # Items per page (max 500)
|
|
196
|
+
max_iteration=10, # Maximum number of pages
|
|
197
|
+
)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Filtering by Date Range
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
events = service.fetch_company_events(
|
|
204
|
+
ticker="AAPL",
|
|
205
|
+
exchange="NasdaqGS",
|
|
206
|
+
country="US",
|
|
207
|
+
event_ids=event_ids,
|
|
208
|
+
start_date="2024-01-01T00:00:00Z", # ISO format
|
|
209
|
+
end_date="2024-03-31T23:59:59Z",
|
|
210
|
+
)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Fetching Multiple Event Types
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
from unique_quartr.constants.event_types import EventType
|
|
217
|
+
|
|
218
|
+
# Combine multiple event types
|
|
219
|
+
event_types = [
|
|
220
|
+
EventType.EARNINGS_CALL,
|
|
221
|
+
EventType.ANALYST_DAY,
|
|
222
|
+
EventType.INVESTOR_DAY,
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
event_ids = QuartrService.get_event_subtype_ids_from_event_types(event_types)
|
|
226
|
+
|
|
227
|
+
events = service.fetch_company_events(
|
|
228
|
+
ticker="AAPL",
|
|
229
|
+
exchange="NasdaqGS",
|
|
230
|
+
country="US",
|
|
231
|
+
event_ids=event_ids,
|
|
232
|
+
)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## API Reference
|
|
236
|
+
|
|
237
|
+
### QuartrService
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
class QuartrService:
|
|
241
|
+
def __init__(
|
|
242
|
+
self,
|
|
243
|
+
*,
|
|
244
|
+
company_id: str,
|
|
245
|
+
requestor_type: RequestorType,
|
|
246
|
+
):
|
|
247
|
+
"""
|
|
248
|
+
Initialize the Quartr service.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
company_id: Company identifier for API access
|
|
252
|
+
requestor_type: Type of requestor (SYNC or ASYNC)
|
|
253
|
+
"""
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### Methods
|
|
257
|
+
|
|
258
|
+
##### fetch_company_events
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
def fetch_company_events(
|
|
262
|
+
self,
|
|
263
|
+
ticker: str,
|
|
264
|
+
exchange: str,
|
|
265
|
+
country: str,
|
|
266
|
+
event_ids: list[int],
|
|
267
|
+
start_date: str | None = None,
|
|
268
|
+
end_date: str | None = None,
|
|
269
|
+
limit: int = 500,
|
|
270
|
+
max_iteration: int = 20,
|
|
271
|
+
) -> list[EventDto]:
|
|
272
|
+
"""
|
|
273
|
+
Retrieve events for a given company.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
ticker: Company ticker symbol (e.g., 'AAPL', 'AMZN')
|
|
277
|
+
exchange: Exchange code (e.g., 'NasdaqGS', 'NYSE')
|
|
278
|
+
country: Country code (e.g., 'US', 'CA')
|
|
279
|
+
event_ids: List of event type IDs to filter
|
|
280
|
+
start_date: Optional start date in ISO format
|
|
281
|
+
end_date: Optional end date in ISO format
|
|
282
|
+
limit: Items per request (max 500)
|
|
283
|
+
max_iteration: Maximum number of pagination iterations
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
List of event dictionaries
|
|
287
|
+
"""
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
##### fetch_event_documents
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
def fetch_event_documents(
|
|
294
|
+
self,
|
|
295
|
+
event_ids: list[int],
|
|
296
|
+
document_ids: list[int],
|
|
297
|
+
limit: int = 500,
|
|
298
|
+
max_iteration: int = 20,
|
|
299
|
+
) -> list[DocumentDto]:
|
|
300
|
+
"""
|
|
301
|
+
Retrieve documents for a list of events.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
event_ids: List of event IDs
|
|
305
|
+
document_ids: List of document type IDs to filter
|
|
306
|
+
limit: Items per request (max 500)
|
|
307
|
+
max_iteration: Maximum number of pagination iterations
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
List of document dictionaries
|
|
311
|
+
"""
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
##### Static Methods
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
@staticmethod
|
|
318
|
+
def get_event_subtype_ids_from_event_types(
|
|
319
|
+
event_types: list[EventType],
|
|
320
|
+
) -> list[int]:
|
|
321
|
+
"""
|
|
322
|
+
Convert EventType enums to Quartr API event subtype IDs.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
event_types: List of EventType enums
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
List of event subtype IDs
|
|
329
|
+
"""
|
|
330
|
+
|
|
331
|
+
@staticmethod
|
|
332
|
+
def get_document_ids_from_document_types(
|
|
333
|
+
document_types: list[DocumentType],
|
|
334
|
+
) -> list[int]:
|
|
335
|
+
"""
|
|
336
|
+
Convert DocumentType enums to Quartr API document type IDs.
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
document_types: List of DocumentType enums
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
List of document type IDs
|
|
343
|
+
"""
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Response Models
|
|
347
|
+
|
|
348
|
+
### EventDto
|
|
349
|
+
|
|
350
|
+
```python
|
|
351
|
+
{
|
|
352
|
+
"company_id": float,
|
|
353
|
+
"date": datetime,
|
|
354
|
+
"id": float,
|
|
355
|
+
"title": str,
|
|
356
|
+
"type_id": float,
|
|
357
|
+
"fiscal_year": float | None,
|
|
358
|
+
"fiscal_period": str | None,
|
|
359
|
+
"backlink_url": str,
|
|
360
|
+
"updated_at": datetime,
|
|
361
|
+
"created_at": datetime,
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### DocumentDto
|
|
366
|
+
|
|
367
|
+
```python
|
|
368
|
+
{
|
|
369
|
+
"company_id": float | None,
|
|
370
|
+
"event_id": float | None,
|
|
371
|
+
"file_url": str,
|
|
372
|
+
"id": float,
|
|
373
|
+
"type_id": float,
|
|
374
|
+
"updated_at": datetime,
|
|
375
|
+
"created_at": datetime,
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Testing
|
|
380
|
+
|
|
381
|
+
Run the test suite:
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
poetry run pytest
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Run with coverage:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
poetry run pytest --cov=unique_quartr --cov-report=html
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Run specific test files:
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
poetry run pytest tests/test_service.py
|
|
397
|
+
poetry run pytest tests/test_constants.py
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
## Error Handling
|
|
401
|
+
|
|
402
|
+
The library will raise exceptions in the following cases:
|
|
403
|
+
|
|
404
|
+
- **Missing API Credentials**: `ValueError` when `QUARTR_API_CREDS` is not set
|
|
405
|
+
- **Company Not Activated**: `ValueError` when the company_id is not in `QUARTR_API_ACTIVATED_COMPANIES`
|
|
406
|
+
- **API Errors**: Various HTTP errors from the Quartr API
|
|
407
|
+
|
|
408
|
+
### Example Error Handling
|
|
409
|
+
|
|
410
|
+
```python
|
|
411
|
+
from unique_quartr.service import QuartrService
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
service = QuartrService(
|
|
415
|
+
company_id="invalid_company",
|
|
416
|
+
requestor_type=RequestorType.SYNC,
|
|
417
|
+
)
|
|
418
|
+
except ValueError as e:
|
|
419
|
+
print(f"Configuration error: {e}")
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Development
|
|
423
|
+
|
|
424
|
+
### Setup Development Environment
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
# Clone the repository
|
|
428
|
+
git clone <repository_url>
|
|
429
|
+
cd unique_quartr
|
|
430
|
+
|
|
431
|
+
# Install dependencies
|
|
432
|
+
poetry install
|
|
433
|
+
|
|
434
|
+
# Run linting
|
|
435
|
+
poetry run ruff check .
|
|
436
|
+
|
|
437
|
+
# Run formatting
|
|
438
|
+
poetry run ruff format .
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Project Structure
|
|
442
|
+
|
|
443
|
+
```
|
|
444
|
+
unique_quartr/
|
|
445
|
+
├── constants/
|
|
446
|
+
│ ├── document_types.py # Document type enums and mappings
|
|
447
|
+
│ └── event_types.py # Event type enums and mappings
|
|
448
|
+
├── endpoints/
|
|
449
|
+
│ ├── api.py # API endpoint definitions
|
|
450
|
+
│ └── schemas.py # Pydantic models for API requests/responses
|
|
451
|
+
├── helpers.py # Helper utilities
|
|
452
|
+
├── service.py # Main service class
|
|
453
|
+
└── settings.py # Configuration and settings
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## License
|
|
457
|
+
|
|
458
|
+
Proprietary
|
|
459
|
+
|
|
460
|
+
## Authors
|
|
461
|
+
|
|
462
|
+
- Rami Azouz <rami.ext@unique.ch>
|
|
463
|
+
|
|
464
|
+
## Support
|
|
465
|
+
|
|
466
|
+
For issues and questions, please contact the maintainers or refer to the [Quartr API documentation](https://quartr.com/api).
|
|
467
|
+
|
|
468
|
+
## Changelog
|
|
469
|
+
|
|
470
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history and updates.
|
|
471
|
+
|
|
472
|
+
# Changelog
|
|
473
|
+
|
|
474
|
+
All notable changes to this project will be documented in this file.
|
|
475
|
+
|
|
476
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
477
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
478
|
+
|
|
479
|
+
## [0.1.0] - 2025-08-18
|
|
480
|
+
- Initial release of `unique_quartr`.
|