diff --git a/lyra/async_client.py b/lyra/async_client.py index 5eec308..bf62cc5 100644 --- a/lyra/async_client.py +++ b/lyra/async_client.py @@ -26,6 +26,7 @@ class AsyncClient(BaseClient): listener = None subscribing = False + _ws = None def __init__( self, @@ -53,6 +54,15 @@ def __init__( print(f"Using subaccount id: {self.subaccount_id}") self.message_queues = {} self.connecting = False + # we make sure to get the event loop + + @property + async def ws(self): + if self._ws is None: + self._ws = await self.connect_ws() + if not self._ws.connected: + self._ws = await self.connect_ws() + return self._ws async def fetch_ticker(self, instrument_name: str): """ @@ -60,6 +70,9 @@ async def fetch_ticker(self, instrument_name: str): """ id = str(int(time.time())) payload = {"instrument_name": instrument_name} + if not self.ws: + await self.connect_ws() + self.ws.send(json.dumps({"method": "public/get_ticker", "params": payload, "id": id})) # we now wait for the response @@ -95,7 +108,7 @@ async def connect_ws(self): self.connecting = True session = aiohttp.ClientSession() ws = await session.ws_connect(self.contracts['WS_ADDRESS']) - self.ws = ws + self._ws = ws self.connecting = False return ws @@ -132,8 +145,8 @@ async def login_client( 'params': self.sign_authentication_header(), 'id': str(int(time.time())), } - await self.ws.send_json(login_request) - async for data in self.ws: + await self._ws.send_json(login_request) + async for data in self._ws: message = json.loads(data.data) if message['id'] == login_request['id']: if "result" not in message: @@ -210,6 +223,8 @@ async def fetch_tickers( instrument_type: InstrumentType = InstrumentType.OPTION, currency: UnderlyingCurrency = UnderlyingCurrency.BTC, ): + if not self._ws: + await self.connect_ws() instruments = await self.fetch_instruments(instrument_type=instrument_type, currency=currency) instrument_names = [i['instrument_name'] for i in instruments] id_base = str(int(time.time())) @@ -218,17 +233,31 @@ async def fetch_tickers( } for id, instrument_name in ids_to_instrument_names.items(): payload = {"instrument_name": instrument_name} - self.ws.send(json.dumps({'method': 'public/get_ticker', 'params': payload, 'id': id})) - await asyncio.sleep(0.05) # otherwise we get rate limited... + await self._ws.send_json({'method': 'public/get_ticker', 'params': payload, 'id': id}) + await asyncio.sleep(0.1) # otherwise we get rate limited... results = {} while ids_to_instrument_names: - message = json.loads(self.ws.recv()) + message = await self._ws.receive() + if message is None: + continue + if 'error' in message: + raise Exception(f"Error fetching ticker {message}") + if message.type == aiohttp.WSMsgType.CLOSED: + # we try to reconnect + print(f"Erorr fetching ticker {message}...") + self._ws = await self.connect_ws() + return await self.fetch_tickers(instrument_type, currency) + message = json.loads(message.data) if message['id'] in ids_to_instrument_names: - results[message['result']['instrument_name']] = message['result'] + try: + results[message['result']['instrument_name']] = message['result'] + except KeyError: + print(f"Error fetching ticker {message}") del ids_to_instrument_names[message['id']] return results async def get_collaterals(self): + breakpoint() return super().get_collaterals() async def get_positions(self, currency: UnderlyingCurrency = UnderlyingCurrency.BTC): diff --git a/poetry.lock b/poetry.lock index 00175d0..f259c57 100644 --- a/poetry.lock +++ b/poetry.lock @@ -175,18 +175,6 @@ files = [ [package.extras] tests = ["PyHamcrest (>=2.0.2)", "mypy", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-flake8"] -[[package]] -name = "bidict" -version = "0.23.1" -description = "The bidirectional mapping library for Python." -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5"}, - {file = "bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71"}, -] - [[package]] name = "bitarray" version = "2.9.2" @@ -988,18 +976,6 @@ files = [ astunparse = {version = ">=1.6", markers = "python_version < \"3.9\""} colorama = ">=0.4" -[[package]] -name = "h11" -version = "0.14.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] - [[package]] name = "hexbytes" version = "0.3.1" @@ -2102,48 +2078,6 @@ files = [ [package.extras] cli = ["click (>=5.0)"] -[[package]] -name = "python-engineio" -version = "4.9.0" -description = "Engine.IO server and client for Python" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "python-engineio-4.9.0.tar.gz", hash = "sha256:e87459c15638e567711fd156e6f9c4a402668871bed79523f0ecfec744729ec7"}, - {file = "python_engineio-4.9.0-py3-none-any.whl", hash = "sha256:979859bff770725b75e60353d7ae53b397e8b517d05ba76733b404a3dcca3e4c"}, -] - -[package.dependencies] -simple-websocket = ">=0.10.0" - -[package.extras] -asyncio-client = ["aiohttp (>=3.4)"] -client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] -docs = ["sphinx"] - -[[package]] -name = "python-socketio" -version = "5.11.2" -description = "Socket.IO server and client for Python" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "python-socketio-5.11.2.tar.gz", hash = "sha256:ae6a1de5c5209ca859dc574dccc8931c4be17ee003e74ce3b8d1306162bb4a37"}, - {file = "python_socketio-5.11.2-py3-none-any.whl", hash = "sha256:b9f22a8ff762d7a6e123d16a43ddb1a27d50f07c3c88ea999334f2f89b0ad52b"}, -] - -[package.dependencies] -aiohttp = {version = ">=3.4", optional = true, markers = "extra == \"asyncio-client\""} -bidict = ">=0.21.0" -python-engineio = ">=4.8.0" - -[package.extras] -asyncio-client = ["aiohttp (>=3.4)"] -client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] -docs = ["sphinx"] - [[package]] name = "pytz" version = "2023.3.post1" @@ -2509,24 +2443,6 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "simple-websocket" -version = "1.0.0" -description = "Simple WebSocket server and client for Python" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "simple-websocket-1.0.0.tar.gz", hash = "sha256:17d2c72f4a2bd85174a97e3e4c88b01c40c3f81b7b648b0cc3ce1305968928c8"}, - {file = "simple_websocket-1.0.0-py3-none-any.whl", hash = "sha256:1d5bf585e415eaa2083e2bcf02a3ecf91f9712e7b3e6b9fa0b461ad04e0837bc"}, -] - -[package.dependencies] -wsproto = "*" - -[package.extras] -docs = ["sphinx"] - [[package]] name = "six" version = "1.16.0" @@ -2810,21 +2726,6 @@ files = [ [package.extras] test = ["pytest (>=6.0.0)", "setuptools (>=65)"] -[[package]] -name = "wsproto" -version = "1.2.0" -description = "WebSockets state-machine based protocol implementation" -category = "main" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, - {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, -] - -[package.dependencies] -h11 = ">=0.9.0,<1" - [[package]] name = "yarl" version = "1.9.4" @@ -2948,4 +2849,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<=3.11.7" -content-hash = "c09c0c7df42a036821612a3c531666acaa7f27c434652b9e1a0aa3670f9cd732" +content-hash = "1d1005192174b5443ef3c0841eead025a9a171f629eb92ba6f29848f616b20d7" diff --git a/pyproject.toml b/pyproject.toml index 1d8f40b..4b812bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,16 +7,14 @@ readme = "README.md" packages = [{include = "lyra"}] [tool.poetry.dependencies] -python = ">=3.8.1,<=3.11.7" -requests = "^2.31.0" -web3 = "^5" +python = ">=3.8.1,<=3.11.9" +requests = "^2" +web3 = "^6" websocket-client = ">=0.32.0,<1" setuptools = "^68.2.2" rich-click = "^1.7.1" python-dotenv = ">=0.14.0,<0.18.0" pandas = "~1" -websockets = "9.1" -python-socketio = {extras = ["asyncio-client"], version = "^5.11.2"} [tool.poetry.scripts]