Skip to content

Commit 0b541b4

Browse files
exception handling in user code (not ready)
1 parent 847289b commit 0b541b4

File tree

6 files changed

+131
-4
lines changed

6 files changed

+131
-4
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,16 @@ ubwa.api.cancel_order(orig_client_order_id=orig_client_order_id, symbol="BUSDUSD
177177
guide on
178178
[how to process requests via the Binance WebSocket API](https://medium.lucit.tech/create-and-cancel-orders-via-websocket-on-binance-7f828831404)!
179179

180+
## STREAM SIGNALS - know the state of your streams
181+
Usually you want to know when a stream is working and when it is not. This can be useful to know that your own system is
182+
currently "blind" and you may want to close open positions to be on the safe side, know that indicators will now provide
183+
incorrect values or that you have to reload the missing data via REST as an alternative.
184+
185+
For this purpose, the UNICORN Binance WebSocket API provides so-called
186+
[STREAM SIGNALS](https://github.com/LUCIT-Systems-and-Development/unicorn-binance-websocket-api/wiki/%60stream_signals%60)
187+
, which are used to tell your code in real time when a stream is connected, when it received its first data record, when
188+
it was disconnected and stopped, and when the stream cannot be restored.
189+
180190
## Stop `ubwa` after usage to avoid memory leaks
181191

182192
```

dev/test_stream_signals.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
from unicorn_binance_websocket_api import BinanceWebSocketApiManager
5+
import time
6+
7+
8+
def receive_stream_signal(self, signal_type=None, stream_id=None, data_record=None, error_msg=None):
9+
print(f"Received stream_signal for stream '{ubwa.get_stream_label(stream_id=stream_id)}': "
10+
f"{signal_type} - {stream_id} - {data_record} - {error_msg}")
11+
12+
13+
with BinanceWebSocketApiManager(process_stream_signals=receive_stream_signal) as ubwa:
14+
ubwa.create_stream(channels="trade", markets="btcusdt", stream_label="HEALTHY")
15+
print(f"Waiting 5 seconds and then stop the stream ...")
16+
time.sleep(5)
17+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Binance WebSocket Stream Signals
2+
## Overview
3+
Usually you want to know when a stream is working and when it is not. This can be useful to know that your own system is
4+
currently "blind" and you may want to close open positions to be on the safe side, know that indicators will now provide
5+
incorrect values or that you have to reload the missing data via REST as an alternative.
6+
7+
For this purpose, the UNICORN Binance WebSocket API provides so-called
8+
[STREAM SIGNALS](https://github.com/LUCIT-Systems-and-Development/unicorn-binance-websocket-api/wiki/%60stream_signals%60)
9+
, which are used to tell your code in real time when a stream is connected, when it received its first data record, when
10+
it was disconnected and stopped, and when the stream cannot be restored.
11+
12+
In this example, a stream is started and stopped. To keep the example lean and clear, we will not process any data, but
13+
only activate and process the stream signals.
14+
15+
## Prerequisites
16+
Ensure you have Python 3.7+ installed on your system.
17+
18+
Before running the provided script, install the required Python packages:
19+
```bash
20+
pip install -r requirements.txt
21+
```
22+
## Get a UNICORN Binance Suite License
23+
To run modules of the *UNICORN Binance Suite* you need a [valid license](https://shop.lucit.services)!
24+
25+
## Usage
26+
### Running the Script:
27+
```bash
28+
python binance_websocket_stream_signals.py
29+
```
30+
31+
### Graceful Shutdown:
32+
The script is designed to handle a graceful shutdown upon receiving a KeyboardInterrupt (e.g., Ctrl+C) or encountering
33+
an unexpected exception.
34+
35+
## Logging
36+
The script employs logging to provide insights into its operation and to assist in troubleshooting. Logs are saved to a
37+
file named after the script with a .log extension.
38+
39+
For further assistance or to report issues, please [contact our support team](https://www.lucit.tech/get-support.html)
40+
or [visit our GitHub repository](https://github.com/LUCIT-Systems-and-Development/unicorn-binance-websocket-api).
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
from unicorn_binance_websocket_api import BinanceWebSocketApiManager
5+
import asyncio
6+
import logging
7+
import os
8+
9+
logging.getLogger("unicorn_binance_websocket_api")
10+
logging.basicConfig(level=logging.INFO,
11+
filename=os.path.basename(__file__) + '.log',
12+
format="{asctime} [{levelname:8}] {process} {thread} {module}: {message}",
13+
style="{")
14+
15+
16+
class BinanceDataProcessor:
17+
def __init__(self):
18+
self.ubwa = BinanceWebSocketApiManager(process_stream_signals=self.receive_stream_signal)
19+
20+
async def main(self):
21+
print(f"In the Wiki you will find detailed information about the respective stream signal types: "
22+
f"https://github.com/LUCIT-Systems-and-Development/unicorn-binance-websocket-api/wiki/%60stream_signals%60")
23+
print(f"\r\nExample of invalid API credentials:")
24+
self.ubwa.create_stream(channels="arr", markets="!userData", stream_label="INVALID_CREDENTIALS",
25+
api_key="something", api_secret="wrong")
26+
await asyncio.sleep(3)
27+
print(f"\r\nExample of a healthy stream:")
28+
stream_id = self.ubwa.create_stream(channels="trade", markets="btcusdt", stream_label="HEALTHY")
29+
await asyncio.sleep(2)
30+
print(f"Waiting 5 seconds and then stop the stream ...")
31+
await asyncio.sleep(5)
32+
self.ubwa.stop_stream(stream_id=stream_id)
33+
await asyncio.sleep(5)
34+
35+
def receive_stream_signal(self, signal_type=None, stream_id=None, data_record=None, error_msg=None):
36+
print(f"Received stream_signal for stream '{self.ubwa.get_stream_label(stream_id=stream_id)}': "
37+
f"{signal_type} - {stream_id} - {data_record} - {error_msg}")
38+
39+
40+
if __name__ == "__main__":
41+
bdp = BinanceDataProcessor()
42+
try:
43+
asyncio.run(bdp.main())
44+
except KeyboardInterrupt:
45+
print("\r\nGracefully stopping ...")
46+
except Exception as e:
47+
print(f"\r\nError: {e}\r\nGracefully stopping ...")
48+
bdp.ubwa.stop_manager()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
unicorn-binance-websocket-api

unicorn_binance_websocket_api/manager.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -855,10 +855,21 @@ def _create_stream_thread(self,
855855
logger.debug(f"BinanceWebSocketApiManager._create_stream_thread() stream_id={str(stream_id)} "
856856
f" - RuntimeError `error: 12` - error_msg: {str(error_msg)}")
857857
except Exception as error_msg:
858-
logger.critical(f"BinanceWebSocketApiManager._create_stream_thread({str(stream_id)} - Unknown Exception - "
859-
f"Please report this issue if your stream does not restart: "
860-
f"https://github.com/LUCIT-Systems-and-Development/unicorn-binance-websocket-api/issues/new/choose"
861-
f" - error_msg: {str(error_msg)}")
858+
stream_label = self.get_stream_label(stream_id=stream_id)
859+
if stream_label is None:
860+
stream_label = ""
861+
else:
862+
stream_label = f" ({stream_label})"
863+
error_msg_wrapper = (f"Exception within a coroutine of stream '{stream_id}'{stream_label}: "
864+
f"\033[1m\033[31m{type(error_msg).__name__} - {error_msg}\033[0m\r\n"
865+
f"{traceback.format_exc()}")
866+
print(f"\r\n{error_msg_wrapper}")
867+
error_msg_wrapper = (f"Exception within to UBWA`s provided `process_asyncio_queue`-coroutine of stream "
868+
f"'{stream_id}'{stream_label}: "
869+
f"{type(error_msg).__name__} - {error_msg}\r\n"
870+
f"{traceback.format_exc()}")
871+
logger.critical(error_msg_wrapper)
872+
self._crash_stream(stream_id=stream_id, error_msg=error_msg_wrapper)
862873
finally:
863874
logger.debug(f"Finally closing the loop stream_id={str(stream_id)}")
864875
try:

0 commit comments

Comments
 (0)