btgsolutions-dataservices-python-client 3.2.11__tar.gz → 3.2.12__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 (41) hide show
  1. {btgsolutions_dataservices_python_client-3.2.11/btgsolutions_dataservices_python_client.egg-info → btgsolutions_dataservices_python_client-3.2.12}/PKG-INFO +28 -18
  2. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/README.md +26 -8
  3. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/__init__.py +1 -1
  4. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/__init__.py +1 -0
  5. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/book_scope.py +31 -23
  6. btgsolutions_dataservices_python_client-3.2.12/btgsolutions_dataservices/rest/broker_analytics.py +173 -0
  7. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/historical_candles.py +66 -6
  8. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12/btgsolutions_dataservices_python_client.egg-info}/PKG-INFO +28 -18
  9. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices_python_client.egg-info/SOURCES.txt +1 -0
  10. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/LICENSE +0 -0
  11. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/MANIFEST.in +0 -0
  12. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/config.py +0 -0
  13. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/exceptions.py +0 -0
  14. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/authenticator.py +0 -0
  15. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/broker_reference.py +0 -0
  16. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/bulk_data.py +0 -0
  17. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/company_data.py +0 -0
  18. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/corporate_events.py +0 -0
  19. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/hfn.py +0 -0
  20. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/historical_candles_crypto.py +0 -0
  21. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/intraday_candles.py +0 -0
  22. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/intraday_tick_data.py +0 -0
  23. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/public_sources.py +0 -0
  24. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/quotes.py +0 -0
  25. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/reference_data.py +0 -0
  26. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/stock_loan.py +0 -0
  27. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/ticker_last_event.py +0 -0
  28. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/rest/ticker_last_event_polling.py +0 -0
  29. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/websocket/__init__.py +0 -0
  30. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/websocket/broker_analytics.py +0 -0
  31. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/websocket/hfn_websocket_client.py +0 -0
  32. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/websocket/market_data_feed.py +0 -0
  33. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/websocket/market_data_websocket_client.py +0 -0
  34. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices/websocket/websocket_default_functions.py +0 -0
  35. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices_python_client.egg-info/dependency_links.txt +0 -0
  36. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices_python_client.egg-info/requires.txt +0 -0
  37. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/btgsolutions_dataservices_python_client.egg-info/top_level.txt +0 -0
  38. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/pyproject.toml +0 -0
  39. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/requirements.txt +0 -0
  40. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/setup.cfg +0 -0
  41. {btgsolutions_dataservices_python_client-3.2.11 → btgsolutions_dataservices_python_client-3.2.12}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.1
2
2
  Name: btgsolutions_dataservices_python_client
3
- Version: 3.2.11
3
+ Version: 3.2.12
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
@@ -12,14 +12,6 @@ Requires-Dist: websocket-client>=1.8.0
12
12
  Requires-Dist: PyJWT>=2.8.0
13
13
  Requires-Dist: requests>=2.32.3
14
14
  Requires-Dist: pyarrow>=17.0.0
15
- Dynamic: author
16
- Dynamic: description
17
- Dynamic: description-content-type
18
- Dynamic: home-page
19
- Dynamic: license-file
20
- Dynamic: requires-dist
21
- Dynamic: requires-python
22
- Dynamic: summary
23
15
 
24
16
  # BTG Solutions - Data Services
25
17
 
@@ -280,6 +272,14 @@ hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
280
272
  hist_candles.get_intraday_history_candles(ticker='PETR4', market_type='stocks', corporate_events_adj=True, date='2023-10-06', candle='1m', rmv_after_market=True, timezone='UTC', raw_data=False, round=True)
281
273
  ```
282
274
 
275
+ ##### Interday Batch
276
+
277
+ ```python
278
+ import btgsolutions_dataservices as btg
279
+ hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
280
+ hist_candles.get_interday_history_candles_batch(market_type='stocks', tickers=['PETR4', 'VALE3'], start_date='2023-10-01', end_date='2023-10-13', corporate_events_adj=True, rmv_after_market=True, timezone='UTC', raw_data=False, round=True)
281
+ ```
282
+
283
283
  ##### Available Tickers
284
284
 
285
285
  ```python
@@ -510,23 +510,33 @@ import btgsolutions_dataservices as btg
510
510
  book_scope = btg.BookScope(api_key='YOUR_API_KEY')
511
511
 
512
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',
513
+ symbol='DOLM26',
514
+ market_type='derivatives',
515
+ start_time='2026-05-28T14:12:00Z',
516
+ end_time='2026-05-28T14:15:00Z',
517
517
  select=['trades', 'book_snapshot', 'book_incremental'], # choose one, two, or all three
518
518
  )
519
519
 
520
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',
521
+ symbol='DOLM26',
522
+ market_type='derivatives',
523
+ start_time='2026-05-28T14:12:00Z',
524
+ end_time='2026-05-28T14:15:00Z',
525
525
  select=['trades', 'book_snapshot', 'book_incremental'],
526
526
  aggregate_info=True,
527
527
  )
528
528
  ```
529
529
 
530
+ #### Broker Analytics
531
+
532
+ ```python
533
+ import btgsolutions_dataservices as btg
534
+ broker_analytics = btg.BrokerAnalytics(api_key='YOUR_API_KEY', market_type='stocks')
535
+ summary = broker_analytics.get_summary(brokers=['85', '3'], tickers=['PETR4', 'ABCB4'])
536
+ top_brokers = broker_analytics.get_top_brokers(n=10)
537
+ top_tickers = broker_analytics.get_top_tickers(n=10, brokers=['85', '3'])
538
+ ```
539
+
530
540
  #### Ticker Reference Data
531
541
 
532
542
  ```python
@@ -257,6 +257,14 @@ hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
257
257
  hist_candles.get_intraday_history_candles(ticker='PETR4', market_type='stocks', corporate_events_adj=True, date='2023-10-06', candle='1m', rmv_after_market=True, timezone='UTC', raw_data=False, round=True)
258
258
  ```
259
259
 
260
+ ##### Interday Batch
261
+
262
+ ```python
263
+ import btgsolutions_dataservices as btg
264
+ hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
265
+ hist_candles.get_interday_history_candles_batch(market_type='stocks', tickers=['PETR4', 'VALE3'], start_date='2023-10-01', end_date='2023-10-13', corporate_events_adj=True, rmv_after_market=True, timezone='UTC', raw_data=False, round=True)
266
+ ```
267
+
260
268
  ##### Available Tickers
261
269
 
262
270
  ```python
@@ -487,23 +495,33 @@ import btgsolutions_dataservices as btg
487
495
  book_scope = btg.BookScope(api_key='YOUR_API_KEY')
488
496
 
489
497
  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',
498
+ symbol='DOLM26',
499
+ market_type='derivatives',
500
+ start_time='2026-05-28T14:12:00Z',
501
+ end_time='2026-05-28T14:15:00Z',
494
502
  select=['trades', 'book_snapshot', 'book_incremental'], # choose one, two, or all three
495
503
  )
496
504
 
497
505
  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',
506
+ symbol='DOLM26',
507
+ market_type='derivatives',
508
+ start_time='2026-05-28T14:12:00Z',
509
+ end_time='2026-05-28T14:15:00Z',
502
510
  select=['trades', 'book_snapshot', 'book_incremental'],
503
511
  aggregate_info=True,
504
512
  )
505
513
  ```
506
514
 
515
+ #### Broker Analytics
516
+
517
+ ```python
518
+ import btgsolutions_dataservices as btg
519
+ broker_analytics = btg.BrokerAnalytics(api_key='YOUR_API_KEY', market_type='stocks')
520
+ summary = broker_analytics.get_summary(brokers=['85', '3'], tickers=['PETR4', 'ABCB4'])
521
+ top_brokers = broker_analytics.get_top_brokers(n=10)
522
+ top_tickers = broker_analytics.get_top_tickers(n=10, brokers=['85', '3'])
523
+ ```
524
+
507
525
  #### Ticker Reference Data
508
526
 
509
527
  ```python
@@ -1,4 +1,4 @@
1
- __version__ = "3.2.11"
1
+ __version__ = "3.2.12"
2
2
 
3
3
  from .websocket import *
4
4
  from .rest import *
@@ -15,3 +15,4 @@ from .stock_loan import StockLoan
15
15
  from .ticker_last_event_polling import TickerLastEventPolling
16
16
  from .broker_reference import BrokerReference
17
17
  from .book_scope import BookScope
18
+ from .broker_analytics import BrokerAnalytics
@@ -9,6 +9,7 @@ import pyarrow as pa
9
9
  import pyarrow.parquet as pq
10
10
 
11
11
  VALID_SELECT_OPTIONS = {"trades", "book_snapshot", "book_incremental"}
12
+ VALID_MARKET_TYPES = {"derivatives", "options", "stocks"}
12
13
  MAX_MARKET_SCOPE_WINDOW = timedelta(minutes=10)
13
14
  ROW_LIMIT = 10000
14
15
 
@@ -25,10 +26,10 @@ class BookScope:
25
26
  >>> api_key='YOUR_API_KEY',
26
27
  >>> )
27
28
  >>> 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',
29
+ >>> symbol='DOLM26',
30
+ >>> market_type='derivatives',
31
+ >>> start_time='2026-05-28T14:12:00Z',
32
+ >>> end_time='2026-05-28T14:15:00Z',
32
33
  >>> )
33
34
 
34
35
  Parameters
@@ -55,8 +56,8 @@ class BookScope:
55
56
  page_params = {**params}
56
57
  if rpt_seq is not None:
57
58
  page_params["rpt_seq"] = rpt_seq
58
-
59
- response = requests.get(endpoint_url, params=page_params, headers=self.headers)
59
+
60
+ response = requests.get(endpoint_url, params=page_params, headers=self.headers, timeout=50)
60
61
  if response.status_code != 200:
61
62
  try:
62
63
  error_body = response.json()
@@ -134,7 +135,7 @@ class BookScope:
134
135
  Pagination is handled automatically: if the API returns the maximum number of rows
135
136
  (10 000), additional pages are fetched using the rpt_seq cursor until all events
136
137
  in the requested horizon are retrieved. The caller always receives a single,
137
- complete parquet file per dataset.
138
+ complete DataFrame per dataset.
138
139
 
139
140
  Parameters
140
141
  ----------------
@@ -143,29 +144,36 @@ class BookScope:
143
144
  Field is required. Example: 'PETR4', 'DOLM26'.
144
145
  market_type: str
145
146
  Market type.
146
- Field is required. Allowed values: 'Equities', 'Derivatives'.
147
+ Field is required. Allowed values: 'derivatives', 'options', 'stocks'.
147
148
  start_time: str
148
- Start of the analysis window in ISO-8601 format.
149
- Field is required. Example: '2026-05-22T15:50:00Z'.
149
+ Start of the analysis window in ISO-8601 UTC format.
150
+ Field is required. Example: '2026-05-28T14:12:00Z'.
150
151
  end_time: str
151
- End of the analysis window in ISO-8601 format.
152
- Field is required. Example: '2026-05-22T12:10:00Z'.
152
+ End of the analysis window in ISO-8601 UTC format.
153
+ Field is required. Example: '2026-05-28T14:15:00Z'.
153
154
  select: list of str
154
155
  Which datasets to return.
155
156
  Field is optional. Default: ['trades', 'book_snapshot', 'book_incremental'].
156
157
  Allowed values: 'trades', 'book_snapshot', 'book_incremental'.
157
158
  aggregate_info: bool
158
- When True, returns a single parquet file containing the selected datasets.
159
+ When True, returns a single pandas.DataFrame containing the selected datasets.
159
160
  Field is optional. Default: False.
160
161
 
161
162
  Returns
162
163
  ----------------
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
164
+ dict or pandas.DataFrame
165
+ When aggregate_info is False (default): dictionary with the selected keys
166
+ ('trades', 'book_snapshot', 'book_incremental'), each mapping directly to
167
+ a pandas.DataFrame with all rows for the requested time window.
168
+ When aggregate_info is True: returns a single pandas.DataFrame with all
169
+ selected datasets combined.
168
170
  """
171
+ normalized_market_type = market_type.lower()
172
+ if normalized_market_type not in VALID_MARKET_TYPES:
173
+ raise ValueError(
174
+ f"Invalid market_type: {market_type}. Valid options are: {VALID_MARKET_TYPES}"
175
+ )
176
+
169
177
  invalid = set(select) - VALID_SELECT_OPTIONS
170
178
  if invalid:
171
179
  raise ValueError(f"Invalid select options: {invalid}. Valid options are: {VALID_SELECT_OPTIONS}")
@@ -184,9 +192,9 @@ class BookScope:
184
192
  scope = self._resolve_scope(parsed_end_time)
185
193
 
186
194
  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",
195
+ "trades": f"{self.base_url}/marketdata/br/b3/book-scope/{scope}/{normalized_market_type}/trades",
196
+ "book_snapshot": f"{self.base_url}/marketdata/br/b3/book-scope/{scope}/{normalized_market_type}/book-snapshot",
197
+ "book_incremental": f"{self.base_url}/marketdata/br/b3/book-scope/{scope}/{normalized_market_type}/book-incremental",
190
198
  }
191
199
 
192
200
  result = {}
@@ -196,9 +204,9 @@ class BookScope:
196
204
  if aggregate_info:
197
205
  parquet_payloads.append(data)
198
206
  else:
199
- result[key] = {"data": data}
207
+ result[key] = pq.read_table(BytesIO(data)).to_pandas()
200
208
 
201
209
  if aggregate_info:
202
- result["data"] = self._combine_parquets(parquet_payloads)
210
+ return pq.read_table(BytesIO(self._combine_parquets(parquet_payloads))).to_pandas()
203
211
 
204
212
  return result
@@ -0,0 +1,173 @@
1
+ from typing import Optional, List
2
+ from ..exceptions import BadResponse
3
+ import requests
4
+ from ..config import url_api_v1
5
+ from .authenticator import Authenticator
6
+
7
+ VALID_MARKET_TYPES = {"derivatives", "stocks", "options"}
8
+
9
+ class BrokerAnalytics:
10
+ """
11
+ This class provides broker analytics data (summary, top brokers, top tickers)
12
+ for a given market type.
13
+
14
+ * Main use case:
15
+
16
+ >>> from btgsolutions_dataservices import BrokerAnalytics
17
+ >>> broker_analytics = BrokerAnalytics(
18
+ >>> api_key='YOUR_API_KEY',
19
+ >>> market_type='stocks',
20
+ >>> )
21
+ >>> broker_analytics.get_summary(
22
+ >>> brokers=['85', '3'],
23
+ >>> tickers=['ABCB4', 'PETR4'],
24
+ >>> )
25
+ >>> broker_analytics.get_top_brokers(n=10, tickers=['ABCB4'])
26
+ >>> broker_analytics.get_top_tickers(n=10, brokers=['85', '3'])
27
+
28
+ Parameters
29
+ ----------------
30
+ api_key: str
31
+ User identification key.
32
+ Field is required.
33
+ market_type: str
34
+ Market type to query. One of: 'derivatives', 'stocks', 'options'.
35
+ Field is required.
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ api_key: str,
41
+ market_type: str,
42
+ ):
43
+ self.api_key = api_key
44
+ self.token = Authenticator(self.api_key).token
45
+ self.headers = {"authorization": f"authorization {self.token}"}
46
+
47
+ market_type = market_type.strip().lower()
48
+ if market_type not in VALID_MARKET_TYPES:
49
+ raise ValueError(
50
+ f"Invalid market_type '{market_type}'. Must be one of: {sorted(VALID_MARKET_TYPES)}"
51
+ )
52
+ self.market_type = market_type
53
+
54
+ def _build_url(self, suffix: str) -> str:
55
+ return f"{url_api_v1}/marketdata/br/b3/realtime/broker-analytics/{self.market_type}/{suffix}"
56
+
57
+ def get_summary(
58
+ self,
59
+ brokers: List[str],
60
+ tickers: List[str],
61
+ side: Optional[str] = None,
62
+ ) -> dict:
63
+ """
64
+ Get day analytics summary for specific brokers and tickers.
65
+
66
+ Parameters
67
+ ----------
68
+ brokers : List[str]
69
+ List of broker names to filter. Required.
70
+ tickers : List[str]
71
+ List of ticker symbols to filter. Required.
72
+ side : str, optional
73
+ Filter by side ('buy' or 'sell'). If None, both sides are returned.
74
+
75
+ Returns
76
+ -------
77
+ dict
78
+ JSON response with broker analytics summary data.
79
+ """
80
+ params = {
81
+ "brokers": ",".join(brokers),
82
+ "tickers": ",".join(tickers),
83
+ }
84
+ if side is not None: params["side"] = side
85
+
86
+ url = self._build_url("summary")
87
+ response = requests.get(url, params=params, headers=self.headers, timeout=30)
88
+
89
+ if response.status_code != 200:
90
+ self._raise_error(response)
91
+
92
+ return response.json()
93
+
94
+ def get_top_brokers(
95
+ self,
96
+ n: int,
97
+ tickers: Optional[List[str]] = None,
98
+ side: Optional[str] = None,
99
+ ) -> dict:
100
+ """
101
+ Get top N brokers ranked by financial volume, with ticker breakdown.
102
+
103
+ Parameters
104
+ ----------
105
+ n : int
106
+ Number of top brokers to return. Required.
107
+ tickers : List[str], optional
108
+ List of ticker symbols to filter.
109
+ side : str, optional
110
+ Filter by side ('buy' or 'sell').
111
+
112
+ Returns
113
+ -------
114
+ dict
115
+ JSON response with top brokers and their top assets breakdown.
116
+ """
117
+ params = {"n": str(n)}
118
+
119
+ if tickers: params["tickers"] = ",".join(tickers)
120
+ if side is not None: params["side"] = side
121
+
122
+ url = self._build_url("top-brokers")
123
+ response = requests.get(url, params=params, headers=self.headers, timeout=30)
124
+
125
+ if response.status_code != 200:
126
+ self._raise_error(response)
127
+
128
+ return response.json()
129
+
130
+ def get_top_tickers(
131
+ self,
132
+ n: int,
133
+ brokers: Optional[List[str]] = None,
134
+ side: Optional[str] = None,
135
+ ) -> dict:
136
+ """
137
+ Get top N tickers ranked by financial volume, with broker breakdown.
138
+
139
+ Parameters
140
+ ----------
141
+ n : int
142
+ Number of top tickers to return. Required.
143
+ brokers : List[str], optional
144
+ List of broker names to filter.
145
+ side : str, optional
146
+ Filter by side ('buy' or 'sell').
147
+
148
+ Returns
149
+ -------
150
+ dict
151
+ JSON response with top tickers and their top brokers breakdown.
152
+ """
153
+ params = {"n": str(n)}
154
+
155
+ if brokers: params["brokers"] = ",".join(brokers)
156
+ if side is not None: params["side"] = side
157
+
158
+ url = self._build_url("top-tickers")
159
+ response = requests.get(url, params=params, headers=self.headers, timeout=30)
160
+
161
+ if response.status_code != 200:
162
+ self._raise_error(response)
163
+
164
+ return response.json()
165
+
166
+ @staticmethod
167
+ def _raise_error(response):
168
+ try:
169
+ error_body = response.json()
170
+ detail = error_body.get("detail", error_body.get("error", response.text))
171
+ except Exception:
172
+ detail = response.text
173
+ raise BadResponse(f"Error {response.status_code}: {detail}")
@@ -74,7 +74,7 @@ class HistoricalCandles:
74
74
  Parameters
75
75
  ----------------
76
76
  market_type: str
77
- Field is required. Allowed values: 'stocks' or 'derivatives'.
77
+ Field is required. Allowed values: 'stocks', 'derivatives' or 'indices'.
78
78
  ticker: str
79
79
  Ticker that needs to be returned.
80
80
  Field is required. Example: 'PETR4'.
@@ -103,8 +103,8 @@ class HistoricalCandles:
103
103
  Field is not required. Default: True.
104
104
  """
105
105
 
106
- if market_type not in ['stocks', 'derivatives']:
107
- raise MarketTypeError(f'Allowed values: "stocks" or "derivatives". Input value: "{market_type}".')
106
+ if market_type not in ['stocks', 'derivatives', 'indices']:
107
+ raise MarketTypeError(f'Allowed values: "stocks", "derivatives" or "indices". Input value: "{market_type}".')
108
108
 
109
109
  url = f"{url_apis_v3}/marketdata/history/candles/intraday/{market_type}?ticker={ticker}&corporate_events_adj={corporate_events_adj}&rmv_after_market={rmv_after_market}&timezone={timezone}&date={date}&candle={candle}&round={round}"
110
110
  response = requests.request("GET", url, headers=self.headers)
@@ -133,7 +133,7 @@ class HistoricalCandles:
133
133
  Parameters
134
134
  ----------------
135
135
  market_type: str
136
- Field is required. Allowed values: 'stocks' or 'derivatives'.
136
+ Field is required. Allowed values: 'stocks', 'derivatives' or 'indices'.
137
137
  ticker: str
138
138
  Ticker that needs to be returned.
139
139
  Field is required. Example: 'PETR4'.
@@ -162,8 +162,8 @@ class HistoricalCandles:
162
162
  Field is not required. Default: True.
163
163
  """
164
164
 
165
- if market_type not in ['stocks', 'derivatives']:
166
- raise MarketTypeError(f'Allowed values: "stocks" or "derivatives". Input value: "{market_type}".')
165
+ if market_type not in ['stocks', 'derivatives', 'indices']:
166
+ raise MarketTypeError(f'Allowed values: "stocks", "derivatives" or "indices". Input value: "{market_type}".')
167
167
 
168
168
  url = f"{url_apis_v3}/marketdata/history/candles/interday/{market_type}?ticker={ticker}&corporate_events_adj={corporate_events_adj}&rmv_after_market={rmv_after_market}&timezone={timezone}&start_date={start_date}&end_date={end_date}&round={round}"
169
169
  response = requests.request("GET", url, headers=self.headers)
@@ -174,6 +174,66 @@ class HistoricalCandles:
174
174
  response = json.loads(response.text)
175
175
  raise BadResponse(f'Error: {response.get("ApiClientError", "")}.\n{response.get("SuggestedAction", "")}')
176
176
 
177
+ def get_interday_history_candles_batch(
178
+ self,
179
+ market_type:str,
180
+ tickers:list,
181
+ start_date:str,
182
+ end_date:str,
183
+ corporate_events_adj:bool,
184
+ rmv_after_market:bool,
185
+ timezone:str,
186
+ raw_data:bool=False,
187
+ round:bool=True
188
+ ):
189
+ """
190
+ This method provides historical candles for a batch of tickers in determined period.
191
+
192
+ Parameters
193
+ ----------------
194
+ market_type: str
195
+ Field is required. Allowed values: 'stocks' or 'derivatives'.
196
+ tickers: list
197
+ Tickers that need to be returned.
198
+ Field is required. Example: ['PETR4', 'VALE3'].
199
+ start_date: string<date>
200
+ Start date of analysis. Format: "YYYY-MM-DD".
201
+ Field is required. Example: '2022-10-06'.
202
+ end_date: string<date>
203
+ End date of analysis. Format: "YYYY-MM-DD".
204
+ Field is required. Example: '2023-01-22'.
205
+ corporate_events_adj: bool
206
+ Corporate events adjustment.
207
+ Field is required. Allowed values: 'true' or 'false'.
208
+ rmv_after_market: bool
209
+ Remove trades after market close.
210
+ Field is required. Allowed values: 'true' or 'false'.
211
+ timezone: str
212
+ Timezone of the datetime.
213
+ Field is required. Allowed values: 'America/Sao_Paulo' or 'UTC'.
214
+ raw_data: bool
215
+ If false, returns data in a dataframe. If true, returns raw data.
216
+ Field is not required. Default: False.
217
+ round: bool
218
+ Apply rounding to prices.
219
+ Useful when corporate_events_adj=True, since price adjustment factors
220
+ may generate values with many decimal places.
221
+ Field is not required. Default: True.
222
+ """
223
+
224
+ if market_type not in ['stocks', 'derivatives']:
225
+ raise MarketTypeError(f'Allowed values: "stocks" or "derivatives". Input value: "{market_type}".')
226
+
227
+ url = f"{url_apis_v3}/marketdata/history/candles/interday/{market_type}/batch?corporate_events_adj={corporate_events_adj}&rmv_after_market={rmv_after_market}&timezone={timezone}&start_date={start_date}&end_date={end_date}&round={round}"
228
+ payload = {"tickers": tickers}
229
+ response = requests.request("POST", url, headers=self.headers, json=payload)
230
+ if response.status_code == 200:
231
+ response_data = json.loads(response.text)
232
+ return response_data if raw_data else pd.DataFrame(pd.concat([pd.DataFrame(v) for v in response_data.values()], ignore_index=True))
233
+
234
+ response = json.loads(response.text)
235
+ raise BadResponse(f'Error: {response.get("ApiClientError", "")}.\n{response.get("SuggestedAction", "")}')
236
+
177
237
  def get_available_tickers(
178
238
  self,
179
239
  market_type:str,
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.1
2
2
  Name: btgsolutions_dataservices_python_client
3
- Version: 3.2.11
3
+ Version: 3.2.12
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
@@ -12,14 +12,6 @@ Requires-Dist: websocket-client>=1.8.0
12
12
  Requires-Dist: PyJWT>=2.8.0
13
13
  Requires-Dist: requests>=2.32.3
14
14
  Requires-Dist: pyarrow>=17.0.0
15
- Dynamic: author
16
- Dynamic: description
17
- Dynamic: description-content-type
18
- Dynamic: home-page
19
- Dynamic: license-file
20
- Dynamic: requires-dist
21
- Dynamic: requires-python
22
- Dynamic: summary
23
15
 
24
16
  # BTG Solutions - Data Services
25
17
 
@@ -280,6 +272,14 @@ hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
280
272
  hist_candles.get_intraday_history_candles(ticker='PETR4', market_type='stocks', corporate_events_adj=True, date='2023-10-06', candle='1m', rmv_after_market=True, timezone='UTC', raw_data=False, round=True)
281
273
  ```
282
274
 
275
+ ##### Interday Batch
276
+
277
+ ```python
278
+ import btgsolutions_dataservices as btg
279
+ hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
280
+ hist_candles.get_interday_history_candles_batch(market_type='stocks', tickers=['PETR4', 'VALE3'], start_date='2023-10-01', end_date='2023-10-13', corporate_events_adj=True, rmv_after_market=True, timezone='UTC', raw_data=False, round=True)
281
+ ```
282
+
283
283
  ##### Available Tickers
284
284
 
285
285
  ```python
@@ -510,23 +510,33 @@ import btgsolutions_dataservices as btg
510
510
  book_scope = btg.BookScope(api_key='YOUR_API_KEY')
511
511
 
512
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',
513
+ symbol='DOLM26',
514
+ market_type='derivatives',
515
+ start_time='2026-05-28T14:12:00Z',
516
+ end_time='2026-05-28T14:15:00Z',
517
517
  select=['trades', 'book_snapshot', 'book_incremental'], # choose one, two, or all three
518
518
  )
519
519
 
520
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',
521
+ symbol='DOLM26',
522
+ market_type='derivatives',
523
+ start_time='2026-05-28T14:12:00Z',
524
+ end_time='2026-05-28T14:15:00Z',
525
525
  select=['trades', 'book_snapshot', 'book_incremental'],
526
526
  aggregate_info=True,
527
527
  )
528
528
  ```
529
529
 
530
+ #### Broker Analytics
531
+
532
+ ```python
533
+ import btgsolutions_dataservices as btg
534
+ broker_analytics = btg.BrokerAnalytics(api_key='YOUR_API_KEY', market_type='stocks')
535
+ summary = broker_analytics.get_summary(brokers=['85', '3'], tickers=['PETR4', 'ABCB4'])
536
+ top_brokers = broker_analytics.get_top_brokers(n=10)
537
+ top_tickers = broker_analytics.get_top_tickers(n=10, brokers=['85', '3'])
538
+ ```
539
+
530
540
  #### Ticker Reference Data
531
541
 
532
542
  ```python
@@ -10,6 +10,7 @@ btgsolutions_dataservices/exceptions.py
10
10
  btgsolutions_dataservices/rest/__init__.py
11
11
  btgsolutions_dataservices/rest/authenticator.py
12
12
  btgsolutions_dataservices/rest/book_scope.py
13
+ btgsolutions_dataservices/rest/broker_analytics.py
13
14
  btgsolutions_dataservices/rest/broker_reference.py
14
15
  btgsolutions_dataservices/rest/bulk_data.py
15
16
  btgsolutions_dataservices/rest/company_data.py