Skip to content

Commit

Permalink
feat(websockets): add orjson support (#1479)
Browse files Browse the repository at this point in the history
* feat(websockets): add orjson support

* formatting

* update readme

* remove unused dependency
  • Loading branch information
carlosmiei authored Nov 22, 2024
1 parent c6dc758 commit 2eeeeae
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 6 deletions.
9 changes: 8 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Features
- Porfolio Margin Trading
- Vanilla Options
- Proxy support
- Orjson support for faster JSON parsing
- Support other domains (.us, .jp, etc)

Upgrading to v1.0.0+
Expand Down Expand Up @@ -274,14 +275,20 @@ for more information.
await client.close_connection()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
The library is under `MIT license`, that means it's absolutely free for any developer to build commercial and opensource software on top of it, but use it at your own risk with no warranties, as is.


Orjson support
-------------------

Python-binance also supports `orjson` for parsing JSON since it is much faster than the builtin library. This is especially important when using websockets because some exchanges return big messages that need to be parsed and dispatched as quickly as possible.

However, `orjson` is not enabled by default because it is not supported by every python interpreter. If you want to opt-in, you just need to install it (`pip install orjson`) on your local environment. Python-binance will detect the installion and pick it up automatically.

Star history
------------

Expand Down
19 changes: 18 additions & 1 deletion binance/ws/reconnecting_websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
from asyncio import sleep
from random import random

# load orjson if available, otherwise default to json
orjson = None
try:
import orjson as orjson
except ImportError:
pass

try:
from websockets.exceptions import ConnectionClosedError # type: ignore
except ImportError:
Expand Down Expand Up @@ -52,6 +59,16 @@ def __init__(
self._handle_read_loop = None
self._ws_kwargs = kwargs

def json_dumps(self, msg):
if orjson:
return orjson.dumps(msg)
return json.dumps(msg)

def json_loads(self, msg):
if orjson:
return orjson.loads(msg)
return json.loads(msg)

async def __aenter__(self):
await self.connect()
return self
Expand Down Expand Up @@ -114,7 +131,7 @@ def _handle_message(self, evt):
except (ValueError, OSError):
return None
try:
return json.loads(evt)
return self.json_loads(evt)
except ValueError:
self._log.debug(f"error parsing evt json:{evt}")
return None
Expand Down
5 changes: 2 additions & 3 deletions binance/ws/websocket_api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from typing import Dict
import asyncio
import json

from websockets import WebSocketClientProtocol # type: ignore

Expand Down Expand Up @@ -31,7 +30,7 @@ def _handle_message(self, msg):
if parsed_msg["status"] != 200:
throwError = True
exception = BinanceAPIException(
parsed_msg, parsed_msg["status"], json.dumps(parsed_msg["error"])
parsed_msg, parsed_msg["status"], self.json_dumps(parsed_msg["error"])
)
if req_id is not None and req_id in self._responses:
if throwError and exception is not None:
Expand Down Expand Up @@ -102,7 +101,7 @@ async def request(self, id: str, payload: dict) -> dict:
raise BinanceWebsocketUnableToConnect(
"Trying to send request while WebSocket is not connected"
)
await self.ws.send(json.dumps(payload))
await self.ws.send(self.json_dumps(payload))

# Wait for response
response = await asyncio.wait_for(future, timeout=self.TIMEOUT)
Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ aiohttp
dateparser
pycryptodome
requests
ujson
websockets

0 comments on commit 2eeeeae

Please sign in to comment.