Skip to content

Commit

Permalink
2.1.12 Fix #49
Browse files Browse the repository at this point in the history
  • Loading branch information
DogsTailFarmer committed Apr 30, 2024
1 parent f73b3c0 commit 38017da
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 55 deletions.
15 changes: 15 additions & 0 deletions .run/exchanges-wrapper-image.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="exchanges-wrapper-image" type="docker-deploy" factoryName="dockerfile" editBeforeRun="true" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="exchanges-wrapper:last" />
<option name="buildCliOptions" value="--no-cache --network=host" />
<option name="buildOnly" value="true" />
<option name="containerName" value="" />
<option name="showCommandPreview" value="true" />
<option name="sourceFilePath" value="Dockerfile" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>
32 changes: 32 additions & 0 deletions .run/exchanges-wrapper.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="exchanges-wrapper" type="docker-deploy" factoryName="docker-image" editBeforeRun="true" server-name="Docker">
<deployment type="docker-image">
<settings>
<option name="imageTag" value="ghcr.io/dogstailfarmer/exchanges-wrapper:latest" />
<option name="containerName" value="exchanges-wrapper" />
<option name="commandLineOptions" value="-i -t -P" />
<option name="showCommandPreview" value="true" />
<option name="volumeBindings">
<list>
<DockerVolumeBindingImpl>
<option name="containerPath" value="$PROJECT_DIR$/../../../appuser/.MartinBinance" />
<option name="hostPath" value="$USER_HOME$/.MartinBinance" />
</DockerVolumeBindingImpl>
</list>
</option>
</settings>
</deployment>
<method v="2" />
</configuration>
<configuration default="false" name="exchanges-wrapper" type="docker-deploy" factoryName="docker-image" editBeforeRun="true" server-name="Docker">
<deployment type="docker-image">
<settings>
<option name="imageTag" value="exchanges-wrapper:last" />
<option name="containerName" value="exchanges-wrapper" />
<option name="commandLineOptions" value="-i -t -P --mount type=bind,source=$USER_HOME$/.MartinBinance,target=$PROJECT_DIR$/../../../appuser/.MartinBinance --network=host" />
<option name="showCommandPreview" value="true" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
## 2.1.11.post1 2024-04-xx
## 2.1.12 2024-04-30
### Fix
* `Docker`: [#49 ImportError: cannot import name 'version' from 'exchanges_wrapper'](https://github.com/DogsTailFarmer/exchanges-wrapper/issues/49#issue-2272432093)

### Update
* `send_request`: controlling rate_limit by changing exception handling
* `Bitfinex`: sync `nonce` for connections group
* Dependency: Up requirements for crypto-ws-api==2.0.11

## 2.1.11 2024-04-19
### Update
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ COPY requirements.txt requirements.txt

RUN pip3 install -r requirements.txt

COPY ./exchanges_wrapper/* /home/appuser/.local/lib/python3.10/site-packages/exchanges_wrapper/
COPY ./exchanges_wrapper /home/appuser/.local/lib/python3.10/site-packages/exchanges_wrapper/

WORKDIR "/home/appuser/.local/lib/python3.10/site-packages"

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ pip install -U exchanges-wrapper

#### Start server
* Run in terminal window
```
exchanges-wrapper-init
```
and

```
exchanges-wrapper-srv
```
Expand Down
2 changes: 1 addition & 1 deletion exchanges_wrapper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
__contact__ = "https://github.com/DogsTailFarmer"
__email__ = "[email protected]"
__credits__ = ["https://github.com/DanyaSWorlD"]
__version__ = "2.1.11.post1"
__version__ = "2.1.12"

from pathlib import Path
import shutil
Expand Down
20 changes: 4 additions & 16 deletions exchanges_wrapper/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ def __init__(self, *acc):
self.ledgers_id = []
self.ts_start = {}
self.tasks = set()
self.request_event = asyncio.Event()
self.request_event.set()

def tasks_manage(self, coro):
_t = asyncio.create_task(coro)
Expand Down Expand Up @@ -377,24 +379,10 @@ async def fetch_exchange_info(self, symbol):
# MARKET DATA ENDPOINTS

# https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#order-book
async def fetch_order_book(self, symbol, precision='P0', limit=100):
async def fetch_order_book(self, symbol, precision='P0'):
self.assert_symbol(symbol)
valid_limits = []
if self.exchange == 'binance':
valid_limits = [5, 10, 20, 50, 100, 500, 1000, 5000]
elif self.exchange == 'bitfinex':
valid_limits = [1, 25, 100]
elif self.exchange == 'huobi':
valid_limits = [5, 10, 20]
elif self.exchange == 'okx':
valid_limits = [1, 5, 10, 20, 50, 100, 400]
elif self.exchange == 'bybit':
valid_limits = range(1, 51)
limit = 1 if self.exchange in ('bitfinex', 'okx', 'bybit') else 5
binance_res = {}
if limit not in valid_limits:
raise ValueError(
f"{limit} is not a valid limit. Valid limits: {valid_limits}"
)
if self.exchange == 'binance':
binance_res = await self.http.send_api_call(
"/api/v3/depth",
Expand Down
75 changes: 41 additions & 34 deletions exchanges_wrapper/exch_srv.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import grpclib.exceptions

from exchanges_wrapper import __version__ as ver_ew
from crypto_ws_api import __version__ as ver_cw
from exchanges_wrapper import __version__ as VER_EW
from crypto_ws_api import __version__ as VER_CW
import time
import weakref
import gc
Expand Down Expand Up @@ -148,10 +149,10 @@ class Martin(mr.MartinBase):
rate_limit_reached_time = None
rate_limiter = None

async def rate_limit_control(self, client, _call_from='default'):
if client.client.exchange == 'bitfinex':
rate_limit_interval = REST_RATE_LIMIT_INTERVAL.get(client.client.exchange, {}).get(_call_from, 0)
ts_diff = time.time() - client.ts_rlc
async def rate_limit_control(self, exchange, ts_rlc, _call_from='default'):
if exchange == 'bitfinex':
rate_limit_interval = REST_RATE_LIMIT_INTERVAL.get(exchange, {}).get(_call_from, 0)
ts_diff = time.time() - ts_rlc
if ts_diff < rate_limit_interval:
sleep_duration = rate_limit_interval - ts_diff
await asyncio.sleep(sleep_duration)
Expand Down Expand Up @@ -201,7 +202,7 @@ async def open_client_connection(self, request: mr.OpenClientConnectionRequest)
Martin.rate_limiter = max(Martin.rate_limiter or 0, request.rate_limiter)
return mr.OpenClientConnectionId(
client_id=client_id,
srv_version=f"{ver_cw}:{ver_ew}",
srv_version=f"{VER_CW}:{VER_EW}",
exchange=open_client.client.exchange,
real_market=open_client.real_market
)
Expand Down Expand Up @@ -231,7 +232,10 @@ async def send_request(self, client_method_name, request, rate_limit=False, **kw
if hasattr(request, 'client_order_id'):
msg_header += f"({request.client_order_id}):"
if rate_limit:
await self.rate_limit_control(open_client)
await self.rate_limit_control(client.exchange, open_client.ts_rlc)
if client.exchange == 'bitfinex':
await client.request_event.wait()
client.request_event.clear()
try:
res = await asyncio.wait_for(getattr(client, client_method_name)(**kwargs), timeout=HEARTBEAT * 60)
except asyncio.exceptions.CancelledError:
Expand Down Expand Up @@ -263,6 +267,8 @@ async def send_request(self, client_method_name, request, rate_limit=False, **kw
if rate_limit:
open_client.ts_rlc = time.time()
return res, client, msg_header
finally:
client.request_event.set()

async def fetch_server_time(self, request: mr.OpenClientConnectionId) -> mr.FetchServerTimeResponse:
res, _, _ = await self.send_request('fetch_server_time', request, rate_limit=True)
Expand Down Expand Up @@ -432,36 +438,39 @@ async def fetch_funding_wallet(self, request: mr.FetchFundingWalletRequest) -> m
return response

async def fetch_order_book(self, request: mr.MarketRequest) -> mr.FetchOrderBookResponse:
open_client = OpenClient.get_client(request.client_id)
client = open_client.client
response = mr.FetchOrderBookResponse()
await self.rate_limit_control(open_client)
limit = 1 if client.exchange in ('bitfinex', 'okx') else 5
res = await client.fetch_order_book(symbol=request.symbol, limit=limit)
open_client.ts_rlc = time.time()
res, _, _ = await self.send_request(
'fetch_order_book',
request,
rate_limit=True,
symbol=request.symbol
)

res['bids'] = [json.dumps(v) for v in res.get('bids', [])]
res['asks'] = [json.dumps(v) for v in res.get('asks', [])]
return response.from_pydict(res)

async def fetch_symbol_price_ticker(self, request: mr.MarketRequest) -> mr.FetchSymbolPriceTickerResponse:
open_client = OpenClient.get_client(request.client_id)
client = open_client.client
response = mr.FetchSymbolPriceTickerResponse()
await self.rate_limit_control(open_client)
res = await client.fetch_symbol_price_ticker(symbol=request.symbol)
open_client.ts_rlc = time.time()
res, _, _ = await self.send_request(
'fetch_symbol_price_ticker',
request,
rate_limit=True,
symbol=request.symbol
)
return response.from_pydict(res)

async def fetch_ticker_price_change_statistics(
self,
request: mr.MarketRequest
) -> mr.FetchTickerPriceChangeStatisticsResponse:
open_client = OpenClient.get_client(request.client_id)
client = open_client.client
response = mr.FetchTickerPriceChangeStatisticsResponse()
await self.rate_limit_control(open_client)
res = await client.fetch_ticker_price_change_statistics(symbol=request.symbol)
open_client.ts_rlc = time.time()
res, _, _ = await self.send_request(
'fetch_ticker_price_change_statistics',
request,
rate_limit=True,
symbol=request.symbol
)
return response.from_pydict(res)

async def fetch_klines(self, request: mr.FetchKlinesRequest) -> mr.JsonResponse:
Expand Down Expand Up @@ -667,15 +676,13 @@ async def on_balance_update(self, request: mr.MarketRequest) -> mr.StreamRespons
_get_event_from_queue = False

if client.exchange in ('bitfinex', 'huobi', 'bybit'):
await self.rate_limit_control(open_client)
try:
balances = await client.fetch_ledgers(request.symbol)
except Exception as _ex:
logger.warning(f"OnBalanceUpdate: for {open_client.name}:{request.symbol}: {_ex}")
logger.debug(f"OnBalanceUpdate: {traceback.format_exc()}")
else:
open_client.ts_rlc = time.time()
[_events.append(client.events.wrap_event(balance)) for balance in balances]
balances, _, _ = await self.send_request(
'fetch_ledgers',
request,
rate_limit=True,
symbol=request.symbol
)
[_events.append(client.events.wrap_event(balance)) for balance in balances]

for _event in _events:
if _event.asset in request.symbol:
Expand Down Expand Up @@ -851,7 +858,7 @@ async def amain(host: str = '127.0.0.1', port: int = 50051):
server = Server([Martin()])
with graceful_exit([server]):
await server.start(host, port)
logger.info(f"Starting server v:{ver_cw}:{ver_ew} on {host}:{port}")
logger.info(f"Starting server v:{VER_CW}:{VER_EW} on {host}:{port}")
await server.wait_closed()

for oc in OpenClient.open_clients:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dynamic = ["version", "description"]
requires-python = ">=3.9"

dependencies = [
"crypto-ws-api==2.0.10",
"crypto-ws-api==2.0.11",
"grpcio==1.62.0",
"pyotp~=2.9.0",
"simplejson==3.19.2",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
crypto-ws-api==2.0.10
crypto-ws-api==2.0.11
pyotp==2.9.0
simplejson==3.19.2
toml~=0.10.2
Expand Down

0 comments on commit 38017da

Please sign in to comment.