btgsolutions-dataservices-python-client 2.10.1__py3-none-any.whl → 2.11.4__py3-none-any.whl

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.
@@ -53,6 +53,10 @@ VALID_MARKET_DATA_TYPES = [
53
53
  ]
54
54
  VALID_MARKET_DATA_SUBTYPES = [ALL, STOCKS, OPTIONS, DERIVATIVES]
55
55
 
56
+ FEED_A = "A"
57
+ FEED_B = "B"
58
+ VALID_FEEDS = [FEED_A, FEED_B]
59
+
56
60
  market_data_socket_urls = {
57
61
  B3: {
58
62
  TRADES: {
@@ -158,4 +158,32 @@ class HistoricalCandles:
158
158
  return response_data if raw_data else pd.DataFrame(response_data)
159
159
 
160
160
  response = json.loads(response.text)
161
- raise BadResponse(f'Error: {response.get("ApiClientError", "")}.\n{response.get("SuggestedAction", "")}')
161
+ raise BadResponse(f'Error: {response.get("ApiClientError", "")}.\n{response.get("SuggestedAction", "")}')
162
+
163
+ def get_available_tickers(
164
+ self,
165
+ market_type:str,
166
+ date:str,
167
+ ):
168
+ """
169
+ This method provides all tickers available for query.
170
+
171
+ Parameters
172
+ ----------------
173
+ market_type: str
174
+ Market type.
175
+ Options: 'stocks', 'derivatives' or 'indices'.
176
+ Field is required.
177
+ date: string<date>
178
+ Date of requested data. Format: "YYYY-MM-DD".
179
+ Field is required. Example: '2023-10-06'.
180
+ """
181
+
182
+ if market_type not in ['stocks', 'derivatives', 'indices']: raise MarketTypeError(f"Must provide a valid 'market_type' parameter. Input: '{market_type}'. Accepted values: 'stocks', 'derivatives' or 'indices'.")
183
+
184
+ url = f"{url_apis_v3}/marketdata/history/candles/available-tickers/{market_type}?date={date}"
185
+
186
+ response = requests.request("GET", url, headers=self.headers)
187
+ if response.status_code == 200: return response.json()
188
+ response = response.json()
189
+ raise BadResponse(f'Error: {response.get("ApiClientError", "") or response.get("ApiServerMessage", "")}.\n{response.get("SuggestedAction", "")}')
@@ -1,2 +1,3 @@
1
1
  from .market_data_websocket_client import MarketDataWebSocketClient
2
- from .hfn_websocket_client import HFNWebSocketClient
2
+ from .hfn_websocket_client import HFNWebSocketClient
3
+ from .market_data_feed import MarketDataFeed
@@ -0,0 +1,315 @@
1
+ from typing import Optional, Callable, List
2
+ import websocket
3
+ import time
4
+ from datetime import date
5
+ import multiprocessing
6
+ import logging
7
+ from logging.handlers import QueueHandler, QueueListener
8
+ import json
9
+ import ssl
10
+ import threading
11
+ from ..rest import Authenticator
12
+ from ..config import market_data_socket_urls, market_data_feedb_socket_urls, REALTIME, B3, TRADES, BOOKS, FEED_A, FEED_B, MAX_WS_RECONNECT_RETRIES
13
+ from .websocket_default_functions import _on_open, _on_message_already_serialized, _on_error, _on_close
14
+
15
+ multiprocessing.set_start_method("spawn", force=True)
16
+
17
+ class MarketDataFeed:
18
+ """
19
+ WebSocket client that connects with BTG Solutions Data Services WebSocket servers. The servers streams realtime and delayed market data, such as trades and book events.
20
+ This is a multiprocessing-based WebSocket client designed for high-performance, scalable message handling applications. It leverages a system of inter-process communication to efficiently separate concerns and prevent the main application thread from blocking during WebSocket operations or message processing.
21
+
22
+ * Main use case:
23
+
24
+ >>> from btgsolutions_dataservices import MarketDataFeed
25
+ >>> ws = MarketDataFeed(
26
+ >>> api_key='YOUR_API_KEY',
27
+ >>> stream_type='realtime',
28
+ >>> exchange='b3',
29
+ >>> data_type='trades',
30
+ >>> data_subtype='stocks',
31
+ >>> ssl=True
32
+ >>> )
33
+ >>> ws.run()
34
+ >>> ws.subscribe(['MGLU3'])
35
+ >>> ws.unsubscribe(['PETR4'])
36
+ >>> ws.close()
37
+
38
+ Parameters
39
+ ----------------
40
+ api_key: str
41
+ User identification key.
42
+ Field is required.
43
+ stream_type: str
44
+ Websocket connection feed.
45
+ Options: 'realtime', 'delayed'.
46
+ Field is not required. Default: 'realtime'.
47
+ exchange: str
48
+ Exchange name.
49
+ Options: 'b3' or 'bmv'.
50
+ Field is not required. Default: 'b3'.
51
+ data_type: str
52
+ Market Data type.
53
+ Options: 'trades', 'processed-trades', 'books', 'indices', 'securities', 'stoploss', 'candles-1S', 'candles-1M', 'instrument_status'.
54
+ Field is not required. Default: 'trades'.
55
+ data_subtype: str
56
+ Market Data subtype (when applicable).
57
+ Options: 'stocks', 'options', 'derivatives'.
58
+ Field is not required. Default: None.
59
+ feed: str
60
+ Market Data Feed.
61
+ Options: 'A', 'B'.
62
+ Field is not required. Default: 'A' (enable).
63
+ ssl: bool
64
+ Enable or disable ssl configuration.
65
+ Field is not required. Default: True (enable).
66
+ reconnect: bool
67
+ Try reconnect if connection is closed.
68
+ Field is not required.
69
+ Default: True.
70
+ on_open: function
71
+ - Called at opening connection to websocket.
72
+ - Field is not required.
73
+ - Default: prints that the connection was opened in case of success.
74
+ on_message: function
75
+ - Called every time it receives a message.
76
+ - Arguments:
77
+ 1. Data received from the server.
78
+ - Field is not required.
79
+ - Default: prints the data.
80
+ on_error: function
81
+ - Called when a error occurs.
82
+ - Arguments:
83
+ 1. Exception object.
84
+ - Field is not required.
85
+ - Default: prints the error.
86
+ on_close: function
87
+ - Called when connection is closed.
88
+ - Arguments:
89
+ 1. close_status_code.
90
+ 2. close_msg.
91
+ - Field is not required.
92
+ - Default: prints a message that the connection was closed.
93
+ log_level: str
94
+ Log level sets how much information the program will print to the log file.
95
+ Options: 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'NOTSET'.
96
+ 'DEBUG' provides the most detailed logs, with verbosity decreasing through each level down to 'NOTSET', which disables all logging.
97
+ Field is not required. Default: 'DEBUG'.
98
+ """
99
+
100
+ def __init__(
101
+ self,
102
+ api_key: str,
103
+ stream_type: Optional[str]=REALTIME,
104
+ exchange: Optional[str]=B3,
105
+ data_type: Optional[str]=TRADES,
106
+ data_subtype: Optional[str]=None,
107
+ feed: Optional[str]=FEED_A,
108
+ ssl: Optional[bool]=True,
109
+ reconnect: bool=True,
110
+ on_open: Optional[Callable]=None,
111
+ on_message: Optional[Callable]=None,
112
+ on_error: Optional[Callable]=None,
113
+ on_close: Optional[Callable]=None,
114
+ log_level: str="DEBUG",
115
+ ):
116
+
117
+ if feed == FEED_B:
118
+ url_feed_map = market_data_feedb_socket_urls
119
+ else:
120
+ url_feed_map = market_data_socket_urls
121
+
122
+ try:
123
+ self.url = url_feed_map[exchange][data_type][stream_type][data_subtype]
124
+ except:
125
+ raise Exception(f"There is no WebSocket type for your specifications (stream_type:{stream_type}, exchange:{exchange}, data_type:{data_type}, data_subtype:{data_subtype})\nPlease check your request parameters and try again")
126
+
127
+ self.__authenticator = Authenticator(api_key)
128
+
129
+ self.data_type = data_type
130
+ self.on_open = _on_open if on_open is None else on_open
131
+ self.on_message = _on_message_already_serialized if on_message is None else on_message
132
+ self.on_error = _on_error if on_error is None else on_error
133
+ self.on_close = _on_close if on_close is None else on_close
134
+
135
+ self.ssl = ssl
136
+ self.reconnect = reconnect
137
+ self.__nro_reconnect_retries = 0
138
+
139
+ self.server_message_queue = multiprocessing.Queue()
140
+ self.client_message_queue = multiprocessing.Queue()
141
+ self.log_queue = multiprocessing.Queue()
142
+
143
+ log_level = getattr(logging, log_level)
144
+ self.log_level = log_level
145
+
146
+ log_handler = logging.FileHandler(filename=f"MarketDataFeed_{date.today().isoformat()}.log")
147
+ log_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
148
+
149
+ log_queue_listener = QueueListener(self.log_queue, log_handler)
150
+ log_queue_listener.start()
151
+
152
+ self.logger = logging.getLogger("main")
153
+ self.logger.setLevel(log_level)
154
+ self.logger.addHandler(QueueHandler(self.log_queue))
155
+
156
+ self.process = None
157
+ self.running = False
158
+
159
+ def _ws_client_process(self, server_message_queue: multiprocessing.Queue, client_message_queue: multiprocessing.Queue, log_queue: multiprocessing.Queue, log_level: int):
160
+
161
+ logger = logging.getLogger("client")
162
+ logger.setLevel(log_level)
163
+ logger.addHandler(QueueHandler(log_queue))
164
+
165
+ def on_message(ws, message):
166
+ server_message_queue.put(json.loads(message))
167
+
168
+ def on_error(ws, error):
169
+ logger.error(f"On Error | {error}")
170
+ self.on_error(error)
171
+
172
+ def on_close(ws, close_status_code, close_msg):
173
+ logger.warning(f"On Close | Connection closed")
174
+ self.on_close(close_status_code, close_msg)
175
+ if self.reconnect:
176
+ if self.__nro_reconnect_retries == MAX_WS_RECONNECT_RETRIES:
177
+ logger.critical(f"On Close | Maximum number of reconnect attempts reached")
178
+ return
179
+ self.__nro_reconnect_retries += 1
180
+ logger.warning(f"On Close | Reconnecting... attempt: {self.__nro_reconnect_retries}/{MAX_WS_RECONNECT_RETRIES}")
181
+ run_forever_new_thread()
182
+
183
+ def on_open(ws):
184
+ logger.info(f"On Open | Connection open")
185
+ self.on_open()
186
+ self.__nro_reconnect_retries = 0
187
+
188
+ ws = websocket.WebSocketApp(
189
+ url=self.url,
190
+ on_open=on_open,
191
+ on_message=on_message,
192
+ on_error=on_error,
193
+ on_close=on_close,
194
+ header={
195
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36",
196
+ "Sec-WebSocket-Protocol": self.__authenticator.token,
197
+ }
198
+ )
199
+
200
+ def run_forever_new_thread():
201
+ ssl_conf = {} if self.ssl else {"sslopt": {"cert_reqs": ssl.CERT_NONE}}
202
+ t = threading.Thread(target=ws.run_forever, kwargs=ssl_conf)
203
+ t.daemon = True
204
+ t.start()
205
+
206
+ while True:
207
+ if ws.sock is not None and ws.sock.connected:
208
+ break
209
+ pass
210
+
211
+ while True:
212
+ try:
213
+ if not client_message_queue.empty():
214
+ msg = client_message_queue.get()
215
+ ws.send(json.dumps(msg))
216
+ else:
217
+ time.sleep(0.05)
218
+ except Exception as e:
219
+ time.sleep(0.1)
220
+
221
+ run_forever_new_thread()
222
+
223
+ def run(self):
224
+ """
225
+ Opens a new connection with the websocket server.
226
+ """
227
+ self.process = multiprocessing.Process(target=self._ws_client_process, args=(self.server_message_queue, self.client_message_queue, self.log_queue, self.log_level))
228
+ self.process.start()
229
+ self.running = True
230
+
231
+ def run_on_new_thread(*args):
232
+ log_timer = time.time()
233
+ while self.running:
234
+ if not self.server_message_queue.empty():
235
+ msg = self.server_message_queue.get()
236
+ self.on_message(msg)
237
+ else:
238
+ time.sleep(0.01)
239
+
240
+ if time.time() - log_timer >= 5.0:
241
+ server_queue_size = self.server_message_queue.qsize()
242
+ client_queue_size = self.client_message_queue.qsize()
243
+ self.logger.debug(f"Server queue: {server_queue_size} | Client queue: {client_queue_size}")
244
+ log_timer = time.time()
245
+
246
+ threading.Thread(target=run_on_new_thread).start()
247
+
248
+ def close(self):
249
+ """
250
+ Closes the connection with the websocket server.
251
+ """
252
+ self.running = False
253
+ if self.process and self.process.is_alive():
254
+ self.process.terminate()
255
+ self.process.join()
256
+
257
+ def _send(self, message):
258
+ """
259
+ Sends a message to the websocket server.
260
+ """
261
+ if not isinstance(message, str):
262
+ message = json.dumps(message)
263
+ self.client_message_queue.put(json.loads(message))
264
+
265
+ def subscribe(self, list_instruments: List[str], n=None):
266
+ """
267
+ Subscribes a list of instruments.
268
+
269
+ Parameters
270
+ ----------
271
+ list_instruments: list
272
+ Field is required.
273
+ n: int
274
+ Field is not required.
275
+ **For books data_type only.**
276
+ Maximum book level. It must be between 1 and 10.
277
+ """
278
+ if self.data_type == BOOKS and n is not None:
279
+ self._send({'action': 'subscribe', 'params': {"tickers": list_instruments, "n": n}})
280
+ else:
281
+ self._send({'action': 'subscribe', 'params': list_instruments})
282
+
283
+ def unsubscribe(self, list_instruments: List[str]):
284
+ """
285
+ Unsubscribes a list of instruments.
286
+
287
+ Parameters
288
+ ----------
289
+ list_instruments: list
290
+ Field is required.
291
+ """
292
+ self._send({'action': 'unsubscribe', 'params': list_instruments})
293
+
294
+ def subscribed_to(self):
295
+ """
296
+ Return client subscribed tickers.
297
+ """
298
+ self._send({'action': 'subscribed_to'})
299
+
300
+ def available_to_subscribe(self):
301
+ """
302
+ Return avaiable tickers to subscribe.
303
+ """
304
+ self._send({'action': 'available_to_subscribe'})
305
+
306
+ def get_last_event(self, ticker: str):
307
+ """
308
+ Get the last event for the provided ticker.
309
+
310
+ Parameters
311
+ ----------
312
+ ticker: str
313
+ Field is required.
314
+ """
315
+ self._send({'action': 'get_last_event', 'params': ticker})
@@ -2,7 +2,7 @@
2
2
  from typing import Optional, List
3
3
  from ..exceptions import WSTypeError, DelayedError, FeedError
4
4
  from ..rest import Authenticator
5
- from ..config import market_data_socket_urls, market_data_feedb_socket_urls, MAX_WS_RECONNECT_RETRIES, VALID_STREAM_TYPES, VALID_EXCHANGES, VALID_MARKET_DATA_TYPES, VALID_MARKET_DATA_SUBTYPES, REALTIME, B3, TRADES, INDICES, ALL, STOCKS, BOOKS
5
+ from ..config import market_data_socket_urls, market_data_feedb_socket_urls, MAX_WS_RECONNECT_RETRIES, VALID_STREAM_TYPES, VALID_EXCHANGES, VALID_MARKET_DATA_TYPES, VALID_MARKET_DATA_SUBTYPES, REALTIME, B3, TRADES, INDICES, ALL, STOCKS, BOOKS, FEED_A, FEED_B
6
6
  from .websocket_default_functions import _on_open, _on_message, _on_error, _on_close
7
7
  import websocket
8
8
  import json
@@ -80,7 +80,7 @@ class MarketDataWebSocketClient:
80
80
  data_subtype: Optional[str] = None,
81
81
  instruments: Optional[List[str]] = [],
82
82
  ssl: Optional[bool] = True,
83
- feed: Optional[str] = "A",
83
+ feed: Optional[str] = FEED_A,
84
84
  **kwargs,
85
85
  ):
86
86
  self.api_key = api_key
@@ -114,7 +114,7 @@ class MarketDataWebSocketClient:
114
114
  raise FeedError(
115
115
  f"Must provide a valid 'data_subtype' parameter. Valid options are: {VALID_MARKET_DATA_SUBTYPES}")
116
116
 
117
- if feed == "B":
117
+ if feed == FEED_B:
118
118
  url_feed_map = market_data_feedb_socket_urls
119
119
  else:
120
120
  url_feed_map = market_data_socket_urls
@@ -1,5 +1,8 @@
1
1
  import json
2
2
 
3
+ def _on_message_already_serialized(message):
4
+ print(message)
5
+
3
6
  def _on_message(message):
4
7
  print(json.loads(message))
5
8
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: btgsolutions-dataservices-python-client
3
- Version: 2.10.1
3
+ Version: 2.11.4
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
@@ -21,9 +21,9 @@ Dynamic: requires-dist
21
21
  Dynamic: requires-python
22
22
  Dynamic: summary
23
23
 
24
- # BTG Solutions - Data Service
24
+ # BTG Solutions - Data Services
25
25
 
26
- Python library to get Brazilian Financial Market Data.
26
+ Real time and historical Financial Market Data, News, Corporate Events and more.
27
27
 
28
28
  ## Installation
29
29
 
@@ -31,61 +31,62 @@ Python library to get Brazilian Financial Market Data.
31
31
  pip3 install btgsolutions-dataservices-python-client
32
32
  ```
33
33
 
34
+ ## Documentation
35
+
36
+ The official documentation is hosted at https://python-client-docs.dataservices.btgpactualsolutions.com/
37
+
34
38
  ## Examples
35
39
 
36
- ### WebSocket Books
40
+ ### Real Time Data
41
+
42
+ #### Market Data Stream (optimized for performance)
37
43
 
38
44
  ```python
39
45
  import btgsolutions_dataservices as btg
40
- ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='books', instruments=['PETR4', 'VALE3'])
41
- ws.run(on_message=lambda message: print(message))
46
+ ws = btg.MarketDataFeed(api_key='YOUR_API_KEY', data_type='books', data_subtype='stocks')
47
+ ws.run()
48
+ ws.subscribe(['PETR4'])
42
49
 
43
50
  ## The following is optional to keep the program running in a .py file:
44
51
  # from time import sleep
45
52
  # while True:
46
53
  # sleep(1)
47
-
48
- ## Another examples
49
- # ws.available_to_subscribe()
50
54
  ```
51
55
 
52
- ### WebSocket Trades Delayed
56
+ #### Market Data Stream
57
+
58
+ ##### Books
53
59
 
54
60
  ```python
55
61
  import btgsolutions_dataservices as btg
56
- ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='trades', stream_type='delayed', instruments=['PETR4', 'VALE3'])
62
+ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='books', instruments=['PETR4', 'VALE3'])
57
63
  ws.run(on_message=lambda message: print(message))
58
64
 
59
65
  ## The following is optional to keep the program running in a .py file:
60
66
  # from time import sleep
61
67
  # while True:
62
68
  # sleep(1)
63
-
64
- ## Another examples
65
- # ws.available_to_subscribe()
66
69
  ```
67
70
 
68
- ### WebSocket Trades with 1 second throttle
71
+ ##### Books, Top Of Book (n=1)
69
72
 
70
73
  ```python
71
74
  import btgsolutions_dataservices as btg
72
- ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='trades', stream_type='throttle', instruments=['PETR4', 'VALE3'])
75
+ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='books')
73
76
  ws.run(on_message=lambda message: print(message))
77
+ ws.subscribe(['PETR4', 'VALE3'], n=1)
74
78
 
75
79
  ## The following is optional to keep the program running in a .py file:
76
80
  # from time import sleep
77
81
  # while True:
78
82
  # sleep(1)
79
-
80
- ## Another examples
81
- # ws.available_to_subscribe()
82
83
  ```
83
84
 
84
- ### WebSocket Securities (Derivatives)
85
+ ##### Trades
85
86
 
86
87
  ```python
87
88
  import btgsolutions_dataservices as btg
88
- ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='securities', data_subtype='derivatives')
89
+ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='trades', instruments=['PETR4', 'VALE3'])
89
90
  ws.run(on_message=lambda message: print(message))
90
91
 
91
92
  ## The following is optional to keep the program running in a .py file:
@@ -94,32 +95,25 @@ ws.run(on_message=lambda message: print(message))
94
95
  # sleep(1)
95
96
  ```
96
97
 
97
- ### WebSocket Candles 1S
98
+ ##### Trades, delayed (15 minutes delay)
98
99
 
99
100
  ```python
100
101
  import btgsolutions_dataservices as btg
101
- ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='candles-1S', stream_type='realtime')
102
+ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='trades', stream_type='delayed', instruments=['PETR4', 'VALE3'])
102
103
  ws.run(on_message=lambda message: print(message))
103
- ws.candle_subscribe(list_instruments=['PETR4','VALE3'], candle_type='partial')
104
104
 
105
105
  ## The following is optional to keep the program running in a .py file:
106
106
  # from time import sleep
107
107
  # while True:
108
108
  # sleep(1)
109
-
110
- ## Another examples
111
- # ws.candle_subscribe(list_instruments=['PRIO3'], candle_type='closed')
112
- # ws.candle_subscribe(list_instruments=['WEGE3'], candle_type='all')
113
- # ws.candle_unsubscribe(list_instruments=['PRIO3', 'PETR4'], candle_type='all')
114
109
  ```
115
110
 
116
- ### WebSocket NASDAQ (US) Trades
111
+ ##### Trades, throttle (1 second throttle)
117
112
 
118
113
  ```python
119
114
  import btgsolutions_dataservices as btg
120
- ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', exchange='nasdaq', data_type='trades')
115
+ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='trades', stream_type='throttle', instruments=['PETR4', 'VALE3'])
121
116
  ws.run(on_message=lambda message: print(message))
122
- ws.subscribe(['AMZN', 'GOOG', 'TSLA'])
123
117
 
124
118
  ## The following is optional to keep the program running in a .py file:
125
119
  # from time import sleep
@@ -127,12 +121,13 @@ ws.subscribe(['AMZN', 'GOOG', 'TSLA'])
127
121
  # sleep(1)
128
122
  ```
129
123
 
130
- ### WebSocket BMV (MX) Trades
124
+ ##### Trades, NASDAQ (US)
131
125
 
132
126
  ```python
133
127
  import btgsolutions_dataservices as btg
134
- ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', exchange='bmv', data_type='trades')
128
+ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', exchange='nasdaq', data_type='trades')
135
129
  ws.run(on_message=lambda message: print(message))
130
+ ws.subscribe(['AMZN', 'GOOG', 'TSLA'])
136
131
 
137
132
  ## The following is optional to keep the program running in a .py file:
138
133
  # from time import sleep
@@ -140,39 +135,33 @@ ws.run(on_message=lambda message: print(message))
140
135
  # sleep(1)
141
136
  ```
142
137
 
143
- ### WebSocket Books (without spawning a new thread for incoming server messages)
138
+ ##### Trades, BMV (MX)
144
139
 
145
140
  ```python
146
141
  import btgsolutions_dataservices as btg
147
- ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='books', instruments=['PETR4', 'VALE3'])
148
- ws.run(on_message=lambda message: print(message), spawn_thread=False)
142
+ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', exchange='bmv', data_type='trades')
143
+ ws.run(on_message=lambda message: print(message))
149
144
 
150
145
  ## The following is optional to keep the program running in a .py file:
151
146
  # from time import sleep
152
147
  # while True:
153
148
  # sleep(1)
154
-
155
- ## Another examples
156
- # ws.available_to_subscribe()
157
149
  ```
158
150
 
159
- ### WebSocket Books with n = 1 (Book TOB - Top Of Book)
151
+ ##### Security List
160
152
 
161
153
  ```python
162
154
  import btgsolutions_dataservices as btg
163
- ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='books')
155
+ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='securities', data_subtype='derivatives')
164
156
  ws.run(on_message=lambda message: print(message))
165
- ws.subscribe(['PETR4', 'VALE3'], n=1)
157
+
166
158
  ## The following is optional to keep the program running in a .py file:
167
159
  # from time import sleep
168
160
  # while True:
169
161
  # sleep(1)
170
-
171
- ## Another examples
172
- # ws.available_to_subscribe()
173
162
  ```
174
163
 
175
- ### WebSocket Instrument Status
164
+ ##### Security Status
176
165
 
177
166
  ```python
178
167
  import btgsolutions_dataservices as btg
@@ -180,18 +169,20 @@ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='books')
180
169
  ws.run(on_message=lambda message: print(message))
181
170
  ws.instrument_status('PETR4')
182
171
  ws.instrument_status_history('PETR4')
172
+
183
173
  ## The following is optional to keep the program running in a .py file:
184
174
  # from time import sleep
185
175
  # while True:
186
176
  # sleep(1)
187
177
  ```
188
178
 
189
- ### WebSocket High Frequency News
179
+ ##### Candles (1 second candles)
190
180
 
191
181
  ```python
192
182
  import btgsolutions_dataservices as btg
193
- ws = btg.HFNWebSocketClient(api_key='YOUR_API_KEY', country='brazil')
183
+ ws = btg.MarketDataWebSocketClient(api_key='YOUR_API_KEY', data_type='candles-1S', stream_type='realtime')
194
184
  ws.run(on_message=lambda message: print(message))
185
+ ws.candle_subscribe(list_instruments=['PETR4','VALE3'], candle_type='partial')
195
186
 
196
187
  ## The following is optional to keep the program running in a .py file:
197
188
  # from time import sleep
@@ -199,7 +190,7 @@ ws.run(on_message=lambda message: print(message))
199
190
  # sleep(1)
200
191
  ```
201
192
 
202
- ### IntradayCandles
193
+ #### Intraday Candles
203
194
 
204
195
  ```python
205
196
  import btgsolutions_dataservices as btg
@@ -207,47 +198,69 @@ int_candles = btg.IntradayCandles(api_key='YOUR_API_KEY')
207
198
  int_candles.get_intraday_candles(market_type='stocks', tickers=['PETR4', 'VALE3'], candle_period='1m', delay='delayed', mode='relative', timezone='UTC', raw_data=True)
208
199
  ```
209
200
 
210
- ### Get Interday History Candles
201
+ #### Intraday Tick Data
211
202
 
212
203
  ```python
213
204
  import btgsolutions_dataservices as btg
214
- hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
215
- hist_candles.get_interday_history_candles(ticker='PETR4', market_type='stocks', corporate_events_adj=True, start_date='2023-10-01', end_date='2023-10-13', rmv_after_market=True, timezone='UTC', raw_data=False)
205
+ intra_tickdata = btg.IntradayTickData(api_key='YOUR_API_KEY')
206
+ intra_tickdata.get_trades(ticker='PETR4')
207
+ ```
208
+
209
+ #### Quotes
210
+
211
+ ```python
212
+ import btgsolutions_dataservices as btg
213
+ quotes = btg.Quotes(api_key='YOUR_API_KEY')
214
+ quotes.get_quote(market_type = 'stocks', tickers = ['PETR4', 'VALE3'])
216
215
  ```
217
216
 
218
- ### Get Intraday History Candles
217
+ #### Ticker Last Event
218
+
219
+ ```python
220
+ import btgsolutions_dataservices as btg
221
+ last_event = btg.TickerLastEvent(api_key='YOUR_API_KEY')
222
+ last_event.get_trades(data_type='equities', ticker='VALE3')
223
+ ```
224
+
225
+ ### Historical Data
226
+
227
+ #### Historical Candles
228
+
229
+ ##### Interday
219
230
 
220
231
  ```python
221
232
  import btgsolutions_dataservices as btg
222
233
  hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
223
- 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)
234
+ hist_candles.get_interday_history_candles(ticker='PETR4', market_type='stocks', corporate_events_adj=True, start_date='2023-10-01', end_date='2023-10-13', rmv_after_market=True, timezone='UTC', raw_data=False)
224
235
  ```
225
236
 
226
- ### Plot History Candles
237
+ ##### Intraday
227
238
 
228
239
  ```python
229
240
  import btgsolutions_dataservices as btg
230
241
  hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
231
- 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).plot(x='candle_time', y='close_price', kind='scatter')
242
+ 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)
232
243
  ```
233
244
 
234
- ### Quotes
245
+ ##### Available Tickers
235
246
 
236
247
  ```python
237
248
  import btgsolutions_dataservices as btg
238
- quotes = btg.Quotes(api_key='YOUR_API_KEY')
239
- quotes.get_quote(market_type = 'stocks', tickers = ['PETR4', 'VALE3'])
249
+ hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
250
+ hist_candles.get_available_tickers(market_type='stocks', date='2025-05-29')
240
251
  ```
241
252
 
242
- ### Ticker Last Event
253
+ ##### Plot Candles
243
254
 
244
255
  ```python
245
256
  import btgsolutions_dataservices as btg
246
- last_event = btg.TickerLastEvent(api_key='YOUR_API_KEY')
247
- last_event.get_trades(data_type='equities', ticker='VALE3')
257
+ hist_candles = btg.HistoricalCandles(api_key='YOUR_API_KEY')
258
+ 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).plot(x='candle_time', y='close_price', kind='scatter')
248
259
  ```
249
260
 
250
- ### BulkData - Available Tickers
261
+ #### Historical Tick Data (Bulk Data)
262
+
263
+ ##### Available Tickers
251
264
 
252
265
  ```python
253
266
  import btgsolutions_dataservices as btg
@@ -255,7 +268,7 @@ bulk_data = btg.BulkData(api_key='YOUR_API_KEY')
255
268
  bulk_data.get_available_tickers(date='2023-07-03', data_type='trades', prefix='PETR')
256
269
  ```
257
270
 
258
- ### BulkData - Get Data
271
+ ##### Get Data
259
272
 
260
273
  ```python
261
274
  import btgsolutions_dataservices as btg
@@ -266,15 +279,15 @@ bulk_data.get_data(ticker='DI1F18', date='2017-01-02', data_type='trades')
266
279
  # bulk_data.get_data(ticker='PETR4', date='2025-05-07', data_type='instrument-status')
267
280
  ```
268
281
 
269
- ### BulkData - Get Security List
282
+ ##### Security List
270
283
 
271
284
  ```python
272
285
  import btgsolutions_dataservices as btg
273
286
  bulk_data = btg.BulkData(api_key='YOUR_API_KEY')
274
- bulk_data.security-list(date='2025-05-07')
287
+ bulk_data.get_security_list(date='2025-05-07')
275
288
  ```
276
289
 
277
- ### BulkData - Get Market Data Channels
290
+ ##### Market Data Channels
278
291
 
279
292
  ```python
280
293
  import btgsolutions_dataservices as btg
@@ -282,7 +295,7 @@ bulk_data = btg.BulkData(api_key='YOUR_API_KEY')
282
295
  bulk_data.get_market_data_channels(date='2024-01-03')
283
296
  ```
284
297
 
285
- ### BulkData - Get Compressed Data (PCAP files)
298
+ ##### Compressed Data (PCAP files)
286
299
 
287
300
  ```python
288
301
  import btgsolutions_dataservices as btg
@@ -292,15 +305,22 @@ bulk_data.get_compressed_data(channel='001', date='2024-01-03', data_type='instr
292
305
  # bulk_data.get_compressed_data(channel='051', date='2024-01-03', data_type='snapshot')
293
306
  ```
294
307
 
295
- ### Intraday Tick Data
308
+ ### Alternative Data
309
+
310
+ #### High Frequency News Stream
296
311
 
297
312
  ```python
298
313
  import btgsolutions_dataservices as btg
299
- intra_tickdata = btg.IntradayTickData(api_key='YOUR_API_KEY')
300
- intra_tickdata.get_trades(ticker='PETR4')
314
+ ws = btg.HFNWebSocketClient(api_key='YOUR_API_KEY', country='brazil')
315
+ ws.run(on_message=lambda message: print(message))
316
+
317
+ ## The following is optional to keep the program running in a .py file:
318
+ # from time import sleep
319
+ # while True:
320
+ # sleep(1)
301
321
  ```
302
322
 
303
- ### High Frequency News
323
+ #### High Frequency News
304
324
 
305
325
  ```python
306
326
  import btgsolutions_dataservices as btg
@@ -308,17 +328,17 @@ hfn = btg.HighFrequencyNews(api_key='YOUR_API_KEY')
308
328
  hfn.latest_news()
309
329
  ```
310
330
 
311
- ### Corporate Events
331
+ #### OPA
312
332
 
313
333
  ```python
314
334
  import btgsolutions_dataservices as btg
315
- corporate_events = btg.CorporateEvents(api_key='YOUR_API_KEY')
316
- corporate_events.get(start_date='2024-05-01', end_date='2024-05-31')
317
- # corporate_events.get(start_date='2024-05-01', end_date='2024-05-31', tickers=['VALE3'])
335
+ public_sources = btg.PublicSources(api_key='YOUR_API_KEY')
336
+ public_sources.get_opas(start_date='2022-10-01', end_date='2024-10-01')
318
337
  ```
319
338
 
320
- ### Company Data
321
- #### Company General Information
339
+ #### Company Fundamentals
340
+
341
+ ##### Company General Information
322
342
 
323
343
  ```python
324
344
  import btgsolutions_dataservices as btg
@@ -326,7 +346,7 @@ company_data = btg.CompanyData(api_key='YOUR_API_KEY')
326
346
  company_data.general_info(ticker='PETR4')
327
347
  ```
328
348
 
329
- #### Income Statement
349
+ ##### Income Statement
330
350
 
331
351
  ```python
332
352
  import btgsolutions_dataservices as btg
@@ -334,7 +354,7 @@ company_data = btg.CompanyData(api_key='YOUR_API_KEY')
334
354
  company_data.income_statement(ticker='PETR4')
335
355
  ```
336
356
 
337
- #### Balance Sheet
357
+ ##### Balance Sheet
338
358
 
339
359
  ```python
340
360
  import btgsolutions_dataservices as btg
@@ -342,7 +362,7 @@ company_data = btg.CompanyData(api_key='YOUR_API_KEY')
342
362
  company_data.balance_sheet(ticker='PETR4')
343
363
  ```
344
364
 
345
- #### Cash Flow
365
+ ##### Cash Flow
346
366
 
347
367
  ```python
348
368
  import btgsolutions_dataservices as btg
@@ -350,7 +370,7 @@ company_data = btg.CompanyData(api_key='YOUR_API_KEY')
350
370
  company_data.cash_flow(ticker='PETR4')
351
371
  ```
352
372
 
353
- #### Valuation
373
+ ##### Valuation
354
374
 
355
375
  ```python
356
376
  import btgsolutions_dataservices as btg
@@ -358,7 +378,7 @@ company_data = btg.CompanyData(api_key='YOUR_API_KEY')
358
378
  company_data.valuation(ticker='PETR4')
359
379
  ```
360
380
 
361
- #### Ratios
381
+ ##### Ratios
362
382
 
363
383
  ```python
364
384
  import btgsolutions_dataservices as btg
@@ -366,7 +386,7 @@ company_data = btg.CompanyData(api_key='YOUR_API_KEY')
366
386
  company_data.ratios(ticker='PETR4')
367
387
  ```
368
388
 
369
- #### Growth
389
+ ##### Growth
370
390
 
371
391
  ```python
372
392
  import btgsolutions_dataservices as btg
@@ -374,7 +394,7 @@ company_data = btg.CompanyData(api_key='YOUR_API_KEY')
374
394
  company_data.growth(ticker='PETR4')
375
395
  ```
376
396
 
377
- #### Interims
397
+ ##### Interims
378
398
 
379
399
  ```python
380
400
  import btgsolutions_dataservices as btg
@@ -382,7 +402,7 @@ company_data = btg.CompanyData(api_key='YOUR_API_KEY')
382
402
  company_data.interims(ticker='PETR4')
383
403
  ```
384
404
 
385
- #### All Financial Tables
405
+ ##### All Financial Tables
386
406
 
387
407
  ```python
388
408
  import btgsolutions_dataservices as btg
@@ -390,22 +410,21 @@ company_data = btg.CompanyData(api_key='YOUR_API_KEY')
390
410
  company_data.all_financial_tables(ticker='PETR4')
391
411
  ```
392
412
 
393
- ### Public Sources - OPA
413
+ ### Reference Data
414
+
415
+ #### Corporate Events
394
416
 
395
417
  ```python
396
418
  import btgsolutions_dataservices as btg
397
- public_sources = btg.PublicSources(api_key='YOUR_API_KEY')
398
- public_sources.get_opas(start_date='2022-10-01', end_date='2024-10-01')
419
+ corporate_events = btg.CorporateEvents(api_key='YOUR_API_KEY')
420
+ corporate_events.get(start_date='2024-05-01', end_date='2024-05-31')
421
+ # corporate_events.get(start_date='2024-05-01', end_date='2024-05-31', tickers=['VALE3'])
399
422
  ```
400
423
 
401
- ### Reference Data - Ticker Reference
424
+ #### Ticker Reference Data
402
425
 
403
426
  ```python
404
427
  import btgsolutions_dataservices as btg
405
428
  ref = btg.ReferenceData(api_key='YOUR_API_KEY')
406
429
  ref.ticker_reference(tickers=['VALE3','PETR4'])
407
430
  ```
408
-
409
- ## Documentation
410
-
411
- The official documentation is hosted at https://python-client-docs.dataservices.btgpactualsolutions.com/
@@ -1,5 +1,5 @@
1
1
  btgsolutions_dataservices/__init__.py,sha256=reSSb9MBIp5WQ5o872fX__moJYXx0sQgkhUf3QmfEjI,93
2
- btgsolutions_dataservices/config.py,sha256=bwlApl8JtuKRP4J9rbQERo1Cuk32n1MBaqYBHeSKhFc,5024
2
+ btgsolutions_dataservices/config.py,sha256=syf7x6LL4WNAM0e6CI1BKfPHnprxWoww7llzvtV0QXs,5082
3
3
  btgsolutions_dataservices/exceptions.py,sha256=QlwQTDEohtVsTER0lHbQrDgAGvjiZBmoyDuqLkUcvh8,599
4
4
  btgsolutions_dataservices/rest/__init__.py,sha256=OI7KWRdAMG3oHABhaGn6nOsGCou4-FX7e0qH2rxChmE,494
5
5
  btgsolutions_dataservices/rest/authenticator.py,sha256=uBLARz5lCRhIDc_PZaC4a2rSQtrFJajmAC4Bdg9BnX0,1363
@@ -7,19 +7,20 @@ btgsolutions_dataservices/rest/bulk_data.py,sha256=26CrFH-IVMUbpPLx0HaN-BePs5R9A
7
7
  btgsolutions_dataservices/rest/company_data.py,sha256=yhsgR-P7g5e6TDdpoMZoyiyqI85roBCXJGyob4g1P_8,7318
8
8
  btgsolutions_dataservices/rest/corporate_events.py,sha256=04DdoUnBaX1rSAWplCLzNm-YPrKks80txOR26xubEZ0,2399
9
9
  btgsolutions_dataservices/rest/hfn.py,sha256=0E-oNw797M8XgbDfwbhmMaPaf9z-WN4rhMpMR_2dkos,11205
10
- btgsolutions_dataservices/rest/historical_candles.py,sha256=RYLLXaFMEe1yx4iaQJVSoV2T2xUEo1eIL8KuTR07MqY,6203
10
+ btgsolutions_dataservices/rest/historical_candles.py,sha256=0iu3clwbJUtwyHotxT5pb3xsqCJvpd6kRUsrYBVNU80,7359
11
11
  btgsolutions_dataservices/rest/intraday_candles.py,sha256=scH2eMh3ZhtWii_Kzv3PEGcUaLAUT-CAeswCY-3pYVc,5221
12
12
  btgsolutions_dataservices/rest/intraday_tick_data.py,sha256=VZZ-yPoQn9dZCJ9KnPYGwaEFq2FZi0oSnLDIIENYCNo,2469
13
13
  btgsolutions_dataservices/rest/public_sources.py,sha256=CMXsvHe8RKuEmJJ_baeVgsj28TrH2AYxE3TEfGSCdOQ,2459
14
14
  btgsolutions_dataservices/rest/quotes.py,sha256=sirlG1-_aCtE7auwYM7lTZkpMcW3UYisjtCaBWzPWuY,7508
15
15
  btgsolutions_dataservices/rest/reference_data.py,sha256=ntcHEMapKULGPHJvmzAnccUo8ZTGokt1M9bDBceV5Tk,2112
16
16
  btgsolutions_dataservices/rest/ticker_last_event.py,sha256=Lnm8sGS6wo6frL8yJddtBtEOEsPiodgjl4qq5Xdo0P0,2950
17
- btgsolutions_dataservices/websocket/__init__.py,sha256=pD5Rj9wV8UX5t5FQPp4BmqwtxTedshPPdYjduUGfrbU,120
17
+ btgsolutions_dataservices/websocket/__init__.py,sha256=Bifok6zQFenYNIA-NE8hYSooZVIQ2MCeTCjIOYnfHzI,165
18
18
  btgsolutions_dataservices/websocket/hfn_websocket_client.py,sha256=wzyPXtXFsv31cVFcTWrTA5uhFBebgM2IpIxXQvPSP54,6253
19
- btgsolutions_dataservices/websocket/market_data_websocket_client.py,sha256=kAavzTQUd1Ki838JRFwfbDsbEaIehRGJlx-eurVx0Lw,13353
20
- btgsolutions_dataservices/websocket/websocket_default_functions.py,sha256=OvqJoyIt2vopwL1z4Mj3EkkpnPsYrdWHux4825WCDsk,270
21
- btgsolutions_dataservices_python_client-2.10.1.dist-info/licenses/LICENSE,sha256=vePSp4Jry-f15vZ48xge2vljuhNgkMZD6wU0XmuFBgA,1057
22
- btgsolutions_dataservices_python_client-2.10.1.dist-info/METADATA,sha256=a0FB3b1aRRaqgNkPSXBOeSLMSlId2ZExwULzR63VAhI,11774
23
- btgsolutions_dataservices_python_client-2.10.1.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
24
- btgsolutions_dataservices_python_client-2.10.1.dist-info/top_level.txt,sha256=OaseSN41lI9j_Z-kHIE_XVo_m1hmGdAHE3EK1h5_Ce0,26
25
- btgsolutions_dataservices_python_client-2.10.1.dist-info/RECORD,,
19
+ btgsolutions_dataservices/websocket/market_data_feed.py,sha256=Zh3aqFLoVZPnA3LVXCRxcsPYdlQId9qifrQsBkWUWrg,11770
20
+ btgsolutions_dataservices/websocket/market_data_websocket_client.py,sha256=i_1kd6mdd9fLDYD54zx_t1HJPPBUdDzE4pojs3DIPLI,13375
21
+ btgsolutions_dataservices/websocket/websocket_default_functions.py,sha256=JWbOR4uX14BI9JB3zXMbwqVsF8AtfDbEC83fgs8O5PY,335
22
+ btgsolutions_dataservices_python_client-2.11.4.dist-info/licenses/LICENSE,sha256=vePSp4Jry-f15vZ48xge2vljuhNgkMZD6wU0XmuFBgA,1057
23
+ btgsolutions_dataservices_python_client-2.11.4.dist-info/METADATA,sha256=___fOIFhAUcvenXmiN89UeDuljLwG8JBwtmNoBq5hMc,11808
24
+ btgsolutions_dataservices_python_client-2.11.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ btgsolutions_dataservices_python_client-2.11.4.dist-info/top_level.txt,sha256=OaseSN41lI9j_Z-kHIE_XVo_m1hmGdAHE3EK1h5_Ce0,26
26
+ btgsolutions_dataservices_python_client-2.11.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.4.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5