exchanges-wrapper 2.1.13__tar.gz → 2.1.15__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/PKG-INFO +1 -2
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/__init__.py +1 -1
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/client.py +46 -36
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/exch_srv.py +18 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/martin/__init__.py +36 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/bybit_parser.py +0 -3
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/proto/martin.proto +2 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/pyproject.toml +0 -1
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/LICENSE.md +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/README.md +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/definitions.py +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/errors.py +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/events.py +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/exch_srv_cfg.toml.template +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/http_client.py +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/lib.py +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/bitfinex_parser.py +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/huobi_parser.py +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/okx_parser.py +0 -0
- {exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/web_sockets.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: exchanges-wrapper
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.15
|
|
4
4
|
Summary: REST API and WebSocket asyncio wrapper with grpc powered multiplexer server
|
|
5
5
|
Author-email: Thomas Marchand <thomas.marchand@tuta.io>, Jerry Fedorenko <jerry.fedorenko@yahoo.com>
|
|
6
6
|
Requires-Python: >=3.9
|
|
@@ -16,7 +16,6 @@ Requires-Dist: grpcio==1.62.0
|
|
|
16
16
|
Requires-Dist: pyotp~=2.9.0
|
|
17
17
|
Requires-Dist: simplejson==3.19.2
|
|
18
18
|
Requires-Dist: aiohttp==3.9.5
|
|
19
|
-
Requires-Dist: Pympler~=1.0.1
|
|
20
19
|
Requires-Dist: websockets~=12.0
|
|
21
20
|
Requires-Dist: expiringdict~=1.2.2
|
|
22
21
|
Requires-Dist: ujson~=5.10.0
|
|
@@ -12,7 +12,7 @@ __maintainer__ = "Jerry Fedorenko"
|
|
|
12
12
|
__contact__ = "https://github.com/DogsTailFarmer"
|
|
13
13
|
__email__ = "jerry.fedorenko@yahoo.com"
|
|
14
14
|
__credits__ = ["https://github.com/DanyaSWorlD"]
|
|
15
|
-
__version__ = "2.1.
|
|
15
|
+
__version__ = "2.1.15"
|
|
16
16
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
import shutil
|
|
@@ -493,24 +493,24 @@ class Client:
|
|
|
493
493
|
uid=self.account_uid
|
|
494
494
|
)
|
|
495
495
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
496
|
+
if not _res:
|
|
497
|
+
# Get Transaction Log
|
|
498
|
+
params.pop('status')
|
|
499
|
+
params['accountType'] = 'UNIFIED'
|
|
500
|
+
params['category'] = 'spot'
|
|
501
|
+
params['type'] = 'TRANSFER_IN'
|
|
502
|
+
|
|
503
|
+
res, ts = await self.http.send_api_call(
|
|
504
|
+
"/v5/account/transaction-log",
|
|
505
|
+
signed=True,
|
|
506
|
+
**params
|
|
507
|
+
)
|
|
508
|
+
_res += bbt.on_balance_update(
|
|
509
|
+
res['list'],
|
|
510
|
+
ts,
|
|
511
|
+
symbol,
|
|
512
|
+
'log'
|
|
513
|
+
)
|
|
514
514
|
|
|
515
515
|
for i in _res:
|
|
516
516
|
_id = next(iter(i))
|
|
@@ -703,7 +703,8 @@ class Client:
|
|
|
703
703
|
# https://github.com/binance/binance-spot-api-docs/blob/master/rest-api.md#symbol-price-ticker
|
|
704
704
|
async def fetch_symbol_price_ticker(self, symbol=None):
|
|
705
705
|
if symbol:
|
|
706
|
-
self.
|
|
706
|
+
if not (self.exchange == 'binance' and symbol == 'BNBUSDT'):
|
|
707
|
+
self.assert_symbol_exists(symbol)
|
|
707
708
|
binance_res = {}
|
|
708
709
|
elif self.exchange in ('bitfinex', 'huobi'):
|
|
709
710
|
raise ValueError('For fetch_symbol_price_ticker() symbol parameter required')
|
|
@@ -1603,25 +1604,34 @@ class Client:
|
|
|
1603
1604
|
binance_res = bbt.funding_wallet(res["balance"])
|
|
1604
1605
|
return binance_res
|
|
1605
1606
|
|
|
1607
|
+
# https://developers.binance.com/docs/sub_account/asset-management/Transfer-to-Sub-account-of-Same-Master
|
|
1608
|
+
async def transfer_to_sub(self, email, symbol, quantity, receive_window=None):
|
|
1609
|
+
if self.exchange == 'binance':
|
|
1610
|
+
quantity = any2str(Decimal(quantity).quantize(Decimal('0.01234567'), rounding=ROUND_HALF_DOWN))
|
|
1611
|
+
params = {"toEmail": email, "asset": symbol, "amount": quantity}
|
|
1612
|
+
if receive_window:
|
|
1613
|
+
params["recvWindow"] = receive_window
|
|
1614
|
+
return await self.http.send_api_call(
|
|
1615
|
+
"/sapi/v1/sub-account/transfer/subToSub",
|
|
1616
|
+
"POST",
|
|
1617
|
+
signed=True,
|
|
1618
|
+
params=params
|
|
1619
|
+
)
|
|
1620
|
+
else:
|
|
1621
|
+
raise ValueError(f"Can't implemented for {self.exchange}")
|
|
1622
|
+
|
|
1606
1623
|
# https://binance-docs.github.io/apidocs/spot/en/#transfer-to-master-for-sub-account
|
|
1607
1624
|
async def transfer_to_master(self, symbol, quantity, receive_window=None):
|
|
1608
|
-
|
|
1609
|
-
|
|
1625
|
+
_quantity = any2str(Decimal(quantity).quantize(Decimal('0.01234567'), rounding=ROUND_HALF_DOWN))
|
|
1610
1626
|
binance_res = {}
|
|
1611
1627
|
if self.exchange == 'binance':
|
|
1612
|
-
params = {"asset": symbol, "amount": quantity}
|
|
1613
|
-
if receive_window:
|
|
1614
|
-
params["recvWindow"] = receive_window
|
|
1615
1628
|
if self.master_email:
|
|
1616
|
-
logger.info(f"Collect {
|
|
1617
|
-
|
|
1618
|
-
binance_res = await self.http.send_api_call(
|
|
1619
|
-
"/sapi/v1/sub-account/transfer/subToSub",
|
|
1620
|
-
"POST",
|
|
1621
|
-
signed=True,
|
|
1622
|
-
params=params
|
|
1623
|
-
)
|
|
1629
|
+
logger.info(f"Collect {_quantity}{symbol} to {self.master_email} sub-account")
|
|
1630
|
+
binance_res = await self.transfer_to_sub(self.master_email, symbol, quantity, receive_window)
|
|
1624
1631
|
else:
|
|
1632
|
+
params = {"asset": symbol, "amount": _quantity}
|
|
1633
|
+
if receive_window:
|
|
1634
|
+
params["recvWindow"] = receive_window
|
|
1625
1635
|
binance_res = await self.http.send_api_call(
|
|
1626
1636
|
"/sapi/v1/sub-account/transfer/subToMaster",
|
|
1627
1637
|
"POST",
|
|
@@ -1636,7 +1646,7 @@ class Client:
|
|
|
1636
1646
|
"from": "exchange",
|
|
1637
1647
|
"to": "exchange",
|
|
1638
1648
|
"currency": symbol,
|
|
1639
|
-
"amount":
|
|
1649
|
+
"amount": _quantity,
|
|
1640
1650
|
"email_dst": self.master_email,
|
|
1641
1651
|
"tfaToken": {"method": "otp", "token": totp.now()}
|
|
1642
1652
|
}
|
|
@@ -1658,7 +1668,7 @@ class Client:
|
|
|
1658
1668
|
'to-account-type': "spot",
|
|
1659
1669
|
'to-account': self.main_account_id,
|
|
1660
1670
|
'currency': symbol.lower(),
|
|
1661
|
-
'amount':
|
|
1671
|
+
'amount': _quantity
|
|
1662
1672
|
}
|
|
1663
1673
|
res = await self.http.send_api_call(
|
|
1664
1674
|
"v1/account/transfer",
|
|
@@ -1670,7 +1680,7 @@ class Client:
|
|
|
1670
1680
|
elif self.exchange == 'okx':
|
|
1671
1681
|
params = {
|
|
1672
1682
|
"ccy": symbol,
|
|
1673
|
-
"amt":
|
|
1683
|
+
"amt": _quantity,
|
|
1674
1684
|
"from": '18',
|
|
1675
1685
|
"to": '18',
|
|
1676
1686
|
"type": '3'
|
|
@@ -1692,7 +1702,7 @@ class Client:
|
|
|
1692
1702
|
params = {
|
|
1693
1703
|
'transferId': str(uuid.uuid4()),
|
|
1694
1704
|
'coin': symbol,
|
|
1695
|
-
'amount': str(math.floor(float(
|
|
1705
|
+
'amount': str(math.floor(float(_quantity) * 10 ** n) / 10 ** n),
|
|
1696
1706
|
'fromMemberId': self.account_uid,
|
|
1697
1707
|
'toMemberId': self.main_account_uid,
|
|
1698
1708
|
'fromAccountType': 'UNIFIED',
|
|
@@ -767,6 +767,24 @@ class Martin(mr.MartinBase):
|
|
|
767
767
|
response.from_pydict(res)
|
|
768
768
|
return response
|
|
769
769
|
|
|
770
|
+
async def transfer_to_sub(self, request: mr.MarketRequest) -> mr.SimpleResponse:
|
|
771
|
+
response = mr.SimpleResponse()
|
|
772
|
+
response.success = False
|
|
773
|
+
|
|
774
|
+
res, _, _ = await self.send_request(
|
|
775
|
+
'transfer_to_sub',
|
|
776
|
+
request,
|
|
777
|
+
rate_limit=True,
|
|
778
|
+
email=request.data,
|
|
779
|
+
symbol=request.symbol,
|
|
780
|
+
quantity=request.amount
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
if res and res.get("txnId"):
|
|
784
|
+
response.success = True
|
|
785
|
+
response.result = json.dumps(res)
|
|
786
|
+
return response
|
|
787
|
+
|
|
770
788
|
async def transfer_to_master(self, request: mr.MarketRequest) -> mr.SimpleResponse:
|
|
771
789
|
response = mr.SimpleResponse()
|
|
772
790
|
response.success = False
|
|
@@ -407,6 +407,7 @@ class MarketRequest(betterproto.Message):
|
|
|
407
407
|
trade_id: str = betterproto.string_field(2)
|
|
408
408
|
symbol: str = betterproto.string_field(3)
|
|
409
409
|
amount: str = betterproto.string_field(4)
|
|
410
|
+
data: str = betterproto.string_field(5)
|
|
410
411
|
|
|
411
412
|
|
|
412
413
|
@dataclass(eq=False, repr=False)
|
|
@@ -916,6 +917,23 @@ class MartinStub(betterproto.ServiceStub):
|
|
|
916
917
|
metadata=metadata,
|
|
917
918
|
)
|
|
918
919
|
|
|
920
|
+
async def transfer_to_sub(
|
|
921
|
+
self,
|
|
922
|
+
market_request: "MarketRequest",
|
|
923
|
+
*,
|
|
924
|
+
timeout: Optional[float] = None,
|
|
925
|
+
deadline: Optional["Deadline"] = None,
|
|
926
|
+
metadata: Optional["MetadataLike"] = None
|
|
927
|
+
) -> "SimpleResponse":
|
|
928
|
+
return await self._unary_unary(
|
|
929
|
+
"/martin.Martin/TransferToSub",
|
|
930
|
+
market_request,
|
|
931
|
+
SimpleResponse,
|
|
932
|
+
timeout=timeout,
|
|
933
|
+
deadline=deadline,
|
|
934
|
+
metadata=metadata,
|
|
935
|
+
)
|
|
936
|
+
|
|
919
937
|
|
|
920
938
|
class MartinBase(ServiceBase):
|
|
921
939
|
|
|
@@ -1056,6 +1074,11 @@ class MartinBase(ServiceBase):
|
|
|
1056
1074
|
) -> "SimpleResponse":
|
|
1057
1075
|
raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
|
|
1058
1076
|
|
|
1077
|
+
async def transfer_to_sub(
|
|
1078
|
+
self, market_request: "MarketRequest"
|
|
1079
|
+
) -> "SimpleResponse":
|
|
1080
|
+
raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
|
|
1081
|
+
|
|
1059
1082
|
async def __rpc_cancel_all_orders(
|
|
1060
1083
|
self, stream: "grpclib.server.Stream[MarketRequest, SimpleResponse]"
|
|
1061
1084
|
) -> None:
|
|
@@ -1270,6 +1293,13 @@ class MartinBase(ServiceBase):
|
|
|
1270
1293
|
response = await self.transfer_to_master(request)
|
|
1271
1294
|
await stream.send_message(response)
|
|
1272
1295
|
|
|
1296
|
+
async def __rpc_transfer_to_sub(
|
|
1297
|
+
self, stream: "grpclib.server.Stream[MarketRequest, SimpleResponse]"
|
|
1298
|
+
) -> None:
|
|
1299
|
+
request = await stream.recv_message()
|
|
1300
|
+
response = await self.transfer_to_sub(request)
|
|
1301
|
+
await stream.send_message(response)
|
|
1302
|
+
|
|
1273
1303
|
def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
|
|
1274
1304
|
return {
|
|
1275
1305
|
"/martin.Martin/CancelAllOrders": grpclib.const.Handler(
|
|
@@ -1434,4 +1464,10 @@ class MartinBase(ServiceBase):
|
|
|
1434
1464
|
MarketRequest,
|
|
1435
1465
|
SimpleResponse,
|
|
1436
1466
|
),
|
|
1467
|
+
"/martin.Martin/TransferToSub": grpclib.const.Handler(
|
|
1468
|
+
self.__rpc_transfer_to_sub,
|
|
1469
|
+
grpclib.const.Cardinality.UNARY_UNARY,
|
|
1470
|
+
MarketRequest,
|
|
1471
|
+
SimpleResponse,
|
|
1472
|
+
),
|
|
1437
1473
|
}
|
{exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/bybit_parser.py
RENAMED
|
@@ -452,7 +452,6 @@ def on_balance_update(data_in: list, ts: str, symbol: str, mode: str, uid=None)
|
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
)
|
|
455
|
-
|
|
456
455
|
elif mode == 'universal':
|
|
457
456
|
for i in data_in:
|
|
458
457
|
if i['coin'] in symbol and \
|
|
@@ -469,7 +468,6 @@ def on_balance_update(data_in: list, ts: str, symbol: str, mode: str, uid=None)
|
|
|
469
468
|
}
|
|
470
469
|
}
|
|
471
470
|
)
|
|
472
|
-
|
|
473
471
|
elif mode == 'log':
|
|
474
472
|
for i in data_in:
|
|
475
473
|
if i['currency'] in symbol:
|
|
@@ -484,7 +482,6 @@ def on_balance_update(data_in: list, ts: str, symbol: str, mode: str, uid=None)
|
|
|
484
482
|
}
|
|
485
483
|
}
|
|
486
484
|
)
|
|
487
|
-
|
|
488
485
|
return data_out
|
|
489
486
|
|
|
490
487
|
|
|
@@ -38,6 +38,7 @@ service Martin {
|
|
|
38
38
|
rpc StartStream (StartStreamRequest) returns (SimpleResponse) {}
|
|
39
39
|
rpc StopStream (MarketRequest) returns (SimpleResponse) {}
|
|
40
40
|
rpc TransferToMaster(MarketRequest) returns (SimpleResponse) {}
|
|
41
|
+
rpc TransferToSub(MarketRequest) returns (SimpleResponse) {}
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
message JSONResponse {
|
|
@@ -368,6 +369,7 @@ message MarketRequest {
|
|
|
368
369
|
string trade_id = 2;
|
|
369
370
|
string symbol = 3;
|
|
370
371
|
string amount = 4;
|
|
372
|
+
string data = 5;
|
|
371
373
|
}
|
|
372
374
|
|
|
373
375
|
message StartStreamRequest {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/exch_srv_cfg.toml.template
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/bitfinex_parser.py
RENAMED
|
File without changes
|
{exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/huobi_parser.py
RENAMED
|
File without changes
|
{exchanges_wrapper-2.1.13 → exchanges_wrapper-2.1.15}/exchanges_wrapper/parsers/okx_parser.py
RENAMED
|
File without changes
|
|
File without changes
|