Repository: ccxt/ccxt
Pull request: fix(bitmex): guard handleOrderBook
fix: ccxt/ccxt#22769

Problem statement:
BitMEX - watch_order_book error once a day - safe_string default value NoneType and operation of return is to append a string
### Operating System

Ubuntu 20.04

### Programming Languages

Python

### CCXT Version

4.3.6

### Description

We are running a long-lived websocket connection for fetching the orderbook prices for XBTUSD on BitMEX. At least once a day, like clockwork, we get an exception that is born out of the guts of ccxt (it happens at around 2AM UTC every day, rarely it can also happen other times).

I assume the reason it happens on schedule is a BitMEX side thing - perhaps they are reseting all WS subscriptions on a clock. CCXT should have the internals for handling this. The issue seems to be that the return of the "safe_string" default is NoneType (when no alternative provided), but the operation on the return of this for 'table' is to append a string to it, which causes the exception below. I assume simply speciyfying a default_value == '' will suffice to avoid this exception, but I don't know what knock-on effects that may have down the line here so probably best to check here first.

### Stack Trace:
```
 File "/home/ubuntu/env/lib/python3.10/site-packages/ccxt/pro/bitmex.py", line 1121, in watch_order_book
    return await self.watch_order_book_for_symbols([symbol], limit, params)
  File "/home/ubuntu/env/lib/python3.10/site-packages/ccxt/pro/bitmex.py", line 1156, in watch_order_book_for_symbols
    orderbook = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), topics)
  File "/home/ubuntu/env/lib/python3.10/site-packages/ccxt/async_support/base/ws/fast_client.py", line 26, in handler
    self.handle_message(message)
  File "/home/ubuntu/env/lib/python3.10/site-packages/ccxt/async_support/base/ws/aiohttp_client.py", line 34, in handle_message
    self.handle_text_or_binary_message(message.data)
  File "/home/ubuntu/env/lib/python3.10/site-packages/ccxt/async_support/base/ws/aiohttp_client.py", line 29, in handle_text_or_binary_message
    self.on_message_callback(self, decoded)
  File "/home/ubuntu/env/lib/python3.10/site-packages/ccxt/pro/bitmex.py", line 1553, in handle_message
    method(client, message)
  File "/home/ubuntu/env/lib/python3.10/site-packages/ccxt/pro/bitmex.py", line 1402, in handle_order_book
    messageHash = table + ':' + symbol
TypeError: can only concatenate str (not "NoneType") to str
``` 

### Code I assume needs to be changed (?)

Current:
```
def handle_order_book(self, client: Client, message):
   (...)
   table = self.safe_string(message, 'table')
   (...)
```

To:
```
def handle_order_book(self, client: Client, message):
   (...)
   table = self.safe_string(message, 'table', '')
   (...)
```

### Code

```
  

```

Hints from issue discussion:
Hi @ryanmccoy, thanks, it looks like the symbol is `None` (the filter could be empty dict). I'll run it and see what the message is.

Which limit did you use?

Commit message: fix(bitmex): guard handleOrderBook

Patch to review:
diff --git a/ts/src/pro/bitmex.ts b/ts/src/pro/bitmex.ts
index 85f9079848f20..55f9d24daa6ad 100644
--- a/ts/src/pro/bitmex.ts
+++ b/ts/src/pro/bitmex.ts
@@ -1573,6 +1573,9 @@ export default class bitmex extends bitmexRest {
             } else if (table === 'orderBook10') {
                 this.orderbooks[symbol] = this.indexedOrderBook ({}, 10);
             }
+            if (table === undefined || symbol === undefined) {
+                return;
+            }
             const orderbook = this.orderbooks[symbol];
             orderbook['symbol'] = symbol;
             for (let i = 0; i < data.length; i++) {


Code review comments:
diff_hunk: @@ -1573,6 +1573,9 @@ export default class bitmex extends bitmexRest {
             } else if (table === 'orderBook10') {
                 this.orderbooks[symbol] = this.indexedOrderBook ({}, 10);
             }
+            if (table === undefined || symbol === undefined) {
path: ts/src/pro/bitmex.ts
text: @user1:
we have to do this earlier because we might be trying to access `this.orderbook` with `symbol = None` which breaks the python version.