btgsolutions-dataservices-python-client 3.2.9__tar.gz → 3.2.11__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 (40) hide show
  1. {btgsolutions_dataservices_python_client-3.2.9/btgsolutions_dataservices_python_client.egg-info → btgsolutions_dataservices_python_client-3.2.11}/PKG-INFO +25 -2
  2. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/README.md +24 -1
  3. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/__init__.py +1 -1
  4. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/__init__.py +1 -0
  5. btgsolutions_dataservices_python_client-3.2.11/btgsolutions_dataservices/rest/book_scope.py +204 -0
  6. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11/btgsolutions_dataservices_python_client.egg-info}/PKG-INFO +25 -2
  7. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices_python_client.egg-info/SOURCES.txt +1 -0
  8. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/LICENSE +0 -0
  9. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/MANIFEST.in +0 -0
  10. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/config.py +0 -0
  11. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/exceptions.py +0 -0
  12. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/authenticator.py +0 -0
  13. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/broker_reference.py +0 -0
  14. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/bulk_data.py +0 -0
  15. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/company_data.py +0 -0
  16. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/corporate_events.py +0 -0
  17. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/hfn.py +0 -0
  18. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/historical_candles.py +0 -0
  19. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/historical_candles_crypto.py +0 -0
  20. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/intraday_candles.py +0 -0
  21. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/intraday_tick_data.py +0 -0
  22. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/public_sources.py +0 -0
  23. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/quotes.py +0 -0
  24. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/reference_data.py +0 -0
  25. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/stock_loan.py +0 -0
  26. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/ticker_last_event.py +0 -0
  27. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/rest/ticker_last_event_polling.py +0 -0
  28. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/websocket/__init__.py +0 -0
  29. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/websocket/broker_analytics.py +0 -0
  30. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/websocket/hfn_websocket_client.py +0 -0
  31. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/websocket/market_data_feed.py +0 -0
  32. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/websocket/market_data_websocket_client.py +0 -0
  33. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices/websocket/websocket_default_functions.py +0 -0
  34. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices_python_client.egg-info/dependency_links.txt +0 -0
  35. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices_python_client.egg-info/requires.txt +0 -0
  36. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/btgsolutions_dataservices_python_client.egg-info/top_level.txt +0 -0
  37. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/pyproject.toml +0 -0
  38. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/requirements.txt +0 -0
  39. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/setup.cfg +0 -0
  40. {btgsolutions_dataservices_python_client-3.2.9 → btgsolutions_dataservices_python_client-3.2.11}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: btgsolutions_dataservices_python_client
3
- Version: 3.2.9
3
+ Version: 3.2.11
4
4
  Summary: Python package containing several classes and data for extracting and manipulating market and trading data.
5
5
  Home-page: https://github.com/BTG-Pactual-Solutions/btgsolutions-dataservices-python-client
6
6
  Author: BTG Solutions Data Services powered by BTG Pactual Solutions
@@ -194,7 +194,6 @@ ws.subscribe_top_brokers(n=5, tickers=['SNFF11'])
194
194
  ws.subscribed_to()
195
195
  ws.get_last_event(analytics_type='top_tickers', n=3, brokers=['85', '3'])
196
196
  ws.get_last_event(analytics_type='top_brokers', n=100, tickers=['SNFF11'])
197
- ws.get_last_event()
198
197
  ws.unsubscribe_top_tickers(brokers=['85'])
199
198
  ws.unsubscribe_top_brokers(tickers=['SNFF11'])
200
199
 
@@ -504,6 +503,30 @@ broker_reference = btg.BrokerReference(api_key='YOUR_API_KEY')
504
503
  broker_reference.get()
505
504
  ```
506
505
 
506
+ #### Book Scope
507
+
508
+ ```python
509
+ import btgsolutions_dataservices as btg
510
+ book_scope = btg.BookScope(api_key='YOUR_API_KEY')
511
+
512
+ result = book_scope.get(
513
+ symbol='PETR4',
514
+ market_type='Equities',
515
+ start_time='2026-05-22T15:50:00Z',
516
+ end_time='2026-05-22T16:00:00Z',
517
+ select=['trades', 'book_snapshot', 'book_incremental'], # choose one, two, or all three
518
+ )
519
+
520
+ single_file_result = book_scope.get(
521
+ symbol='PETR4',
522
+ market_type='Equities',
523
+ start_time='2026-05-22T15:50:00Z',
524
+ end_time='2026-05-22T16:00:00Z',
525
+ select=['trades', 'book_snapshot', 'book_incremental'],
526
+ aggregate_info=True,
527
+ )
528
+ ```
529
+
507
530
  #### Ticker Reference Data
508
531
 
509
532
  ```python
@@ -171,7 +171,6 @@ ws.subscribe_top_brokers(n=5, tickers=['SNFF11'])
171
171
  ws.subscribed_to()
172
172
  ws.get_last_event(analytics_type='top_tickers', n=3, brokers=['85', '3'])
173
173
  ws.get_last_event(analytics_type='top_brokers', n=100, tickers=['SNFF11'])
174
- ws.get_last_event()
175
174
  ws.unsubscribe_top_tickers(brokers=['85'])
176
175
  ws.unsubscribe_top_brokers(tickers=['SNFF11'])
177
176
 
@@ -481,6 +480,30 @@ broker_reference = btg.BrokerReference(api_key='YOUR_API_KEY')
481
480
  broker_reference.get()
482
481
  ```
483
482
 
483
+ #### Book Scope
484
+
485
+ ```python
486
+ import btgsolutions_dataservices as btg
487
+ book_scope = btg.BookScope(api_key='YOUR_API_KEY')
488
+
489
+ result = book_scope.get(
490
+ symbol='PETR4',
491
+ market_type='Equities',
492
+ start_time='2026-05-22T15:50:00Z',
493
+ end_time='2026-05-22T16:00:00Z',
494
+ select=['trades', 'book_snapshot', 'book_incremental'], # choose one, two, or all three
495
+ )
496
+
497
+ single_file_result = book_scope.get(
498
+ symbol='PETR4',
499
+ market_type='Equities',
500
+ start_time='2026-05-22T15:50:00Z',
501
+ end_time='2026-05-22T16:00:00Z',
502
+ select=['trades', 'book_snapshot', 'book_incremental'],
503
+ aggregate_info=True,
504
+ )
505
+ ```
506
+
484
507
  #### Ticker Reference Data
485
508
 
486
509
  ```python
@@ -1,4 +1,4 @@
1
- __version__ = "3.2.9"
1
+ __version__ = "3.2.11"
2
2
 
3
3
  from .websocket import *
4
4
  from .rest import *
@@ -14,3 +14,4 @@ from .reference_data import ReferenceData
14
14
  from .stock_loan import StockLoan
15
15
  from .ticker_last_event_polling import TickerLastEventPolling
16
16
  from .broker_reference import BrokerReference
17
+ from .book_scope import BookScope
@@ -0,0 +1,204 @@
1
+ from datetime import datetime, timedelta, timezone
2
+ from typing import Optional, List
3
+ from ..exceptions import BadResponse
4
+ import requests
5
+ from ..config import url_api_v1
6
+ from .authenticator import Authenticator
7
+ from io import BytesIO
8
+ import pyarrow as pa
9
+ import pyarrow.parquet as pq
10
+
11
+ VALID_SELECT_OPTIONS = {"trades", "book_snapshot", "book_incremental"}
12
+ MAX_MARKET_SCOPE_WINDOW = timedelta(minutes=10)
13
+ ROW_LIMIT = 10000
14
+
15
+
16
+ class BookScope:
17
+ """
18
+ This class provides market scope data (trades, book snapshots, book incremental)
19
+ for a given symbol and time window.
20
+
21
+ * Main use case:
22
+
23
+ >>> from btgsolutions_dataservices import BookScope
24
+ >>> book_scope = BookScope(
25
+ >>> api_key='YOUR_API_KEY',
26
+ >>> )
27
+ >>> book_scope.get(
28
+ >>> symbol='PETR4',
29
+ >>> market_type='Equities',
30
+ >>> start_time='2026-05-22T12:00:00Z',
31
+ >>> end_time='2026-05-22T12:10:00Z',
32
+ >>> )
33
+
34
+ Parameters
35
+ ----------------
36
+ api_key: str
37
+ User identification key.
38
+ Field is required.
39
+ """
40
+ def __init__(
41
+ self,
42
+ api_key: Optional[str],
43
+ ):
44
+ self.api_key = api_key
45
+ self.token = Authenticator(self.api_key).token
46
+ self.headers = {"authorization": f"authorization {self.token}"}
47
+ self.base_url = url_api_v1
48
+
49
+ def _fetch_all_pages(self, endpoint_url: str, params: dict) -> bytes:
50
+ """Fetches all pages via rpt_seq cursor and returns a single combined parquet."""
51
+ tables = []
52
+ rpt_seq = None
53
+
54
+ while True:
55
+ page_params = {**params}
56
+ if rpt_seq is not None:
57
+ page_params["rpt_seq"] = rpt_seq
58
+
59
+ response = requests.get(endpoint_url, params=page_params, headers=self.headers)
60
+ if response.status_code != 200:
61
+ try:
62
+ error_body = response.json()
63
+ detail = error_body.get("detail", error_body.get("error", response.text))
64
+ except Exception:
65
+ detail = response.text
66
+ raise BadResponse(f"Error: {detail}")
67
+
68
+ table = pq.read_table(BytesIO(response.content))
69
+ tables.append(table)
70
+
71
+ if table.num_rows < ROW_LIMIT:
72
+ break
73
+ rpt_seq = table.column("rpt_seq")[-1].as_py()
74
+
75
+ combined = pa.concat_tables(tables)
76
+ buffer = BytesIO()
77
+ pq.write_table(combined, buffer)
78
+ return buffer.getvalue()
79
+
80
+ @staticmethod
81
+ def _combine_parquets(parquet_payloads: List[bytes]) -> bytes:
82
+ """Combines multiple parquet payloads into a single parquet file."""
83
+ tables = [BookScope._normalize_timestamps(pq.read_table(BytesIO(payload))) for payload in parquet_payloads]
84
+ combined = pa.concat_tables(tables, promote_options="default")
85
+ buffer = BytesIO()
86
+ pq.write_table(combined, buffer)
87
+ return buffer.getvalue()
88
+
89
+ @staticmethod
90
+ def _normalize_timestamps(table: pa.Table) -> pa.Table:
91
+ """Normalizes timestamp columns so tables can be concatenated safely."""
92
+ normalized = table
93
+
94
+ for field in table.schema:
95
+ if pa.types.is_timestamp(field.type):
96
+ target_type = pa.timestamp("us", tz=field.type.tz)
97
+ column_index = normalized.schema.get_field_index(field.name)
98
+ normalized = normalized.set_column(
99
+ column_index,
100
+ field.name,
101
+ normalized[field.name].cast(target_type),
102
+ )
103
+
104
+ return normalized
105
+
106
+ @staticmethod
107
+ def _parse_iso8601(value: str, field_name: str) -> datetime:
108
+ try:
109
+ return datetime.fromisoformat(value.replace("Z", "+00:00"))
110
+ except ValueError as exc:
111
+ raise ValueError(f"{field_name} must be a valid ISO-8601 datetime string.") from exc
112
+
113
+ @staticmethod
114
+ def _resolve_scope(end_time: datetime) -> str:
115
+ """Determines whether the request is 'intraday' or 'historical' based on end_time."""
116
+ now = datetime.now(timezone.utc)
117
+ today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
118
+ if end_time >= today_start:
119
+ return "intraday"
120
+ return "historical"
121
+
122
+ def get(
123
+ self,
124
+ symbol: str,
125
+ market_type: str,
126
+ start_time: str,
127
+ end_time: str,
128
+ select: List[str] = ["trades", "book_snapshot", "book_incremental"],
129
+ aggregate_info: bool = False,
130
+ ):
131
+ """
132
+ Returns trades, book snapshot and book incremental data for the given symbol and time window.
133
+
134
+ Pagination is handled automatically: if the API returns the maximum number of rows
135
+ (10 000), additional pages are fetched using the rpt_seq cursor until all events
136
+ in the requested horizon are retrieved. The caller always receives a single,
137
+ complete parquet file per dataset.
138
+
139
+ Parameters
140
+ ----------------
141
+ symbol: str
142
+ The ticker symbol to query.
143
+ Field is required. Example: 'PETR4', 'DOLM26'.
144
+ market_type: str
145
+ Market type.
146
+ Field is required. Allowed values: 'Equities', 'Derivatives'.
147
+ start_time: str
148
+ Start of the analysis window in ISO-8601 format.
149
+ Field is required. Example: '2026-05-22T15:50:00Z'.
150
+ end_time: str
151
+ End of the analysis window in ISO-8601 format.
152
+ Field is required. Example: '2026-05-22T12:10:00Z'.
153
+ select: list of str
154
+ Which datasets to return.
155
+ Field is optional. Default: ['trades', 'book_snapshot', 'book_incremental'].
156
+ Allowed values: 'trades', 'book_snapshot', 'book_incremental'.
157
+ aggregate_info: bool
158
+ When True, returns a single parquet file containing the selected datasets.
159
+ Field is optional. Default: False.
160
+
161
+ Returns
162
+ ----------------
163
+ dict
164
+ Dictionary with the selected keys, each containing:
165
+ - 'data': raw parquet bytes with all rows for the requested time window
166
+ When aggregate_info is True, returns a single key:
167
+ - 'data': raw parquet bytes with all selected datasets combined into one parquet file
168
+ """
169
+ invalid = set(select) - VALID_SELECT_OPTIONS
170
+ if invalid:
171
+ raise ValueError(f"Invalid select options: {invalid}. Valid options are: {VALID_SELECT_OPTIONS}")
172
+
173
+ parsed_start_time = self._parse_iso8601(start_time, "start_time")
174
+ parsed_end_time = self._parse_iso8601(end_time, "end_time")
175
+
176
+ if parsed_start_time >= parsed_end_time:
177
+ raise ValueError("start_time must be earlier than end_time.")
178
+
179
+ if parsed_end_time - parsed_start_time > MAX_MARKET_SCOPE_WINDOW:
180
+ raise ValueError("The maximum allowed range between start_time and end_time is 10 minutes.")
181
+
182
+ base_params = dict(symbol=symbol, start_time=start_time, end_time=end_time, limit=ROW_LIMIT)
183
+
184
+ scope = self._resolve_scope(parsed_end_time)
185
+
186
+ endpoint_map = {
187
+ "trades": f"{self.base_url}/marketdata/br/b3/book-scope/{scope}/{market_type}/trades",
188
+ "book_snapshot": f"{self.base_url}/marketdata/br/b3/book-scope/{scope}/{market_type}/book-snapshot",
189
+ "book_incremental": f"{self.base_url}/marketdata/br/b3/book-scope/{scope}/{market_type}/book-incremental",
190
+ }
191
+
192
+ result = {}
193
+ parquet_payloads = []
194
+ for key in select:
195
+ data = self._fetch_all_pages(endpoint_map[key], base_params)
196
+ if aggregate_info:
197
+ parquet_payloads.append(data)
198
+ else:
199
+ result[key] = {"data": data}
200
+
201
+ if aggregate_info:
202
+ result["data"] = self._combine_parquets(parquet_payloads)
203
+
204
+ return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: btgsolutions_dataservices_python_client
3
- Version: 3.2.9
3
+ Version: 3.2.11
4
4
  Summary: Python package containing several classes and data for extracting and manipulating market and trading data.
5
5
  Home-page: https://github.com/BTG-Pactual-Solutions/btgsolutions-dataservices-python-client
6
6
  Author: BTG Solutions Data Services powered by BTG Pactual Solutions
@@ -194,7 +194,6 @@ ws.subscribe_top_brokers(n=5, tickers=['SNFF11'])
194
194
  ws.subscribed_to()
195
195
  ws.get_last_event(analytics_type='top_tickers', n=3, brokers=['85', '3'])
196
196
  ws.get_last_event(analytics_type='top_brokers', n=100, tickers=['SNFF11'])
197
- ws.get_last_event()
198
197
  ws.unsubscribe_top_tickers(brokers=['85'])
199
198
  ws.unsubscribe_top_brokers(tickers=['SNFF11'])
200
199
 
@@ -504,6 +503,30 @@ broker_reference = btg.BrokerReference(api_key='YOUR_API_KEY')
504
503
  broker_reference.get()
505
504
  ```
506
505
 
506
+ #### Book Scope
507
+
508
+ ```python
509
+ import btgsolutions_dataservices as btg
510
+ book_scope = btg.BookScope(api_key='YOUR_API_KEY')
511
+
512
+ result = book_scope.get(
513
+ symbol='PETR4',
514
+ market_type='Equities',
515
+ start_time='2026-05-22T15:50:00Z',
516
+ end_time='2026-05-22T16:00:00Z',
517
+ select=['trades', 'book_snapshot', 'book_incremental'], # choose one, two, or all three
518
+ )
519
+
520
+ single_file_result = book_scope.get(
521
+ symbol='PETR4',
522
+ market_type='Equities',
523
+ start_time='2026-05-22T15:50:00Z',
524
+ end_time='2026-05-22T16:00:00Z',
525
+ select=['trades', 'book_snapshot', 'book_incremental'],
526
+ aggregate_info=True,
527
+ )
528
+ ```
529
+
507
530
  #### Ticker Reference Data
508
531
 
509
532
  ```python
@@ -9,6 +9,7 @@ btgsolutions_dataservices/config.py
9
9
  btgsolutions_dataservices/exceptions.py
10
10
  btgsolutions_dataservices/rest/__init__.py
11
11
  btgsolutions_dataservices/rest/authenticator.py
12
+ btgsolutions_dataservices/rest/book_scope.py
12
13
  btgsolutions_dataservices/rest/broker_reference.py
13
14
  btgsolutions_dataservices/rest/bulk_data.py
14
15
  btgsolutions_dataservices/rest/company_data.py